1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-1999 The LyX Team.
9 * ======================================================*/
14 #include FORMS_H_LOCATION
18 #pragma implementation "lyxtext.h"
19 #pragma implementation "undo.h"
23 #include "lyxparagraph.h"
24 #include "insets/inseterror.h"
27 #include "support/textutils.h"
30 #include "minibuffer.h"
32 #include "bufferparams.h"
33 #include "lyx_gui_misc.h"
39 extern MiniBuffer * minibuffer;
42 LyXText::LyXText(int pw, Buffer * p)
49 parameters = &p->params;
53 status = LyXText::UNCHANGED;
54 LyXParagraph * par = p->paragraph;
55 current_font = GetFont(par, 0);
60 InsertParagraph(par, lastrow);
63 /* set cursor at the very top position */
64 selection = true; /* these setting is necessary
65 * because of the delete-empty-
66 * paragraph mechanism in
68 SetCursor(firstrow->par, 0);
73 /* no rebreak necessary */
79 // Default layouttype for copy environment type
87 // Delete all rows, this does not touch the paragraphs!
88 Row * tmprow = firstrow;
90 tmprow = firstrow->next;
97 // Gets the fully instantiated font at a given position in a paragraph
98 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
99 // The difference is that this one is used for displaying, and thus we
100 // are allowed to make cosmetic improvements. For instance make footnotes
102 // If position is -1, we get the layout font of the paragraph.
103 // If position is -2, we get the font of the manual label of the paragraph.
105 LyXFont LyXText::GetFont(LyXParagraph * par,
106 LyXParagraph::size_type pos)
108 LyXFont LyXText::GetFont(LyXParagraph * par, int pos)
111 LyXLayout const & layout =
112 textclasslist.Style(parameters->textclass, par->GetLayout());
114 char par_depth = par->GetDepth();
115 // We specialize the 95% common case:
116 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
119 if (layout.labeltype == LABEL_MANUAL
120 && pos < BeginningOfMainBody(par)) {
122 return par->GetFontSettings(pos).
123 realize(layout.reslabelfont);
125 return par->GetFontSettings(pos).
126 realize(layout.resfont);
129 // process layoutfont for pos == -1 and labelfont for pos < -1
131 return layout.resfont;
133 return layout.reslabelfont;
137 // The uncommon case need not be optimized as much
139 LyXFont layoutfont, tmpfont;
143 if (pos < BeginningOfMainBody(par)) {
145 layoutfont = layout.labelfont;
148 layoutfont = layout.font;
150 tmpfont = par->GetFontSettings(pos);
151 tmpfont.realize(layoutfont);
154 // process layoutfont for pos == -1 and labelfont for pos < -1
156 tmpfont = layout.font;
158 tmpfont = layout.labelfont;
161 // Resolve against environment font information
162 while (par && par_depth && !tmpfont.resolved()) {
163 par = par->DepthHook(par_depth - 1);
165 tmpfont.realize(textclasslist.
166 Style(parameters->textclass,
167 par->GetLayout()).font);
168 par_depth = par->GetDepth();
172 tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
174 // Cosmetic improvement: If this is an open footnote, make the font
176 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
177 && par->footnotekind == LyXParagraph::FOOTNOTE) {
186 void LyXText::SetCharFont(LyXParagraph * par,
187 LyXParagraph::size_type pos,
190 void LyXText::SetCharFont(LyXParagraph * par, int pos, LyXFont font)
193 /* let the insets convert their font */
194 if (par->GetChar(pos) == LYX_META_INSET) {
195 if (par->GetInset(pos))
196 font = par->GetInset(pos)->ConvertFont(font);
199 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
202 // Get concrete layout font to reduce against
205 if (pos < BeginningOfMainBody(par))
206 layoutfont = layout.labelfont;
208 layoutfont = layout.font;
210 // Realize against environment font information
211 if (par->GetDepth()){
212 LyXParagraph * tp = par;
213 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
214 tp = tp->DepthHook(tp->GetDepth()-1);
216 layoutfont.realize(textclasslist.
217 Style(parameters->textclass,
218 tp->GetLayout()).font);
222 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
224 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
225 && par->footnotekind == LyXParagraph::FOOTNOTE) {
226 layoutfont.decSize();
229 // Now, reduce font against full layout font
230 font.reduce(layoutfont);
232 par->SetFont(pos, font);
236 /* inserts a new row behind the specified row, increments
237 * the touched counters */
239 void LyXText::InsertRow(Row * row, LyXParagraph * par,
240 LyXParagraph::size_type pos)
242 void LyXText::InsertRow(Row * row, LyXParagraph * par, int pos)
245 Row * tmprow = new Row;
247 tmprow->previous = 0;
248 tmprow->next = firstrow;
252 tmprow->previous = row;
253 tmprow->next = row->next;
258 tmprow->next->previous = tmprow;
260 if (tmprow->previous)
261 tmprow->previous->next = tmprow;
269 number_of_rows++; /* one more row */
273 /* removes the row and reset the touched counters */
274 void LyXText::RemoveRow(Row * row)
276 /* this must not happen before the currentrow for clear reasons.
277 so the trick is just to set the current row onto the previous
280 GetRow(row->par, row->pos, unused_y);
281 currentrow = currentrow->previous;
283 currentrow_y -= currentrow->height;
288 row->next->previous = row->previous;
289 if (!row->previous) {
290 firstrow = row->next;
293 row->previous->next = row->next;
296 lastrow = row->previous;
298 height -= row->height; /* the text becomes smaller */
301 --number_of_rows; /* one row less */
305 /* remove all following rows of the paragraph of the specified row. */
306 void LyXText::RemoveParagraph(Row * row)
310 LyXParagraph * tmppar = row->par;
313 while (row && row->par == tmppar) {
321 /* insert the specified paragraph behind the specified row */
322 void LyXText::InsertParagraph(LyXParagraph * par, Row * row)
324 InsertRow(row, par, 0); /* insert a new row, starting
327 SetCounter(par); /* set the counters */
329 /* and now append the whole paragraph behind the new row */
331 firstrow->height = 0;
332 AppendParagraph(firstrow);
335 row->next->height = 0;
336 AppendParagraph(row->next);
341 void LyXText::ToggleFootnote()
343 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
344 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
346 minibuffer->Set(_("Opened float"));
349 minibuffer->Set(_("Closed float"));
355 void LyXText::OpenStuff()
357 if (cursor.pos == 0 && cursor.par->bibkey){
358 cursor.par->bibkey->Edit(0,0);
360 else if (cursor.pos < cursor.par->Last()
361 && cursor.par->GetChar(cursor.pos) == LYX_META_INSET
362 && cursor.par->GetInset(cursor.pos)->Editable()) {
363 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
364 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
366 cursor.par->GetInset(cursor.pos)->Edit(0,0);
374 void LyXText::CloseFootnote()
376 LyXParagraph * endpar, * tmppar;
379 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
381 /* if the cursor is not in an open footnote, or
382 * there is no open footnote in this paragraph, just return. */
383 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
386 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
387 minibuffer->Set(_("Nothing to do"));
391 /* ok, move the cursor right before the footnote */
393 /* just a little faster than using CursorRight() */
394 for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
395 /* now the cursor is at the beginning of the physical par */
397 SetCursor(cursor.par,
399 cursor.par->ParFromPos(cursor.pos)->text.size());
401 SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
405 /* we are in a footnote, so let us move at the beginning */
406 /* this is just faster than using just CursorLeft() */
409 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
410 /* just a little bit faster than movin the cursor */
411 tmppar = tmppar->Previous();
413 SetCursor(tmppar, tmppar->Last());
416 /* the cursor must be exactly before the footnote */
417 par = cursor.par->ParFromPos(cursor.pos);
419 status = LyXText::NEED_MORE_REFRESH;
420 refresh_row = cursor.row;
421 refresh_y = cursor.y - cursor.row->baseline;
424 endpar = par->NextAfterFootnote()->Next();
427 tmppar->CloseFootnote(cursor.pos);
429 while (tmppar != endpar) {
430 RemoveRow(row->next);
432 tmppar = row->next->par;
437 AppendParagraph(cursor.row);
439 SetCursor(cursor.par, cursor.pos);
443 if (cursor.row->next)
444 SetHeightOfRow(cursor.row->next);
448 /* used in setlayout */
449 // Asger is not sure we want to do this...
450 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
452 LyXFont layoutfont, tmpfont;
454 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
457 for (LyXParagraph::size_type pos = 0;
458 pos < par->Last(); ++pos) {
460 for (int pos = 0; pos < par->Last(); pos++) {
462 if (pos < BeginningOfMainBody(par))
463 layoutfont = layout.labelfont;
465 layoutfont = layout.font;
467 tmpfont = par->GetFontSettings(pos);
468 tmpfont.reduce(layoutfont);
469 par->SetFont(pos, tmpfont);
474 /* set layout over selection and make a total rebreak of those paragraphs */
475 void LyXText::SetLayout(char layout)
479 /* if there is no selection just set the layout of the current paragraph */
481 sel_start_cursor = cursor; /* dummy selection */
482 sel_end_cursor = cursor;
485 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
486 LyXParagraph * undoendpar = endpar;
488 if (endpar && endpar->GetDepth()) {
489 while (endpar && endpar->GetDepth()) {
490 endpar = endpar->LastPhysicalPar()->Next();
495 endpar = endpar->Next(); /* because of parindents etc. */
499 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
502 tmpcursor = cursor; /* store the current cursor */
504 /* ok we have a selection. This is always between sel_start_cursor
505 * and sel_end cursor */
506 cursor = sel_start_cursor;
508 LyXLayout const & lyxlayout = textclasslist.Style(parameters->textclass, layout);
510 while (cursor.par != sel_end_cursor.par) {
511 if (cursor.par->footnoteflag ==
512 sel_start_cursor.par->footnoteflag) {
513 cursor.par->SetLayout(layout);
514 MakeFontEntriesLayoutSpecific(cursor.par);
515 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
516 fppar->added_space_top = lyxlayout.fill_top ?
517 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
518 fppar->added_space_bottom = lyxlayout.fill_bottom ?
519 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
520 if (lyxlayout.margintype == MARGIN_MANUAL)
521 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
522 if (lyxlayout.labeltype != LABEL_BIBLIO
524 delete fppar->bibkey;
528 cursor.par = cursor.par->Next();
530 if (cursor.par->footnoteflag ==
531 sel_start_cursor.par->footnoteflag) {
532 cursor.par->SetLayout(layout);
533 MakeFontEntriesLayoutSpecific(cursor.par);
534 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
535 fppar->added_space_top = lyxlayout.fill_top ?
536 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
537 fppar->added_space_bottom = lyxlayout.fill_bottom ?
538 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
539 if (lyxlayout.margintype == MARGIN_MANUAL)
540 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
541 if (lyxlayout.labeltype != LABEL_BIBLIO
543 delete fppar->bibkey;
548 RedoParagraphs(sel_start_cursor, endpar);
550 /* we have to reset the selection, because the
551 * geometry could have changed */
552 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
554 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
555 UpdateCounters(cursor.row);
558 SetCursor(tmpcursor.par, tmpcursor.pos);
562 /* increment depth over selection and
563 * make a total rebreak of those paragraphs */
564 void LyXText::IncDepth()
566 // If there is no selection, just use the current paragraph
568 sel_start_cursor = cursor; /* dummy selection */
569 sel_end_cursor = cursor;
572 // We end at the next paragraph with depth 0
573 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
574 LyXParagraph * undoendpar = endpar;
576 if (endpar && endpar->GetDepth()) {
577 while (endpar && endpar->GetDepth()) {
578 endpar = endpar->LastPhysicalPar()->Next();
583 endpar = endpar->Next(); /* because of parindents etc. */
587 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
590 LyXCursor tmpcursor = cursor; /* store the current cursor */
592 /* ok we have a selection. This is always between sel_start_cursor
593 * and sel_end cursor */
594 cursor = sel_start_cursor;
596 bool anything_changed = false;
599 // NOTE: you can't change the depth of a bibliography entry
600 if (cursor.par->footnoteflag ==
601 sel_start_cursor.par->footnoteflag
602 && textclasslist.Style(parameters->textclass,
603 cursor.par->GetLayout()
604 ).labeltype != LABEL_BIBLIO) {
605 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
607 && (prev->GetDepth() - cursor.par->GetDepth() > 0
608 || (prev->GetDepth() == cursor.par->GetDepth()
609 && textclasslist.Style(parameters->textclass,
610 prev->GetLayout()).isEnvironment()))) {
611 cursor.par->FirstPhysicalPar()->depth++;
612 anything_changed = true;
615 if (cursor.par == sel_end_cursor.par)
617 cursor.par = cursor.par->Next();
620 /* if nothing changed set all depth to 0 */
621 if (!anything_changed) {
622 cursor = sel_start_cursor;
623 while (cursor.par != sel_end_cursor.par) {
624 cursor.par->FirstPhysicalPar()->depth = 0;
625 cursor.par = cursor.par->Next();
627 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
628 cursor.par->FirstPhysicalPar()->depth = 0;
631 RedoParagraphs(sel_start_cursor, endpar);
633 /* we have to reset the selection, because the
634 * geometry could have changed */
635 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
637 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
638 UpdateCounters(cursor.row);
641 SetCursor(tmpcursor.par, tmpcursor.pos);
645 /* decrement depth over selection and
646 * make a total rebreak of those paragraphs */
647 void LyXText::DecDepth()
649 /* if there is no selection just set the layout of the current paragraph */
651 sel_start_cursor = cursor; /* dummy selection */
652 sel_end_cursor = cursor;
655 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
656 LyXParagraph * undoendpar = endpar;
658 if (endpar && endpar->GetDepth()) {
659 while (endpar && endpar->GetDepth()) {
660 endpar = endpar->LastPhysicalPar()->Next();
665 endpar = endpar->Next(); /* because of parindents etc. */
669 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
672 LyXCursor tmpcursor = cursor; /* store the current cursor */
674 /* ok we have a selection. This is always between sel_start_cursor
675 * and sel_end cursor */
676 cursor = sel_start_cursor;
679 if (cursor.par->footnoteflag ==
680 sel_start_cursor.par->footnoteflag) {
681 if (cursor.par->FirstPhysicalPar()->depth)
682 cursor.par->FirstPhysicalPar()->depth--;
684 if (cursor.par == sel_end_cursor.par)
686 cursor.par = cursor.par->Next();
689 RedoParagraphs(sel_start_cursor, endpar);
691 /* we have to reset the selection, because the
692 * geometry could have changed */
693 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
695 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
696 UpdateCounters(cursor.row);
699 SetCursor(tmpcursor.par, tmpcursor.pos);
703 /* set font over selection and make a total rebreak of those paragraphs */
704 void LyXText::SetFont(LyXFont font, bool toggleall)
706 /* if there is no selection just set the current_font */
708 // Determine basis font
710 if (cursor.pos < BeginningOfMainBody(cursor.par))
711 layoutfont = GetFont(cursor.par, -2);
713 layoutfont = GetFont(cursor.par, -1);
714 // Update current font
715 real_current_font.update(font,toggleall);
717 // Reduce to implicit settings
718 current_font = real_current_font;
719 current_font.reduce(layoutfont);
720 // And resolve it completely
721 real_current_font.realize(layoutfont);
725 LyXCursor tmpcursor = cursor; /* store the current cursor */
727 /* ok we have a selection. This is always between sel_start_cursor
728 * and sel_end cursor */
731 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
732 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
733 cursor = sel_start_cursor;
734 while (cursor.par != sel_end_cursor.par ||
735 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
736 && cursor.pos < sel_end_cursor.pos))
738 if (cursor.pos < cursor.par->Last()
739 && cursor.par->footnoteflag
740 == sel_start_cursor.par->footnoteflag) { /* an open footnote
743 LyXFont newfont = GetFont(cursor.par,cursor.pos);
744 newfont.update(font,toggleall);
745 SetCharFont(cursor.par, cursor.pos, newfont);
749 cursor.par = cursor.par->Next();
753 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
755 /* we have to reset the selection, because the
756 * geometry could have changed */
757 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
759 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
762 SetCursor(tmpcursor.par, tmpcursor.pos);
766 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
768 Row * tmprow = cursor.row;
769 long y = cursor.y - tmprow->baseline;
771 SetHeightOfRow(tmprow);
772 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
773 /* find the first row of the paragraph */
774 if (first_phys_par != tmprow->par)
775 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
776 tmprow = tmprow->previous;
778 SetHeightOfRow(tmprow);
780 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
781 tmprow = tmprow->previous;
783 SetHeightOfRow(tmprow);
786 /* we can set the refreshing parameters now */
787 status = LyXText::NEED_MORE_REFRESH;
789 refresh_row = tmprow;
790 SetCursor(cursor.par, cursor.pos);
794 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
796 Row * tmprow = cursor.row;
798 long y = cursor.y - tmprow->baseline;
799 SetHeightOfRow(tmprow);
800 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
801 /* find the first row of the paragraph */
802 if (first_phys_par != tmprow->par)
803 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
804 tmprow = tmprow->previous;
807 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
808 tmprow = tmprow->previous;
813 /* we can set the refreshing parameters now */
814 if (status == LyXText::UNCHANGED || y < refresh_y) {
816 refresh_row = tmprow;
818 status = LyXText::NEED_MORE_REFRESH;
819 SetCursor(cursor.par, cursor.pos);
823 /* deletes and inserts again all paragaphs between the cursor
824 * and the specified par
825 * This function is needed after SetLayout and SetFont etc. */
826 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph * endpar)
829 LyXParagraph * tmppar, * first_phys_par;
831 Row * tmprow = cursor.row;
833 long y = cursor.y - tmprow->baseline;
835 if (!tmprow->previous){
836 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
839 first_phys_par = tmprow->par->FirstPhysicalPar();
840 /* find the first row of the paragraph */
841 if (first_phys_par != tmprow->par)
842 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
843 tmprow = tmprow->previous;
846 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
847 tmprow = tmprow->previous;
852 /* we can set the refreshing parameters now */
853 status = LyXText::NEED_MORE_REFRESH;
855 refresh_row = tmprow->previous; /* the real refresh row will
856 * be deleted, so I store
857 * the previous here */
860 tmppar = tmprow->next->par;
863 while (tmppar != endpar) {
864 RemoveRow(tmprow->next);
866 tmppar = tmprow->next->par;
871 /* remove the first one */
872 tmprow2 = tmprow; /* this is because tmprow->previous
874 tmprow = tmprow->previous;
877 tmppar = first_phys_par;
881 InsertParagraph(tmppar, tmprow);
884 while (tmprow->next && tmprow->next->par == tmppar)
885 tmprow = tmprow->next;
886 tmppar = tmppar->Next();
890 while (tmppar != endpar);
892 /* this is because of layout changes */
894 refresh_y -= refresh_row->height;
895 SetHeightOfRow(refresh_row);
898 refresh_row = firstrow;
900 SetHeightOfRow(refresh_row);
903 if (tmprow && tmprow->next)
904 SetHeightOfRow(tmprow->next);
908 int LyXText::FullRebreak()
910 if (need_break_row) {
911 BreakAgain(need_break_row);
919 /* important for the screen */
922 /* the cursor set functions have a special mechanism. When they
923 * realize, that you left an empty paragraph, they will delete it.
924 * They also delet the corresponding row */
926 /* need the selection cursor: */
927 void LyXText::SetSelection()
930 last_sel_cursor = sel_cursor;
931 sel_start_cursor = sel_cursor;
932 sel_end_cursor = sel_cursor;
937 /* first the toggling area */
938 if (cursor.y < last_sel_cursor.y ||
939 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
940 toggle_end_cursor = last_sel_cursor;
941 toggle_cursor = cursor;
944 toggle_end_cursor = cursor;
945 toggle_cursor = last_sel_cursor;
948 last_sel_cursor = cursor;
950 /* and now the whole selection */
952 if (sel_cursor.y < cursor.y ||
953 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
954 sel_end_cursor = cursor;
955 sel_start_cursor = sel_cursor;
958 sel_end_cursor = sel_cursor;
959 sel_start_cursor = cursor;
962 /* a selection with no contents is not a selection */
963 if (sel_start_cursor.x == sel_end_cursor.x &&
964 sel_start_cursor.y == sel_end_cursor.y)
969 void LyXText::ClearSelection()
976 void LyXText::CursorHome()
978 SetCursor(cursor.par, cursor.row->pos);
982 void LyXText::CursorEnd()
984 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
985 SetCursor(cursor.par, RowLast(cursor.row) + 1);
987 if (cursor.par->Last() &&
988 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
989 || cursor.par->IsNewline(RowLast(cursor.row))))
990 SetCursor(cursor.par, RowLast(cursor.row));
992 SetCursor(cursor.par, RowLast(cursor.row) + 1);
994 if (cursor.par->table) {
995 int cell = NumberOfCell(cursor.par, cursor.pos);
996 if (cursor.par->table->RowHasContRow(cell) &&
997 cursor.par->table->CellHasContRow(cell)<0) {
998 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
999 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1001 if (cursor.par->Last() &&
1002 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1003 || cursor.par->IsNewline(RowLast(cursor.row))))
1004 SetCursor(cursor.par, RowLast(cursor.row));
1006 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1013 void LyXText::CursorTop()
1015 while (cursor.par->Previous())
1016 cursor.par = cursor.par->Previous();
1017 SetCursor(cursor.par, 0);
1021 void LyXText::CursorBottom()
1023 while (cursor.par->Next())
1024 cursor.par = cursor.par->Next();
1025 SetCursor(cursor.par, cursor.par->Last());
1029 /* returns a pointer to the row near the specified y-coordinate
1030 * (relative to the whole text). y is set to the real beginning
1032 Row * LyXText::GetRowNearY(long & y)
1038 tmprow = currentrow;
1039 tmpy = currentrow_y;
1047 while (tmprow->next && tmpy + tmprow->height <= y) {
1048 tmpy += tmprow->height;
1049 tmprow = tmprow->next;
1052 while (tmprow->previous && tmpy > y) {
1053 tmprow = tmprow->previous;
1054 tmpy -= tmprow->height;
1057 currentrow = tmprow;
1058 currentrow_y = tmpy;
1060 y = tmpy; /* return the real y */
1065 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1067 // If the mask is completely neutral, tell user
1068 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1069 // Could only happen with user style
1070 minibuffer->Set(_("No font change defined. Use Character under"
1071 " the Layout menu to define font change."));
1075 // Try implicit word selection
1076 LyXCursor resetCursor = cursor;
1077 int implicitSelection = SelectWordWhenUnderCursor();
1080 SetFont(font,toggleall);
1081 //minibuffer->Set(_("Font style changed"));
1083 /* Implicit selections are cleared afterwards and cursor is set to the
1084 original position. */
1085 if (implicitSelection) {
1087 cursor = resetCursor;
1088 SetCursor( cursor.par, cursor.pos );
1089 sel_cursor = cursor;
1095 LyXParagraph::size_type
1096 LyXText::BeginningOfMainBody(LyXParagraph * par)
1098 int LyXText::BeginningOfMainBody(LyXParagraph * par)
1101 if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1104 return par->BeginningOfMainBody();
1108 /* if there is a selection, reset every environment you can find
1109 * in the selection, otherwise just the environment you are in */
1110 void LyXText::MeltFootnoteEnvironment()
1112 LyXParagraph * tmppar, * firsttmppar;
1116 /* is is only allowed, if the cursor is IN an open footnote.
1117 * Otherwise it is too dangerous */
1118 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1121 SetUndo(Undo::FINISH,
1122 cursor.par->PreviousBeforeFootnote()->previous,
1123 cursor.par->NextAfterFootnote()->next);
1125 /* ok, move to the beginning of the footnote. */
1126 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1127 cursor.par = cursor.par->Previous();
1129 SetCursor(cursor.par, cursor.par->Last());
1130 /* this is just faster than using CursorLeft(); */
1132 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1133 tmppar = firsttmppar;
1134 /* tmppar is now the paragraph right before the footnote */
1137 char first_footnote_par_is_not_empty = tmppar->next->text.size();
1139 char first_footnote_par_is_not_empty = tmppar->next->last;
1142 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1143 tmppar = tmppar->next; /* I use next instead of Next(),
1144 * because there cannot be any
1145 * footnotes in a footnote
1147 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1149 /* remember the captions and empty paragraphs */
1150 if ((textclasslist.Style(parameters->textclass,
1151 tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1153 tmppar->SetLayout(0);
1156 /* now we will paste the ex-footnote, if the layouts allow it */
1157 /* first restore the layout of the paragraph right behind the footnote*/
1159 tmppar->next->MakeSameLayout(cursor.par);
1162 if ((!tmppar->GetLayout() && !tmppar->table)
1163 || (tmppar->Next() && (!tmppar->Next()->Last()
1164 || tmppar->Next()->HasSameLayout(tmppar)))) {
1165 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1166 tmppar->Next()->Erase(0);
1167 tmppar->PasteParagraph();
1170 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1171 * by the pasting of the beginning */
1173 /* then the beginning */
1174 /* if there is no space between the text and the footnote, so we insert
1176 * (only if the previous par and the footnotepar are not empty!) */
1177 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1178 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1180 if (firsttmppar->text.size()
1181 && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1183 if (firsttmppar->last
1184 && !firsttmppar->IsSeparator(firsttmppar->last - 1)
1186 && first_footnote_par_is_not_empty) {
1187 firsttmppar->next->InsertChar(0, ' ');
1189 firsttmppar->PasteParagraph();
1192 /* now redo the paragaphs */
1193 RedoParagraphs(cursor, tmppar);
1195 SetCursor(cursor.par, cursor.pos);
1197 /* sometimes it can happen, that there is a counter change */
1198 Row * row = cursor.row;
1199 while (row->next && row->par != tmppar && row->next->par != tmppar)
1201 UpdateCounters(row);
1208 /* the DTP switches for paragraphs. LyX will store them in the
1209 * first physicla paragraph. When a paragraph is broken, the top settings
1210 * rest, the bottom settings are given to the new one. So I can make shure,
1211 * they do not duplicate themself and you cannnot make dirty things with
1214 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1215 bool pagebreak_top, bool pagebreak_bottom,
1216 VSpace space_top, VSpace space_bottom,
1218 string labelwidthstring,
1221 LyXCursor tmpcursor = cursor;
1223 sel_start_cursor = cursor;
1224 sel_end_cursor = cursor;
1227 // make sure that the depth behind the selection are restored, too
1228 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1229 LyXParagraph * undoendpar = endpar;
1231 if (endpar && endpar->GetDepth()) {
1232 while (endpar && endpar->GetDepth()) {
1233 endpar = endpar->LastPhysicalPar()->Next();
1234 undoendpar = endpar;
1238 endpar = endpar->Next(); /* because of parindents etc. */
1242 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1246 LyXParagraph * tmppar = sel_end_cursor.par;
1247 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1248 SetCursor(tmppar->FirstPhysicalPar(), 0);
1249 status = LyXText::NEED_MORE_REFRESH;
1250 refresh_row = cursor.row;
1251 refresh_y = cursor.y - cursor.row->baseline;
1252 if (cursor.par->footnoteflag ==
1253 sel_start_cursor.par->footnoteflag) {
1254 cursor.par->line_top = line_top;
1255 cursor.par->line_bottom = line_bottom;
1256 cursor.par->pagebreak_top = pagebreak_top;
1257 cursor.par->pagebreak_bottom = pagebreak_bottom;
1258 cursor.par->added_space_top = space_top;
1259 cursor.par->added_space_bottom = space_bottom;
1260 /* does the layout allow the new alignment? */
1261 if (align == LYX_ALIGN_LAYOUT)
1262 align = textclasslist
1263 .Style(parameters->textclass,
1264 cursor.par->GetLayout()).align;
1265 if (align & textclasslist
1266 .Style(parameters->textclass,
1267 cursor.par->GetLayout()).alignpossible) {
1268 if (align == textclasslist
1269 .Style(parameters->textclass,
1270 cursor.par->GetLayout()).align)
1271 cursor.par->align = LYX_ALIGN_LAYOUT;
1273 cursor.par->align = align;
1275 cursor.par->SetLabelWidthString(labelwidthstring);
1276 cursor.par->noindent = noindent;
1279 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1282 RedoParagraphs(sel_start_cursor, endpar);
1285 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1286 sel_cursor = cursor;
1287 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1289 SetCursor(tmpcursor.par, tmpcursor.pos);
1293 void LyXText::SetParagraphExtraOpt(int type,
1295 char const * widthp,
1296 int alignment, bool hfill,
1297 bool start_minipage)
1299 LyXCursor tmpcursor = cursor;
1300 LyXParagraph * tmppar;
1302 sel_start_cursor = cursor;
1303 sel_end_cursor = cursor;
1306 // make sure that the depth behind the selection are restored, too
1307 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1308 LyXParagraph * undoendpar = endpar;
1310 if (endpar && endpar->GetDepth()) {
1311 while (endpar && endpar->GetDepth()) {
1312 endpar = endpar->LastPhysicalPar()->Next();
1313 undoendpar = endpar;
1317 endpar = endpar->Next(); /* because of parindents etc. */
1321 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1324 tmppar = sel_end_cursor.par;
1325 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1326 SetCursor(tmppar->FirstPhysicalPar(), 0);
1327 status = LyXText::NEED_MORE_REFRESH;
1328 refresh_row = cursor.row;
1329 refresh_y = cursor.y - cursor.row->baseline;
1330 if (cursor.par->footnoteflag ==
1331 sel_start_cursor.par->footnoteflag) {
1332 if (type == PEXTRA_NONE) {
1333 if (cursor.par->pextra_type != PEXTRA_NONE) {
1334 cursor.par->UnsetPExtraType();
1335 cursor.par->pextra_type=PEXTRA_NONE;
1338 cursor.par->SetPExtraType(type,width,widthp);
1339 cursor.par->pextra_hfill = hfill;
1340 cursor.par->pextra_start_minipage = start_minipage;
1341 cursor.par->pextra_alignment = alignment;
1344 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1346 RedoParagraphs(sel_start_cursor, endpar);
1348 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1349 sel_cursor = cursor;
1350 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1352 SetCursor(tmpcursor.par, tmpcursor.pos);
1356 static char const * alphaCounter(int n){
1357 static char result[2];
1370 /* set the counter of a paragraph. This includes the labels */
1371 void LyXText::SetCounter(LyXParagraph * par)
1375 /* this is only relevant for the beginning of paragraph */
1376 par = par->FirstPhysicalPar();
1378 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1381 LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1383 /* copy the prev-counters to this one, unless this is the start of a
1384 footnote or of a bibliography or the very first paragraph */
1386 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1387 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1388 && par->footnotekind == LyXParagraph::FOOTNOTE)
1389 && !(textclasslist.Style(parameters->textclass,
1390 par->Previous()->GetLayout()
1391 ).labeltype != LABEL_BIBLIO
1392 && layout.labeltype == LABEL_BIBLIO)) {
1393 for (i=0; i<10; i++) {
1394 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1396 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1397 if (!par->appendix && par->start_of_appendix){
1398 par->appendix = true;
1399 for (i=0; i<10; i++) {
1400 par->setCounter(i, 0);
1403 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1404 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1407 for (i=0; i<10; i++) {
1408 par->setCounter(i, 0);
1410 par->appendix = par->start_of_appendix;
1415 // if this is an open marginnote and this is the first
1416 // entry in the marginnote and the enclosing
1417 // environment is an enum/item then correct for the
1418 // LaTeX behaviour (ARRae)
1419 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1420 && par->footnotekind == LyXParagraph::MARGIN
1422 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1423 && (par->PreviousBeforeFootnote()
1424 && textclasslist.Style(parameters->textclass,
1425 par->PreviousBeforeFootnote()->GetLayout()
1426 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1427 // Any itemize or enumerate environment in a marginnote
1428 // that is embedded in an itemize or enumerate
1429 // paragraph is seen by LaTeX as being at a deeper
1430 // level within that enclosing itemization/enumeration
1431 // even if there is a "standard" layout at the start of
1437 /* Maybe we have to increment the enumeration depth.
1438 * BUT, enumeration in a footnote is considered in isolation from its
1439 * surrounding paragraph so don't increment if this is the
1440 * first line of the footnote
1441 * AND, bibliographies can't have their depth changed ie. they
1442 * are always of depth 0
1445 && par->Previous()->GetDepth() < par->GetDepth()
1446 && textclasslist.Style(parameters->textclass,
1447 par->Previous()->GetLayout()
1448 ).labeltype == LABEL_COUNTER_ENUMI
1449 && par->enumdepth < 3
1450 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1451 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1452 && par->footnotekind == LyXParagraph::FOOTNOTE)
1453 && layout.labeltype != LABEL_BIBLIO) {
1457 /* Maybe we have to decrement the enumeration depth, see note above */
1459 && par->Previous()->GetDepth() > par->GetDepth()
1460 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1461 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1462 && par->footnotekind == LyXParagraph::FOOTNOTE)
1463 && layout.labeltype != LABEL_BIBLIO) {
1464 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1465 par->setCounter(6 + par->enumdepth,
1466 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1467 /* reset the counters.
1468 * A depth change is like a breaking layout
1470 for (i=6 + par->enumdepth + 1; i<10;i++)
1471 par->setCounter(i, 0);
1474 if (!par->labelstring.empty()) {
1475 par->labelstring.clear();
1478 if (layout.margintype == MARGIN_MANUAL) {
1479 if (par->labelwidthstring.empty()) {
1480 par->SetLabelWidthString(layout.labelstring());
1484 par->SetLabelWidthString(string());
1487 /* is it a layout that has an automatic label ? */
1488 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1490 i = layout.labeltype - LABEL_FIRST_COUNTER;
1491 if (i >= 0 && i<=parameters->secnumdepth) {
1492 par->incCounter(i); // increment the counter
1494 char * s = new char[50];
1496 // Is there a label? Useful for Chapter layout
1497 if (!par->appendix){
1498 if (!layout.labelstring().empty())
1499 par->labelstring = layout.labelstring();
1501 par->labelstring.clear();
1504 if (!layout.labelstring_appendix().empty())
1505 par->labelstring = layout.labelstring_appendix();
1507 par->labelstring.clear();
1510 if (!par->appendix){
1511 switch (2 * LABEL_FIRST_COUNTER -
1512 textclass.maxcounter() + i) {
1513 case LABEL_COUNTER_CHAPTER:
1515 par->getCounter(i));
1517 case LABEL_COUNTER_SECTION:
1519 par->getCounter(i - 1),
1520 par->getCounter(i));
1522 case LABEL_COUNTER_SUBSECTION:
1523 sprintf(s, "%d.%d.%d",
1524 par->getCounter(i-2),
1525 par->getCounter(i-1),
1526 par->getCounter(i));
1528 case LABEL_COUNTER_SUBSUBSECTION:
1529 sprintf(s, "%d.%d.%d.%d",
1530 par->getCounter(i-3),
1531 par->getCounter(i-2),
1532 par->getCounter(i-1),
1533 par->getCounter(i));
1535 case LABEL_COUNTER_PARAGRAPH:
1536 sprintf(s, "%d.%d.%d.%d.%d",
1537 par->getCounter(i-4),
1538 par->getCounter(i-3),
1539 par->getCounter(i-2),
1540 par->getCounter(i-1),
1541 par->getCounter(i));
1543 case LABEL_COUNTER_SUBPARAGRAPH:
1544 sprintf(s, "%d.%d.%d.%d.%d.%d",
1545 par->getCounter(i-5),
1546 par->getCounter(i-4),
1547 par->getCounter(i-3),
1548 par->getCounter(i-2),
1549 par->getCounter(i-1),
1550 par->getCounter(i));
1553 sprintf(s, "%d.", par->getCounter(i));
1558 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1559 case LABEL_COUNTER_CHAPTER:
1561 alphaCounter(par->getCounter(i)));
1563 case LABEL_COUNTER_SECTION:
1565 alphaCounter(par->getCounter(i - 1)),
1566 par->getCounter(i));
1568 case LABEL_COUNTER_SUBSECTION:
1569 sprintf(s, "%s.%d.%d",
1570 alphaCounter(par->getCounter(i-2)),
1571 par->getCounter(i-1),
1572 par->getCounter(i));
1574 case LABEL_COUNTER_SUBSUBSECTION:
1575 sprintf(s, "%s.%d.%d.%d",
1576 alphaCounter(par->getCounter(i-3)),
1577 par->getCounter(i-2),
1578 par->getCounter(i-1),
1579 par->getCounter(i));
1581 case LABEL_COUNTER_PARAGRAPH:
1582 sprintf(s, "%s.%d.%d.%d.%d",
1583 alphaCounter(par->getCounter(i-4)),
1584 par->getCounter(i-3),
1585 par->getCounter(i-2),
1586 par->getCounter(i-1),
1587 par->getCounter(i));
1589 case LABEL_COUNTER_SUBPARAGRAPH:
1590 sprintf(s, "%s.%d.%d.%d.%d.%d",
1591 alphaCounter(par->getCounter(i-5)),
1592 par->getCounter(i-4),
1593 par->getCounter(i-3),
1594 par->getCounter(i-2),
1595 par->getCounter(i-1),
1596 par->getCounter(i));
1599 sprintf(s, "%c.", par->getCounter(i));
1604 par->labelstring += s;
1607 for (i++; i<10; i++) {
1608 /* reset the following counters */
1609 par->setCounter(i, 0);
1611 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1612 for (i++; i<10; i++) {
1613 /* reset the following counters */
1614 par->setCounter(i, 0);
1616 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1617 par->incCounter(i + par->enumdepth);
1618 char * s = new char[25];
1619 int number = par->getCounter(i + par->enumdepth);
1620 switch (par->enumdepth) {
1622 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1626 case 1: sprintf(s, "i."); break;
1627 case 2: sprintf(s, "ii."); break;
1628 case 3: sprintf(s, "iii."); break;
1629 case 4: sprintf(s, "iv."); break;
1630 case 5: sprintf(s, "v."); break;
1631 case 6: sprintf(s, "vi."); break;
1632 case 7: sprintf(s, "vii."); break;
1633 case 8: sprintf(s, "viii."); break;
1634 case 9: sprintf(s, "ix."); break;
1635 case 10: sprintf(s, "x."); break;
1636 case 11: sprintf(s, "xi."); break;
1637 case 12: sprintf(s, "xii."); break;
1638 case 13: sprintf(s, "xiii."); break;
1640 sprintf(s, "\\roman{%d}.", number);
1645 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1648 sprintf(s, "%d.", number);
1651 par->labelstring = s;
1654 for (i += par->enumdepth + 1;i<10;i++)
1655 par->setCounter(i, 0); /* reset the following counters */
1658 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1659 i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1661 int number = par->getCounter(i);
1663 par->bibkey = new InsetBibKey();
1664 par->bibkey->setCounter(number);
1665 par->labelstring = layout.labelstring();
1667 // In biblio should't be following counters but...
1670 string s = layout.labelstring();
1672 /* the caption hack: */
1674 if (layout.labeltype == LABEL_SENSITIVE) {
1675 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1676 && (par->footnotekind == LyXParagraph::FIG
1677 || par->footnotekind == LyXParagraph::WIDE_FIG))
1679 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1680 && (par->footnotekind == LyXParagraph::TAB
1681 || par->footnotekind == LyXParagraph::WIDE_TAB))
1683 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1684 && par->footnotekind == LyXParagraph::ALGORITHM)
1687 /* par->SetLayout(0);
1688 s = layout->labelstring; */
1693 par->labelstring = s;
1695 /* reset the enumeration counter. They are always resetted
1696 * when there is any other layout between */
1697 for (i=6 + par->enumdepth; i<10;i++)
1698 par->setCounter(i, 0);
1703 /* Updates all counters BEHIND the row. Changed paragraphs
1704 * with a dynamic left margin will be rebroken. */
1705 void LyXText::UpdateCounters(Row * row)
1713 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1714 par = row->par->LastPhysicalPar()->Next();
1716 par = row->par->next;
1721 while (row->par != par)
1726 /* now check for the headline layouts. remember that they
1727 * have a dynamic left margin */
1729 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1730 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1733 /* Rebreak the paragraph */
1734 RemoveParagraph(row);
1735 AppendParagraph(row);
1737 /* think about the damned open footnotes! */
1738 while (par->Next() &&
1739 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1740 || par->Next()->IsDummy())){
1742 if (par->IsDummy()) {
1743 while (row->par != par)
1745 RemoveParagraph(row);
1746 AppendParagraph(row);
1751 par = par->LastPhysicalPar()->Next();
1757 /* insets an inset. */
1758 void LyXText::InsertInset(Inset *inset)
1760 SetUndo(Undo::INSERT,
1761 cursor.par->ParFromPos(cursor.pos)->previous,
1762 cursor.par->ParFromPos(cursor.pos)->next);
1763 cursor.par->InsertChar(cursor.pos, LYX_META_INSET);
1764 cursor.par->InsertInset(cursor.pos, inset);
1765 InsertChar(LYX_META_INSET); /* just to rebreak and refresh correctly.
1766 * The character will not be inserted a
1771 /* this is for the simple cut and paste mechanism */
1772 static LyXParagraph * simple_cut_buffer = 0;
1773 static char simple_cut_buffer_textclass = 0;
1775 void DeleteSimpleCutBuffer()
1777 if (!simple_cut_buffer)
1779 LyXParagraph *tmppar;
1781 while (simple_cut_buffer) {
1782 tmppar = simple_cut_buffer;
1783 simple_cut_buffer = simple_cut_buffer->next;
1786 simple_cut_buffer = 0;
1790 void LyXText::copyEnvironmentType()
1792 copylayouttype = cursor.par->GetLayout();
1796 void LyXText::pasteEnvironmentType()
1798 SetLayout(copylayouttype);
1802 void LyXText::CutSelection(bool doclear)
1804 /* This doesn't make sense, if there is no selection */
1809 /* OK, we have a selection. This is always between sel_start_cursor
1810 * and sel_end cursor */
1811 LyXParagraph * tmppar;
1813 /* Check whether there are half footnotes in the selection */
1814 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1815 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1816 tmppar = sel_start_cursor.par;
1817 while (tmppar != sel_end_cursor.par){
1818 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1819 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1822 tmppar = tmppar->Next();
1826 /* table stuff -- begin*/
1827 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1828 if ( sel_start_cursor.par != sel_end_cursor.par){
1829 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1832 sel_start_cursor.par->table->Reinit();
1834 /* table stuff -- end*/
1836 // make sure that the depth behind the selection are restored, too
1837 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1838 LyXParagraph * undoendpar = endpar;
1840 if (endpar && endpar->GetDepth()) {
1841 while (endpar && endpar->GetDepth()) {
1842 endpar = endpar->LastPhysicalPar()->Next();
1843 undoendpar = endpar;
1847 endpar = endpar->Next(); /* because of parindents etc. */
1850 SetUndo(Undo::DELETE,
1851 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1854 /* delete the simple_cut_buffer */
1855 DeleteSimpleCutBuffer();
1857 /* set the textclass */
1858 simple_cut_buffer_textclass = parameters->textclass;
1860 #ifdef WITH_WARNINGS
1861 #warning Asger: Make cut more intelligent here.
1864 White paper for "intelligent" cutting:
1866 Example: "This is our text."
1867 Using " our " as selection, cutting will give "This istext.".
1868 Using "our" as selection, cutting will give "This is text.".
1869 Using " our" as selection, cutting will give "This is text.".
1870 Using "our " as selection, cutting will give "This is text.".
1872 All those four selections will (however) paste identically:
1873 Pasting with the cursor right after the "is" will give the
1874 original text with all four selections.
1876 The rationale is to be intelligent such that words are copied,
1877 cut and pasted in a functional manner.
1879 This is not implemented yet.
1882 bool space_wrapped =
1883 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1884 if (sel_end_cursor.pos > 0
1885 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1886 sel_end_cursor.pos--; /* please break before a space at
1888 space_wrapped = true;
1891 // cut behind a space if there is one
1892 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1893 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1894 && (sel_start_cursor.par != sel_end_cursor.par
1895 || sel_start_cursor.pos < sel_end_cursor.pos))
1896 sel_start_cursor.pos++;
1898 /* there are two cases: cut only within one paragraph or
1899 * more than one paragraph */
1901 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1902 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1903 /* only within one paragraph */
1904 simple_cut_buffer = new LyXParagraph;
1906 simple_cut_buffer->text.reserve(500);
1907 LyXParagraph::size_type i =
1908 sel_start_cursor.pos;
1910 int i = sel_start_cursor.pos;
1912 for (; i< sel_end_cursor.pos; i++){
1913 /* table stuff -- begin*/
1914 if (sel_start_cursor.par->table
1915 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1916 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1917 sel_start_cursor.pos++;
1919 /* table stuff -- end*/
1920 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1921 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1923 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1925 /* check for double spaces */
1926 if (sel_start_cursor.pos &&
1927 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1928 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1929 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1930 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1933 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1934 endpar = sel_end_cursor.par->Next();
1937 /* cut more than one paragraph */
1939 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1940 /* insert a space at the end if there was one */
1942 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1944 sel_end_cursor.par = sel_end_cursor.par->Next();
1945 sel_end_cursor.pos = 0;
1947 cursor = sel_end_cursor;
1949 /* please break behind a space, if there is one. The space should
1951 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1952 sel_start_cursor.pos++;
1954 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1955 if (!sel_start_cursor.pos
1956 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1957 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1958 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1961 /* store the endparagraph for redoing later */
1962 endpar = sel_end_cursor.par->Next(); /* needed because
1967 /*store the selection */
1968 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1969 simple_cut_buffer->previous = 0;
1970 sel_end_cursor.par->previous->next = 0;
1972 /* cut the selection */
1973 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1974 = sel_end_cursor.par;
1976 sel_end_cursor.par->previous
1977 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1979 /* care about footnotes */
1980 if (simple_cut_buffer->footnoteflag) {
1981 LyXParagraph *tmppar = simple_cut_buffer;
1983 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1984 tmppar = tmppar->next;
1988 /* the cut selection should begin with standard layout */
1989 simple_cut_buffer->Clear();
1991 /* paste the paragraphs again, if possible */
1993 sel_start_cursor.par->Next()->ClearParagraph();
1994 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1996 !sel_start_cursor.par->Next()->Last())
1997 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2000 /* maybe a forgotten blank */
2001 if (sel_start_cursor.pos
2002 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2003 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
2004 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2009 /* sometimes necessary */
2011 sel_start_cursor.par->ClearParagraph();
2013 RedoParagraphs(sel_start_cursor, endpar);
2016 cursor = sel_start_cursor;
2017 SetCursor(cursor.par, cursor.pos);
2018 sel_cursor = cursor;
2019 UpdateCounters(cursor.row);
2023 void LyXText::CopySelection()
2026 LyXParagraph::size_type i = 0;
2030 /* this doesnt make sense, if there is no selection */
2035 /* ok we have a selection. This is always between sel_start_cursor
2036 * and sel_end cursor */
2037 LyXParagraph * tmppar;
2039 /* check wether there are half footnotes in the selection */
2040 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2041 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2042 tmppar = sel_start_cursor.par;
2043 while (tmppar != sel_end_cursor.par){
2044 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2045 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2048 tmppar = tmppar->Next();
2052 /* table stuff -- begin*/
2053 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2054 if ( sel_start_cursor.par != sel_end_cursor.par){
2055 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2059 /* table stuff -- end*/
2061 /* delete the simple_cut_buffer */
2062 DeleteSimpleCutBuffer();
2064 /* set the textclass */
2065 simple_cut_buffer_textclass = parameters->textclass;
2067 // copy behind a space if there is one
2068 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2069 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2070 && (sel_start_cursor.par != sel_end_cursor.par
2071 || sel_start_cursor.pos < sel_end_cursor.pos))
2072 sel_start_cursor.pos++;
2074 /* there are two cases: copy only within one paragraph or more than one paragraph */
2075 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2076 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2077 /* only within one paragraph */
2078 simple_cut_buffer = new LyXParagraph;
2080 simple_cut_buffer->text.reserve(500);
2082 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2083 sel_start_cursor.par->CopyIntoMinibuffer(i);
2084 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2088 /* copy more than one paragraph */
2089 /* clone the paragraphs within the selection*/
2090 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2091 simple_cut_buffer = tmppar->Clone();
2092 LyXParagraph *tmppar2 = simple_cut_buffer;
2094 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2096 tmppar = tmppar->next;
2097 tmppar2->next = tmppar->Clone();
2098 tmppar2->next->previous = tmppar2;
2099 tmppar2=tmppar2->next;
2103 /* care about footnotes */
2104 if (simple_cut_buffer->footnoteflag) {
2105 tmppar = simple_cut_buffer;
2107 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2108 tmppar = tmppar->next;
2112 /* the simple_cut_buffer paragraph is too big */
2114 LyXParagraph::size_type tmpi2 =
2115 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2118 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2120 for (;tmpi2;tmpi2--)
2121 simple_cut_buffer->Erase(0);
2123 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2125 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2127 while (tmppar2->size() > tmpi2) {
2128 tmppar2->Erase(tmppar2->text.size() - 1);
2131 while (tmppar2->last > tmpi2) {
2132 tmppar2->Erase(tmppar2->last-1);
2139 void LyXText::PasteSelection()
2141 /* this does not make sense, if there is nothing to paste */
2142 if (!simple_cut_buffer)
2145 LyXParagraph * tmppar;
2146 LyXParagraph * endpar;
2148 LyXCursor tmpcursor;
2150 /* be carefull with footnotes in footnotes */
2151 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2153 /* check whether the cut_buffer includes a footnote */
2154 tmppar = simple_cut_buffer;
2155 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2156 tmppar = tmppar->next;
2159 WriteAlert(_("Impossible operation"),
2160 _("Can't paste float into float!"), _("Sorry."));
2165 /* table stuff -- begin*/
2166 if (cursor.par->table){
2167 if (simple_cut_buffer->next){
2168 WriteAlert(_("Impossible operation"),
2169 _("Table cell cannot include more than one paragraph!"),
2174 /* table stuff -- end*/
2176 SetUndo(Undo::INSERT,
2177 cursor.par->ParFromPos(cursor.pos)->previous,
2178 cursor.par->ParFromPos(cursor.pos)->next);
2182 /* There are two cases: cutbuffer only one paragraph or many */
2183 if (!simple_cut_buffer->next) {
2184 /* only within a paragraph */
2186 /* please break behind a space, if there is one */
2187 while (tmpcursor.par->Last() > tmpcursor.pos
2188 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2191 tmppar = simple_cut_buffer->Clone();
2192 /* table stuff -- begin*/
2193 bool table_too_small = false;
2194 if (tmpcursor.par->table) {
2196 while (simple_cut_buffer->text.size()
2197 && !table_too_small) {
2199 while (simple_cut_buffer->last && !table_too_small){
2201 if (simple_cut_buffer->IsNewline(0)){
2202 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2204 simple_cut_buffer->Erase(0);
2205 if (tmpcursor.pos < tmpcursor.par->Last())
2208 table_too_small = true;
2210 simple_cut_buffer->CutIntoMinibuffer(0);
2211 simple_cut_buffer->Erase(0);
2212 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2217 /* table stuff -- end*/
2219 while (simple_cut_buffer->text.size()){
2221 while (simple_cut_buffer->last){
2223 simple_cut_buffer->CutIntoMinibuffer(0);
2224 simple_cut_buffer->Erase(0);
2225 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2230 delete simple_cut_buffer;
2231 simple_cut_buffer = tmppar;
2232 endpar = tmpcursor.par->Next();
2234 /* many paragraphs */
2236 /* make a copy of the simple cut_buffer */
2237 tmppar = simple_cut_buffer;
2238 LyXParagraph * simple_cut_clone = tmppar->Clone();
2239 LyXParagraph * tmppar2 = simple_cut_clone;
2240 if (cursor.par->footnoteflag){
2241 tmppar->footnoteflag = cursor.par->footnoteflag;
2242 tmppar->footnotekind = cursor.par->footnotekind;
2244 while (tmppar->next) {
2245 tmppar = tmppar->next;
2246 tmppar2->next = tmppar->Clone();
2247 tmppar2->next->previous = tmppar2;
2248 tmppar2=tmppar2->next;
2249 if (cursor.par->footnoteflag){
2250 tmppar->footnoteflag = cursor.par->footnoteflag;
2251 tmppar->footnotekind = cursor.par->footnotekind;
2255 /* make sure there is no class difference */
2256 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2257 parameters->textclass,
2260 /* make the simple_cut_buffer exactly the same layout than
2261 the cursor paragraph */
2262 simple_cut_buffer->MakeSameLayout(cursor.par);
2264 /* find the end of the buffer */
2265 LyXParagraph *lastbuffer = simple_cut_buffer;
2266 while (lastbuffer->Next())
2267 lastbuffer=lastbuffer->Next();
2269 /* find the physical end of the buffer */
2270 lastbuffer = simple_cut_buffer;
2271 while (lastbuffer->Next())
2272 lastbuffer=lastbuffer->Next();
2274 /* please break behind a space, if there is one. The space
2275 * should be copied too */
2276 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2279 bool paste_the_end = false;
2281 /* open the paragraph for inserting the simple_cut_buffer
2283 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2284 cursor.par->BreakParagraphConservative(cursor.pos);
2285 paste_the_end = true;
2288 /* be careful with double spaces */
2289 if ((!cursor.par->Last()
2290 || cursor.par->IsLineSeparator(cursor.pos - 1)
2291 || cursor.par->IsNewline(cursor.pos - 1))
2293 && simple_cut_buffer->text.size()
2295 && simple_cut_buffer->last
2297 && simple_cut_buffer->IsLineSeparator(0))
2298 simple_cut_buffer->Erase(0);
2300 /* set the end for redoing later */
2301 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2304 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2305 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2307 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2308 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2310 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2311 lastbuffer = cursor.par;
2313 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2315 /* store the new cursor position */
2316 tmpcursor.par = lastbuffer;
2317 tmpcursor.pos = lastbuffer->Last();
2319 /* maybe some pasting */
2320 if (lastbuffer->Next() && paste_the_end) {
2321 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2323 /* be careful witth double spaces */
2324 if ((!lastbuffer->Last()
2325 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2326 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2327 && lastbuffer->Next()->Last()
2328 && lastbuffer->Next()->IsLineSeparator(0))
2329 lastbuffer->Next()->Erase(0);
2331 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2334 else if (!lastbuffer->Next()->Last()) {
2335 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2337 /* be careful witth double spaces */
2338 if ((!lastbuffer->Last()
2339 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2340 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2341 && lastbuffer->Next()->Last()
2342 && lastbuffer->Next()->IsLineSeparator(0))
2343 lastbuffer->Next()->Erase(0);
2345 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2348 else if (!lastbuffer->Last()) {
2349 lastbuffer->MakeSameLayout(lastbuffer->next);
2351 /* be careful witth double spaces */
2352 if ((!lastbuffer->Last()
2353 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2354 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2355 && lastbuffer->Next()->Last()
2356 && lastbuffer->Next()->IsLineSeparator(0))
2357 lastbuffer->Next()->Erase(0);
2359 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2362 else lastbuffer->Next()->ClearParagraph();
2365 /* restore the simple cut buffer */
2366 simple_cut_buffer = simple_cut_clone;
2369 RedoParagraphs(cursor, endpar);
2371 SetCursor(cursor.par, cursor.pos);
2374 sel_cursor = cursor;
2375 SetCursor(tmpcursor.par, tmpcursor.pos);
2377 UpdateCounters(cursor.row);
2381 /* returns a pointer to the very first LyXParagraph */
2382 LyXParagraph * LyXText::FirstParagraph()
2384 return params->paragraph;
2388 /* returns true if the specified string is at the specified position */
2390 bool LyXText::IsStringInText(LyXParagraph * par,
2391 LyXParagraph::size_type pos,
2394 bool LyXText::IsStringInText(LyXParagraph * par, int pos, char const * str)
2399 while (pos + i < par->Last() && str[i] &&
2400 str[i] == par->GetChar(pos + i)) {
2410 /* sets the selection over the number of characters of string, no check!! */
2411 void LyXText::SetSelectionOverString(char const * string)
2413 sel_cursor = cursor;
2414 for (int i = 0; string[i]; ++i)
2420 /* simple replacing. The font of the first selected character is used */
2421 void LyXText::ReplaceSelectionWithString(char const * str)
2426 if (!selection) { /* create a dummy selection */
2427 sel_end_cursor = cursor;
2428 sel_start_cursor = cursor;
2431 // Get font setting before we cut
2433 LyXParagraph::size_type pos = sel_end_cursor.pos;
2435 int pos = sel_end_cursor.pos;
2437 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2439 // Insert the new string
2440 for (int i = 0; str[i]; ++i) {
2441 sel_end_cursor.par->InsertChar(pos, str[i]);
2442 sel_end_cursor.par->SetFont(pos, font);
2446 // Cut the selection
2453 /* if the string can be found: return true and set the cursor to
2454 * the new position */
2455 bool LyXText::SearchForward(char const * str)
2457 LyXParagraph * par = cursor.par;
2459 LyXParagraph::size_type pos = cursor.pos;
2461 int pos = cursor.pos;
2463 while (par && !IsStringInText(par, pos, str)) {
2464 if (pos < par->Last() - 1)
2480 bool LyXText::SearchBackward(char const * string)
2482 LyXParagraph * par = cursor.par;
2483 int pos = cursor.pos;
2489 // We skip empty paragraphs (Asger)
2491 par = par->Previous();
2493 pos = par->Last()-1;
2494 } while (par && pos<0);
2496 } while (par && !IsStringInText(par,pos,string));
2508 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2510 char * str = new char[text.size() + 1];
2511 copy(text.begin(), text.end(), str);
2512 str[text.size()] = '\0';
2518 /* needed to insert the selection */
2519 void LyXText::InsertStringA(char const * str)
2521 LyXParagraph * par = cursor.par;
2523 LyXParagraph::size_type pos = cursor.pos;
2524 LyXParagraph::size_type a = 0;
2526 int pos = cursor.pos;
2530 LyXParagraph * endpar = cursor.par->Next();
2534 char flag = textclasslist.Style(parameters->textclass,
2535 cursor.par->GetLayout()).isEnvironment();
2536 /* only to be sure, should not be neccessary */
2539 /* insert the string, don't insert doublespace */
2543 for (i2 = i; str[i2] && str[i2] != '\n'; ++i2);
2544 par->Enlarge(pos, i2 - i);
2548 if (str[i]==' ' && (str[i+1]!=' ')
2549 && pos && par->GetChar(pos-1)!=' ') {
2550 par->InsertChar(pos,' ');
2553 else if (par->table) {
2554 if (str[i] == '\t') {
2556 while((pos < par->size()) &&
2557 (par->GetChar(pos) != LYX_META_NEWLINE))
2559 if (pos < par->size())
2562 while((pos < par->last) &&
2563 (par->GetChar(pos) != LYX_META_NEWLINE))
2565 if (pos < par->last)
2568 else // no more fields to fill skip the rest
2570 } else if ((str[i] != 13) &&
2571 ((str[i] & 127) >= ' ')) {
2572 par->InsertChar(pos,str[i]);
2576 else if (str[i]==' ') {
2577 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2580 else if (str[i]=='\t') {
2581 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2582 par->InsertChar(a, LYX_META_PROTECTED_SEPARATOR);
2586 else if (str[i]!=13 &&
2587 // Ignore unprintables
2588 (str[i] & 127) >= ' ') {
2589 par->InsertChar(pos,str[i]);
2599 while((pos < par->size()) &&
2601 while((pos < par->last) &&
2603 (par->GetChar(pos) != LYX_META_NEWLINE))
2606 cell=NumberOfCell(par,pos);
2608 while((pos < par->size()) &&
2609 !(par->table->IsFirstCell(cell))) {
2610 while((pos < par->size()) &&
2611 (par->GetChar(pos) != LYX_META_NEWLINE))
2614 cell=NumberOfCell(par,pos);
2616 if (pos >= par->size())
2617 // no more fields to fill skip the rest
2620 while((pos < par->last) &&
2621 !(par->table->IsFirstCell(cell))) {
2622 while((pos < par->last) &&
2623 (par->GetChar(pos) != LYX_META_NEWLINE))
2626 cell=NumberOfCell(par,pos);
2628 if (pos >= par->last)
2629 // no more fields to fill skip the rest
2634 if (!par->text.size()) {
2638 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2641 par->BreakParagraph(pos, flag);
2646 for (i2 = i; str[i2] && str[i2] != '\n'; i2++);
2647 par->Enlarge(pos, i2 - i);
2654 RedoParagraphs(cursor,endpar);
2655 SetCursor(cursor.par, cursor.pos);
2656 sel_cursor = cursor;
2657 SetCursor(par, pos);
2663 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2665 char * str = new char[text.size() + 1];
2666 copy(text.begin(), text.end(), str);
2667 str[text.size()] = '\0';
2673 /* turns double-CR to single CR, others where converted into one blank and 13s
2674 * that are ignored .Double spaces are also converted into one. Spaces at
2675 * the beginning of a paragraph are forbidden. tabs are converted into one
2676 * space. then InsertStringA is called */
2677 void LyXText::InsertStringB(char const * s)
2680 LyXParagraph * par = cursor.par;
2683 if (str[i] == '\t' && !par->table)
2685 if (str[i] == ' ' && str[i + 1] == ' ')
2687 if (str[i] == '\n' && str[i + 1] && !par->table){
2688 if (str[i + 1] != '\n') {
2689 if (str[i - 1] != ' ')
2694 while (str[i + 1] && (str[i + 1] == ' '
2695 || str[i + 1] == '\t'
2696 || str[i + 1] == '\n'
2697 || str[i + 1] == 13)) {
2704 InsertStringA(str.c_str());
2708 bool LyXText::GotoNextError()
2710 LyXCursor res=cursor;
2712 if (res.pos < res.par->Last() - 1) {
2716 res.par=res.par->Next();
2721 !(res.par->GetChar(res.pos)==LYX_META_INSET
2722 && res.par->GetInset(res.pos)->AutoDelete()));
2725 SetCursor(res.par, res.pos);
2733 bool LyXText::GotoNextNote()
2735 LyXCursor res=cursor;
2737 if (res.pos < res.par->Last()-1) {
2741 res.par=res.par->Next();
2746 !(res.par->GetChar(res.pos)==LYX_META_INSET
2747 && res.par->GetInset(res.pos)->LyxCode()==Inset::IGNORE_CODE));
2750 SetCursor(res.par, res.pos);
2758 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2761 InsetError * new_inset = 0;
2763 if (!par || class1 == class2)
2765 par = par->FirstPhysicalPar();
2767 string name = textclasslist.NameOfLayout(class1, par->layout);
2769 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2770 textclasslist.NumberOfLayout(class2, name);
2773 } else { // layout not found
2774 // use default layout "Standard" (0)
2779 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2781 string s = "Layout had to be changed from\n"
2782 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2783 + "\nbecause of class conversion from\n"
2784 + textclasslist.NameOfClass(class1) + " to "
2785 + textclasslist.NameOfClass(class2);
2786 new_inset = new InsetError(s);
2787 par->InsertChar(0, LYX_META_INSET);
2788 par->InsertInset(0, new_inset);
2798 void LyXText::CheckParagraph(LyXParagraph * par,
2799 LyXParagraph::size_type pos)
2801 void LyXText::CheckParagraph(LyXParagraph * par, int pos)
2805 LyXCursor tmpcursor;
2807 /* table stuff -- begin*/
2810 CheckParagraphInTable(par, pos);
2813 /* table stuff -- end*/
2817 LyXParagraph::size_type z;
2821 Row * row = GetRow(par, pos, y);
2823 /* is there a break one row above */
2824 if (row->previous && row->previous->par == row->par) {
2825 z = NextBreakPoint(row->previous, paperwidth);
2826 if ( z >= row->pos) {
2827 /* set the dimensions of the row above */
2828 y -= row->previous->height;
2830 refresh_row = row->previous;
2831 status = LyXText::NEED_MORE_REFRESH;
2833 BreakAgain(row->previous);
2835 /* set the cursor again. Otherwise dungling pointers are possible */
2836 SetCursor(cursor.par, cursor.pos);
2837 sel_cursor = cursor;
2842 int tmpheight = row->height;
2844 LyXParagraph::size_type tmplast = RowLast(row);
2846 int tmplast = RowLast(row);
2852 if (row->height == tmpheight && RowLast(row) == tmplast)
2853 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2855 status = LyXText::NEED_MORE_REFRESH;
2857 /* check the special right address boxes */
2858 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2859 tmpcursor.par = par;
2860 tmpcursor.row = row;
2863 tmpcursor.x_fix = 0;
2864 tmpcursor.pos = pos;
2865 RedoDrawingOfParagraph(tmpcursor);
2870 /* set the cursor again. Otherwise dangling pointers are possible */
2871 // also set the selection
2875 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2876 sel_cursor = cursor;
2877 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2878 sel_start_cursor = cursor;
2879 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2880 sel_end_cursor = cursor;
2881 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2882 last_sel_cursor = cursor;
2885 SetCursorIntern(cursor.par, cursor.pos);
2889 /* returns 0 if inset wasn't found */
2890 int LyXText::UpdateInset(Inset * inset)
2892 /* first check the current paragraph */
2893 int pos = cursor.par->GetPositionOfInset(inset);
2895 CheckParagraph(cursor.par, pos);
2899 /* check every paragraph */
2901 LyXParagraph * par = FirstParagraph();
2903 /* make sure the paragraph is open */
2904 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2905 pos = par->GetPositionOfInset(inset);
2907 CheckParagraph(par, pos);
2919 void LyXText::SetCursor(LyXParagraph * par,
2920 LyXParagraph::size_type pos)
2922 void LyXText::SetCursor(LyXParagraph * par, int pos)
2925 LyXCursor old_cursor = cursor;
2926 SetCursorIntern(par, pos);
2927 DeleteEmptyParagraphMechanism(old_cursor);
2932 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2934 void LyXText::SetCursorIntern(LyXParagraph * par, int pos)
2940 LyXParagraph * tmppar;
2942 /* correct the cursor position if impossible */
2943 if (pos > par->Last()){
2944 tmppar = par->ParFromPos(pos);
2945 pos = par->PositionInParFromPos(pos);
2948 if (par->IsDummy() && par->previous &&
2949 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2950 while (par->previous &&
2951 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2952 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2953 par = par->previous ;
2954 if (par->IsDummy() &&
2955 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2957 pos += par->text.size() + 1;
2959 pos += par->last + 1;
2962 if (par->previous) {
2963 par = par->previous;
2966 pos += par->text.size() + 1;
2968 pos += par->last + 1;
2975 /* get the cursor y position in text */
2976 row = GetRow(par, pos, y);
2977 /* y is now the beginning of the cursor row */
2979 /* y is now the cursor baseline */
2982 /* now get the cursors x position */
2985 float fill_separator, fill_hfill, fill_label_hfill;
2986 left_margin = LabelEnd(row);
2987 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2989 LyXParagraph::size_type main_body =
2990 BeginningOfMainBody(row->par);
2992 int main_body = BeginningOfMainBody(row->par);
2994 /* table stuff -- begin*/
2995 if (row->par->table) {
2996 int cell = NumberOfCell(row->par, row->pos);
2998 x += row->par->table->GetBeginningOfTextInCell(cell);
2999 for (pos = row->pos; pos < cursor.pos; pos++) {
3000 if (row->par->IsNewline(pos)) {
3001 x = x_old + row->par->table->WidthOfColumn(cell);
3004 x += row->par->table->GetBeginningOfTextInCell(cell);
3006 x += SingleWidth(row->par, pos);
3010 /* table stuff -- end*/
3012 for (pos = row->pos; pos < cursor.pos; pos++) {
3013 if (pos && pos == main_body
3014 && !row->par->IsLineSeparator(pos - 1)) {
3015 x += GetFont(row->par, -2).stringWidth(
3016 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3017 if (x < left_margin)
3021 x += SingleWidth(row->par, pos);
3022 if (HfillExpansion(row, pos)) {
3023 if (pos >= main_body)
3026 x += fill_label_hfill;
3028 else if (pos >= main_body && row->par->IsSeparator(pos)) {
3032 if (pos + 1 == main_body
3033 && row->par->IsLineSeparator(pos)) {
3034 x += GetFont(row->par, -2).stringWidth(
3035 textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3036 if (row->par->IsLineSeparator(pos))
3037 x-= SingleWidth(row->par, pos);
3038 if (x < left_margin)
3045 cursor.x_fix = cursor.x;
3049 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3050 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3051 && !cursor.par->IsSeparator(cursor.pos))
3053 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3054 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3056 current_font = cursor.par->GetFontSettings(cursor.pos);
3057 real_current_font = GetFont(cursor.par, cursor.pos);
3062 void LyXText::SetCursorFromCoordinates(int x, long y)
3064 LyXCursor old_cursor = cursor;
3066 /* get the row first */
3068 Row * row = GetRowNearY(y);
3070 cursor.par = row->par;
3072 int column = GetColumnNearX(row, x);
3073 cursor.pos = row->pos + column;
3075 cursor.y = y + row->baseline;
3080 (cursor.pos == cursor.par->Last()
3081 || cursor.par->IsSeparator(cursor.pos)
3082 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3083 && !cursor.par->IsSeparator(cursor.pos))
3085 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3086 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3088 current_font = cursor.par->GetFontSettings(cursor.pos);
3089 real_current_font = GetFont(cursor.par, cursor.pos);
3091 DeleteEmptyParagraphMechanism(old_cursor);
3095 void LyXText::CursorLeft()
3098 if (cursor.par->table) {
3099 int cell = NumberOfCell(cursor.par, cursor.pos);
3100 if (cursor.par->table->IsContRow(cell) &&
3101 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3108 void LyXText::CursorLeftIntern()
3110 if (cursor.pos > 0) {
3111 SetCursor(cursor.par, cursor.pos - 1);
3113 else if (cursor.par->Previous()) {
3114 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3119 void LyXText::CursorRight()
3121 CursorRightIntern();
3122 if (cursor.par->table) {
3123 int cell = NumberOfCell(cursor.par, cursor.pos);
3124 if (cursor.par->table->IsContRow(cell) &&
3125 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3132 void LyXText::CursorRightIntern()
3134 if (cursor.pos < cursor.par->Last()) {
3135 SetCursor(cursor.par, cursor.pos + 1);
3137 else if (cursor.par->Next()) {
3138 SetCursor(cursor.par->Next(), 0);
3143 void LyXText::CursorUp()
3145 SetCursorFromCoordinates(cursor.x_fix,
3146 cursor.y - cursor.row->baseline - 1);
3147 if (cursor.par->table) {
3148 int cell = NumberOfCell(cursor.par, cursor.pos);
3149 if (cursor.par->table->IsContRow(cell) &&
3150 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3157 void LyXText::CursorDown()
3159 if (cursor.par->table &&
3160 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3163 SetCursorFromCoordinates(cursor.x_fix,
3164 cursor.y - cursor.row->baseline
3165 + cursor.row->height + 1);
3166 if (cursor.par->table) {
3167 int cell = NumberOfCell(cursor.par, cursor.pos);
3168 int cell_above = cursor.par->table->GetCellAbove(cell);
3169 while(cursor.par->table &&
3170 cursor.par->table->IsContRow(cell) &&
3171 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3172 SetCursorFromCoordinates(cursor.x_fix,
3173 cursor.y - cursor.row->baseline
3174 + cursor.row->height + 1);
3175 if (cursor.par->table) {
3176 cell = NumberOfCell(cursor.par, cursor.pos);
3177 cell_above = cursor.par->table->GetCellAbove(cell);
3184 void LyXText::CursorUpParagraph()
3186 if (cursor.pos > 0) {
3187 SetCursor(cursor.par, 0);
3189 else if (cursor.par->Previous()) {
3190 SetCursor(cursor.par->Previous(), 0);
3195 void LyXText::CursorDownParagraph()
3197 if (cursor.par->Next()) {
3198 SetCursor(cursor.par->Next(), 0);
3200 SetCursor(cursor.par,cursor.par->Last());
3206 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3208 bool deleted = false;
3210 /* this is the delete-empty-paragraph-mechanism. */
3214 // Paragraph should not be deleted if empty
3215 if ((textclasslist.Style(parameters->textclass,
3216 old_cursor.par->GetLayout())).keepempty)
3219 LyXCursor tmpcursor;
3221 if (old_cursor.par != cursor.par) {
3222 if ( (old_cursor.par->Last() == 0
3223 || (old_cursor.par->Last() == 1
3224 && (old_cursor.par->IsLineSeparator(0))))
3225 && old_cursor.par->FirstPhysicalPar()
3226 == old_cursor.par->LastPhysicalPar()) {
3228 /* ok, we will delete anything */
3230 // make sure that you do not delete any environments
3231 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3232 !(old_cursor.row->previous
3233 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3234 && !(old_cursor.row->next
3235 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3237 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3238 ((old_cursor.row->previous
3239 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3241 (old_cursor.row->next
3242 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3244 status = LyXText::NEED_MORE_REFRESH;
3247 if (old_cursor.row->previous) {
3248 refresh_row = old_cursor.row->previous;
3249 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3251 cursor = old_cursor; // that undo can restore the right cursor position
3252 LyXParagraph *endpar = old_cursor.par->next;
3253 if (endpar && endpar->GetDepth()) {
3254 while (endpar && endpar->GetDepth()) {
3255 endpar = endpar->LastPhysicalPar()->Next();
3258 SetUndo(Undo::DELETE,
3259 old_cursor.par->previous,
3263 /* delete old row */
3264 RemoveRow(old_cursor.row);
3265 if (params->paragraph == old_cursor.par) {
3266 params->paragraph = params->paragraph->next;
3268 /* delete old par */
3269 delete old_cursor.par;
3271 /* Breakagain the next par. Needed
3272 * because of the parindent that
3273 * can occur or dissappear. The
3274 * next row can change its height,
3275 * if there is another layout before */
3276 if (refresh_row->next) {
3277 BreakAgain(refresh_row->next);
3278 UpdateCounters(refresh_row);
3280 SetHeightOfRow(refresh_row);
3283 refresh_row = old_cursor.row->next;
3284 refresh_y = old_cursor.y - old_cursor.row->baseline;
3287 cursor = old_cursor; // that undo can restore the right cursor position
3288 LyXParagraph *endpar = old_cursor.par->next;
3289 if (endpar && endpar->GetDepth()) {
3290 while (endpar && endpar->GetDepth()) {
3291 endpar = endpar->LastPhysicalPar()->Next();
3294 SetUndo(Undo::DELETE,
3295 old_cursor.par->previous,
3299 /* delete old row */
3300 RemoveRow(old_cursor.row);
3301 /* delete old par */
3302 if (params->paragraph == old_cursor.par) {
3303 params->paragraph = params->paragraph->next;
3305 delete old_cursor.par;
3307 /* Breakagain the next par. Needed because of
3308 * the parindent that can occur or dissappear.
3309 * The next row can change its height, if there
3310 * is another layout before */
3312 BreakAgain(refresh_row);
3313 UpdateCounters(refresh_row->previous);
3317 /* correct cursor y */
3318 SetCursor(cursor.par, cursor.pos);
3320 /* if (cursor.y > old_cursor.y)
3321 cursor.y -= old_cursor.row->height; */
3323 if (sel_cursor.par == old_cursor.par
3324 && sel_cursor.pos == sel_cursor.pos) {
3325 /* correct selection*/
3326 sel_cursor = cursor;
3332 if (old_cursor.par->ClearParagraph()){
3333 RedoParagraphs(old_cursor, old_cursor.par->Next());
3334 /* correct cursor y */
3335 SetCursor(cursor.par, cursor.pos);
3336 sel_cursor = cursor;
3339 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3340 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3341 if (old_cursor.par->table->IsContRow(cell) &&
3342 IsEmptyTableRow(&old_cursor)) {
3343 RemoveTableRow(&old_cursor);
3350 LyXParagraph * LyXText::GetParFromID(int id)
3352 LyXParagraph * result = FirstParagraph();
3353 while (result && result->GetID() != id)
3354 result = result->next;
3360 bool LyXText::TextUndo()
3361 { // returns false if no undo possible
3362 Undo * undo = params->undostack.Pop();
3366 params->redostack.Push(CreateUndo(undo->kind,
3367 GetParFromID(undo->number_of_before_par),
3368 GetParFromID(undo->number_of_behind_par)));
3370 return TextHandleUndo(undo);
3374 bool LyXText::TextRedo()
3375 { // returns false if no redo possible
3376 Undo * undo = params->redostack.Pop();
3380 params->undostack.Push(CreateUndo(undo->kind,
3381 GetParFromID(undo->number_of_before_par),
3382 GetParFromID(undo->number_of_behind_par)));
3384 return TextHandleUndo(undo);
3388 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3389 bool result = false;
3391 LyXParagraph * before = GetParFromID(undo->number_of_before_par);
3392 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par);
3393 LyXParagraph * tmppar;
3394 LyXParagraph * tmppar2;
3395 LyXParagraph * tmppar3;
3396 LyXParagraph * tmppar4;
3397 LyXParagraph * endpar;
3398 LyXParagraph * tmppar5;
3400 // if there's no before take the beginning of the document for redoing
3402 SetCursorIntern(FirstParagraph(), 0);
3404 // replace the paragraphs with the undo informations
3406 tmppar3 = undo->par;
3407 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3410 while (tmppar4->next)
3411 tmppar4 = tmppar4->next;
3412 } // get last undo par
3414 // now remove the old text if there is any
3415 if (before != behind || (!behind && !before)){
3417 tmppar5 = before->next;
3419 tmppar5 = params->paragraph;
3421 while (tmppar5 && tmppar5 != behind){
3423 tmppar5 = tmppar5->next;
3424 // a memory optimization for edit: Only layout information
3425 // is stored in the undo. So restore the text informations.
3426 if (undo->kind == Undo::EDIT){
3427 tmppar2->text = tmppar->text;
3429 //tmppar->text.clear();
3430 tmppar->text.erase(tmppar->text.begin(),
3431 tmppar->text.end());
3435 tmppar2 = tmppar2->next;
3437 if ( currentrow && currentrow->par == tmppar )
3438 currentrow = currentrow -> previous;
3443 // put the new stuff in the list if there is one
3446 before->next = tmppar3;
3448 params->paragraph = tmppar3;
3449 tmppar3->previous = before;
3453 params->paragraph = behind;
3456 tmppar4->next = behind;
3458 behind->previous = tmppar4;
3462 // Set the cursor for redoing
3464 SetCursorIntern(before->FirstSelfrowPar(), 0);
3465 // check wether before points to a closed float and open it if necessary
3466 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3467 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3469 while (tmppar4->previous &&
3470 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3471 tmppar4 = tmppar4->previous;
3472 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3473 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3474 tmppar4 = tmppar4->next;
3479 // open a cosed footnote at the end if necessary
3480 if (behind && behind->previous &&
3481 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3482 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3483 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3484 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3485 behind = behind->next;
3489 // calculate the endpar for redoing the paragraphs.
3491 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3492 endpar = behind->LastPhysicalPar()->Next();
3494 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3499 tmppar = GetParFromID(undo->number_of_cursor_par);
3500 RedoParagraphs(cursor, endpar);
3502 SetCursorIntern(tmppar, undo->cursor_pos);
3503 UpdateCounters(cursor.row);
3513 void LyXText::FinishUndo()
3514 { // makes sure the next operation will be stored
3515 undo_finished = True;
3519 void LyXText::FreezeUndo()
3520 { // this is dangerous and for internal use only
3525 void LyXText::UnFreezeUndo()
3526 { // this is dangerous and for internal use only
3527 undo_frozen = false;
3531 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3532 LyXParagraph * behind)
3535 params->undostack.Push(CreateUndo(kind, before, behind));
3536 params->redostack.Clear();
3540 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3541 LyXParagraph * behind)
3543 params->redostack.Push(CreateUndo(kind, before, behind));
3547 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3548 LyXParagraph * behind)
3550 int before_number = -1;
3551 int behind_number = -1;
3553 before_number = before->GetID();
3555 behind_number = behind->GetID();
3556 // Undo::EDIT and Undo::FINISH are
3557 // always finished. (no overlapping there)
3558 // overlapping only with insert and delete inside one paragraph:
3559 // Nobody wants all removed character
3560 // appear one by one when undoing.
3561 // EDIT is special since only layout information, not the
3562 // contents of a paragaph are stored.
3563 if (!undo_finished && kind != Undo::EDIT &&
3564 kind != Undo::FINISH){
3565 // check wether storing is needed
3566 if (params->undostack.Top() &&
3567 params->undostack.Top()->kind == kind &&
3568 params->undostack.Top()->number_of_before_par == before_number &&
3569 params->undostack.Top()->number_of_behind_par == behind_number ){
3574 // create a new Undo
3575 LyXParagraph * undopar;
3576 LyXParagraph * tmppar;
3577 LyXParagraph * tmppar2;
3579 LyXParagraph * start = 0;
3580 LyXParagraph * end = 0;
3583 start = before->next;
3585 start = FirstParagraph();
3587 end = behind->previous;
3589 end = FirstParagraph();
3594 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3596 tmppar2 = tmppar->Clone();
3597 tmppar2->SetID(tmppar->GetID());
3599 // a memory optimization: Just store the layout information when only edit
3600 if (kind == Undo::EDIT){
3602 //tmppar2->text.clear();
3603 tmppar2->text.erase(tmppar2->text.begin(),
3604 tmppar2->text.end());
3607 delete[] tmppar2->text;
3614 while (tmppar != end && tmppar->next) {
3615 tmppar = tmppar->next;
3616 tmppar2->next = tmppar->Clone();
3617 tmppar2->next->SetID(tmppar->GetID());
3618 // a memory optimization: Just store the layout information when only edit
3619 if (kind == Undo::EDIT){
3621 //tmppar2->next->text.clear();
3622 tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3624 if (tmppar2->next->text)
3625 delete[] tmppar2->next->text;
3626 tmppar2->next->text = 0;
3629 tmppar2->next->previous = tmppar2;
3630 tmppar2=tmppar2->next;
3635 undopar = 0; // nothing to replace (undo of delete maybe)
3637 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3638 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3640 Undo * undo = new Undo(kind,
3641 before_number, behind_number,
3642 cursor_par, cursor_pos,
3645 undo_finished = false;
3650 void LyXText::SetCursorParUndo()
3652 SetUndo(Undo::FINISH,
3653 cursor.par->ParFromPos(cursor.pos)->previous,
3654 cursor.par->ParFromPos(cursor.pos)->next);
3657 void LyXText::RemoveTableRow(LyXCursor * cursor)
3665 /* move to the previous row */
3666 cell_act = NumberOfCell(cursor->par, cursor->pos);
3669 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3671 while (cursor->pos &&
3672 !cursor->par->table->IsFirstCell(cell_act)){
3674 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3679 /* now we have to pay attention if the actual table is the
3680 main row of TableContRows and if yes to delete all of them */
3685 /* delete up to the next row */
3686 while (cursor->pos < cursor->par->Last() &&
3688 || !cursor->par->table->IsFirstCell(cell_act))){
3689 while (cursor->pos < cursor->par->Last() &&
3690 !cursor->par->IsNewline(cursor->pos))
3691 cursor->par->Erase(cursor->pos);
3694 if (cursor->pos < cursor->par->Last())
3695 cursor->par-> Erase(cursor->pos);
3697 if (cursor->pos && cursor->pos == cursor->par->Last()){
3699 cursor->par->Erase(cursor->pos); // no newline at the very end!
3701 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3702 !cursor->par->table->IsContRow(cell_org) &&
3703 cursor->par->table->IsContRow(cell));
3704 cursor->par->table->DeleteRow(cell_org);
3709 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor)
3711 if (!old_cursor->par->table)
3713 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3715 pos = old_cursor->pos,
3716 cell = NumberOfCell(old_cursor->par, pos);
3718 // search first charater of this table row
3719 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3721 while (pos && !old_cursor->par->IsNewline(pos-1))
3725 if (!old_cursor->par->IsNewline(pos))
3729 while ((pos < old_cursor->par->Last()) &&
3730 !old_cursor->par->table->IsFirstCell(cell)) {
3731 if (!old_cursor->par->IsNewline(pos))
3742 bool LyXText::IsEmptyTableCell()
3745 LyXParagraph::size_type pos = cursor.pos - 1;
3747 int pos = cursor.pos - 1;
3749 while (pos >= 0 && pos < cursor.par->Last()
3750 && !cursor.par->IsNewline(pos))
3752 return cursor.par->IsNewline(pos + 1);
3755 void LyXText::toggleAppendix(){
3756 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3757 bool start = !par->start_of_appendix;
3759 /* ensure that we have only one start_of_appendix in this document */
3760 LyXParagraph * tmp = FirstParagraph();
3761 for (;tmp;tmp=tmp->next)
3762 tmp->start_of_appendix = 0;
3763 par->start_of_appendix = start;
3765 /* we can set the refreshing parameters now */
3766 status = LyXText::NEED_MORE_REFRESH;
3768 refresh_row = 0; // not needed for full update
3770 SetCursor(cursor.par, cursor.pos);