1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 1995 Matthias Ettrich
7 * Copyright (C) 1995-1998 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 "textutils.h"
29 #include "minibuffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
36 // $Id: text2.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $
38 #if !defined(lint) && !defined(WITH_WARNINGS)
39 static char vcid[] = "$Id: text2.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $";
42 extern MiniBuffer *minibuffer;
45 LyXText::LyXText(int pw, Buffer *p)
52 parameters = &p->params;
56 status = LyXText::UNCHANGED;
57 LyXParagraph *par = p->paragraph;
58 current_font = GetFont(par, 0);
63 InsertParagraph(par, lastrow);
66 /* set cursor at the very top position */
67 selection = true; /* these setting is necessary
68 * because of the delete-empty-
69 * paragraph mechanism in
71 SetCursor(firstrow->par, 0);
76 /* no rebreak necessary */
77 need_break_row = NULL;
82 // Default layouttype for copy environment type
90 // Delete all rows, this does not touch the paragraphs!
91 Row *tmprow = firstrow;
93 tmprow = firstrow->next;
100 // Gets the fully instantiated font at a given position in a paragraph
101 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
102 // The difference is that this one is used for displaying, and thus we
103 // are allowed to make cosmetic improvements. For instance make footnotes
105 // If position is -1, we get the layout font of the paragraph.
106 // If position is -2, we get the font of the manual label of the paragraph.
107 LyXFont LyXText::GetFont(LyXParagraph* par, int pos)
110 lyxstyle.Style(parameters->textclass, par->GetLayout());
112 char par_depth = par->GetDepth();
113 // We specialize the 95% common case:
114 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
117 if (layout->labeltype == LABEL_MANUAL
118 && pos < BeginningOfMainBody(par)) {
120 return par->GetFontSettings(pos).
121 realize(layout->reslabelfont);
123 return par->GetFontSettings(pos).
124 realize(layout->resfont);
127 // process layoutfont for pos == -1 and labelfont for pos < -1
129 return layout->resfont;
131 return layout->reslabelfont;
135 // The uncommon case need not be optimized as much
137 LyXFont layoutfont, tmpfont;
141 if (pos < BeginningOfMainBody(par)) {
143 layoutfont = layout->labelfont;
146 layoutfont = layout->font;
148 tmpfont = par->GetFontSettings(pos);
149 tmpfont.realize(layoutfont);
152 // process layoutfont for pos == -1 and labelfont for pos < -1
154 tmpfont = layout->font;
156 tmpfont = layout->labelfont;
159 // Resolve against environment font information
160 //if (par->GetDepth()){ // already in while condition
161 while (par && par_depth && !tmpfont.resolved()) {
162 par = par->DepthHook(par_depth - 1);
164 tmpfont.realize(lyxstyle.
165 Style(parameters->textclass,
166 par->GetLayout())->font);
167 par_depth = par->GetDepth();
172 tmpfont.realize(lyxstyle.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) {
185 void LyXText::SetCharFont(LyXParagraph *par, int pos, LyXFont font)
187 /* let the insets convert their font */
188 if (par->GetChar(pos) == LYX_META_INSET) {
189 if (par->GetInset(pos))
190 font = par->GetInset(pos)->ConvertFont(font);
193 LyXLayout *layout = lyxstyle.Style(parameters->textclass,
196 // Get concrete layout font to reduce against
199 if (pos < BeginningOfMainBody(par))
200 layoutfont = layout->labelfont;
202 layoutfont = layout->font;
204 // Realize against environment font information
205 if (par->GetDepth()){
206 LyXParagraph * tp = par;
207 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
208 tp = tp->DepthHook(tp->GetDepth()-1);
210 layoutfont.realize(lyxstyle.
211 Style(parameters->textclass,
212 tp->GetLayout())->font);
216 layoutfont.realize(lyxstyle.TextClass(parameters->textclass)->defaultfont);
218 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
219 && par->footnotekind == LyXParagraph::FOOTNOTE) {
220 layoutfont.decSize();
223 // Now, reduce font against full layout font
224 font.reduce(layoutfont);
226 par->SetFont(pos, font);
230 /* inserts a new row behind the specified row, increments
231 * the touched counters */
232 void LyXText::InsertRow(Row *row, LyXParagraph *par, int pos)
234 Row *tmprow = new Row;
236 tmprow->previous = NULL;
237 tmprow->next = firstrow;
241 tmprow->previous = row;
242 tmprow->next = row->next;
247 tmprow->next->previous = tmprow;
249 if (tmprow->previous)
250 tmprow->previous->next = tmprow;
258 number_of_rows++; /* one more row */
262 /* removes the row and reset the touched counters */
263 void LyXText::RemoveRow(Row *row)
265 /* this must not happen before the currentrow for clear reasons.
266 so the trick is just to set the current row onto the previous
269 GetRow(row->par, row->pos, unused_y);
270 currentrow = currentrow->previous;
272 currentrow_y -= currentrow->height;
277 row->next->previous = row->previous;
278 if (!row->previous) {
279 firstrow = row->next;
282 row->previous->next = row->next;
285 lastrow = row->previous;
287 height -= row->height; /* the text becomes smaller */
290 number_of_rows--; /* one row less */
293 /* remove all following rows of the paragraph of the specified row. */
294 void LyXText::RemoveParagraph(Row *row)
296 LyXParagraph *tmppar;
302 while (row && row->par == tmppar) {
310 /* insert the specified paragraph behind the specified row */
311 void LyXText::InsertParagraph(LyXParagraph *par, Row *row)
313 InsertRow(row, par, 0); /* insert a new row, starting
316 SetCounter(par); /* set the counters */
318 /* and now append the whole paragraph behind the new row */
320 firstrow->height = 0;
321 AppendParagraph(firstrow);
324 row->next->height = 0;
325 AppendParagraph(row->next);
330 void LyXText::ToggleFootnote()
334 par = cursor.par->ParFromPos(cursor.pos);
335 if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
337 minibuffer->Set(_("Opened float"));
340 minibuffer->Set(_("Closed float"));
346 void LyXText::OpenStuff()
348 if (cursor.pos == 0 && cursor.par->bibkey){
349 cursor.par->bibkey->Edit(0,0);
351 else if (cursor.pos < cursor.par->Last()
352 && cursor.par->GetChar(cursor.pos) == LYX_META_INSET
353 && cursor.par->GetInset(cursor.pos)->Editable()) {
354 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
355 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
357 cursor.par->GetInset(cursor.pos)->Edit(0,0);
365 void LyXText::CloseFootnote()
367 LyXParagraph *par, *endpar,*tmppar;
370 par = cursor.par->ParFromPos(cursor.pos);
372 /* if the cursor is not in an open footnote, or
373 * there is no open footnote in this paragraph, just return. */
374 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
377 || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
378 minibuffer->Set(_("Nothing to do"));
382 /* ok, move the cursor right before the footnote */
384 /* just a little faster than using CursorRight() */
385 for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
386 /* now the cursor is at the beginning of the physical par */
387 SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
390 /* we are in a footnote, so let us move at the beginning */
391 /* while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
392 cursor.par = cursor.par->Previous();
394 SetCursor(cursor.par, cursor.par->Last()); */
395 /* this is just faster than using just CursorLeft() */
398 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
399 /* just a little bit faster than movin the cursor */
400 tmppar = tmppar->Previous();
402 SetCursor(tmppar, tmppar->Last());
405 /* the cursor must be exactly before the footnote */
406 par = cursor.par->ParFromPos(cursor.pos);
408 status = LyXText::NEED_MORE_REFRESH;
409 refresh_row = cursor.row;
410 refresh_y = cursor.y - cursor.row->baseline;
413 endpar = par->NextAfterFootnote()->Next();
416 tmppar->CloseFootnote(cursor.pos);
418 /* set the dimensions of the cursor row */
419 /* row->fill = Fill(row, paperwidth);
420 SetHeightOfRow(row); */
422 while (tmppar != endpar) {
423 RemoveRow(row->next);
425 tmppar = row->next->par;
430 AppendParagraph(cursor.row);
432 SetCursor(cursor.par, cursor.pos);
436 if (cursor.row->next)
437 SetHeightOfRow(cursor.row->next);
441 /* used in setlayout */
442 // Asger is not sure we want to do this...
443 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph *par)
445 LyXFont layoutfont, tmpfont;
449 LyXLayout* layout = lyxstyle.Style(parameters->textclass, par->GetLayout());
451 for (pos = 0; pos < par->Last(); pos++) {
452 if (pos < BeginningOfMainBody(par))
453 layoutfont = layout->labelfont;
455 layoutfont = layout->font;
457 tmpfont = par->GetFontSettings(pos);
458 tmpfont.reduce(layoutfont);
459 par->SetFont(pos, tmpfont);
464 /* set layout over selection and make a total rebreak of those paragraphs */
465 void LyXText::SetLayout(char layout)
469 /* if there is no selection just set the layout of the current paragraph */
471 sel_start_cursor = cursor; /* dummy selection */
472 sel_end_cursor = cursor;
475 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
476 LyXParagraph *undoendpar = endpar;
478 if (endpar && endpar->GetDepth()) {
479 while (endpar && endpar->GetDepth()) {
481 endpar = endpar->LastPhysicalPar()->Next();
486 endpar = endpar->Next(); /* because of parindents etc. */
490 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
493 tmpcursor = cursor; /* store the current cursor */
495 /* ok we have a selection. This is always between sel_start_cursor
496 * and sel_end cursor */
497 cursor = sel_start_cursor;
499 LyXLayout * lyxlayout = lyxstyle.Style(parameters->textclass, layout);
501 while (cursor.par != sel_end_cursor.par) {
502 if (cursor.par->footnoteflag ==
503 sel_start_cursor.par->footnoteflag) {
504 cursor.par->SetLayout(layout);
505 MakeFontEntriesLayoutSpecific(cursor.par);
506 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
507 fppar->added_space_top = lyxlayout->fill_top ?
508 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
509 fppar->added_space_bottom = lyxlayout->fill_bottom ?
510 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
511 if (lyxlayout->margintype == MARGIN_MANUAL)
512 cursor.par->SetLabelWidthString(lyxlayout->labelstring);
513 if (lyxlayout->labeltype != LABEL_BIBLIO
515 delete fppar->bibkey;
519 cursor.par = cursor.par->Next();
521 if (cursor.par->footnoteflag ==
522 sel_start_cursor.par->footnoteflag) {
523 cursor.par->SetLayout(layout);
524 MakeFontEntriesLayoutSpecific(cursor.par);
525 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
526 fppar->added_space_top = lyxlayout->fill_top ?
527 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
528 fppar->added_space_bottom = lyxlayout->fill_bottom ?
529 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
530 if (lyxlayout->margintype == MARGIN_MANUAL)
531 cursor.par->SetLabelWidthString(lyxlayout->labelstring);
532 if (lyxlayout->labeltype != LABEL_BIBLIO
534 delete fppar->bibkey;
539 RedoParagraphs(sel_start_cursor, endpar);
541 /* we have to reset the selection, because the
542 * geometry could have changed */
543 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
545 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
546 UpdateCounters(cursor.row);
549 SetCursor(tmpcursor.par, tmpcursor.pos);
553 /* increment depth over selection and
554 * make a total rebreak of those paragraphs */
555 void LyXText::IncDepth()
557 // If there is no selection, just use the current paragraph
559 sel_start_cursor = cursor; /* dummy selection */
560 sel_end_cursor = cursor;
563 // We end at the next paragraph with depth 0
564 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
565 LyXParagraph *undoendpar = endpar;
567 if (endpar && endpar->GetDepth()) {
568 while (endpar && endpar->GetDepth()) {
569 endpar = endpar->LastPhysicalPar()->Next();
574 endpar = endpar->Next(); /* because of parindents etc. */
578 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
581 LyXCursor tmpcursor = cursor; /* store the current cursor */
583 /* ok we have a selection. This is always between sel_start_cursor
584 * and sel_end cursor */
585 cursor = sel_start_cursor;
587 bool anything_changed = false;
590 // NOTE: you can't change the depth of a bibliography entry
591 if (cursor.par->footnoteflag ==
592 sel_start_cursor.par->footnoteflag
593 && lyxstyle.Style(parameters->textclass,
594 cursor.par->GetLayout()
595 )->labeltype != LABEL_BIBLIO) {
596 LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
598 && (prev->GetDepth() - cursor.par->GetDepth() > 0
599 || (prev->GetDepth() == cursor.par->GetDepth()
600 && lyxstyle.Style(parameters->textclass,
601 prev->GetLayout())->isEnvironment()))) {
602 cursor.par->FirstPhysicalPar()->depth++;
603 anything_changed = true;
606 if (cursor.par == sel_end_cursor.par)
608 cursor.par = cursor.par->Next();
611 /* if nothing changed set all depth to 0 */
612 if (!anything_changed) {
613 cursor = sel_start_cursor;
614 while (cursor.par != sel_end_cursor.par) {
615 cursor.par->FirstPhysicalPar()->depth = 0;
616 cursor.par = cursor.par->Next();
618 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
619 cursor.par->FirstPhysicalPar()->depth = 0;
622 RedoParagraphs(sel_start_cursor, endpar);
624 /* we have to reset the selection, because the
625 * geometry could have changed */
626 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
628 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
629 UpdateCounters(cursor.row);
632 SetCursor(tmpcursor.par, tmpcursor.pos);
636 /* decrement depth over selection and
637 * make a total rebreak of those paragraphs */
638 void LyXText::DecDepth()
640 /* if there is no selection just set the layout of the current paragraph */
642 sel_start_cursor = cursor; /* dummy selection */
643 sel_end_cursor = cursor;
646 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
647 LyXParagraph *undoendpar = endpar;
649 if (endpar && endpar->GetDepth()) {
650 while (endpar && endpar->GetDepth()) {
651 endpar = endpar->LastPhysicalPar()->Next();
656 endpar = endpar->Next(); /* because of parindents etc. */
660 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
663 LyXCursor tmpcursor = cursor; /* store the current cursor */
665 /* ok we have a selection. This is always between sel_start_cursor
666 * and sel_end cursor */
667 cursor = sel_start_cursor;
670 if (cursor.par->footnoteflag ==
671 sel_start_cursor.par->footnoteflag) {
672 if (cursor.par->FirstPhysicalPar()->depth)
673 cursor.par->FirstPhysicalPar()->depth--;
675 if (cursor.par == sel_end_cursor.par)
677 cursor.par = cursor.par->Next();
680 RedoParagraphs(sel_start_cursor, endpar);
682 /* we have to reset the selection, because the
683 * geometry could have changed */
684 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
686 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
687 UpdateCounters(cursor.row);
690 SetCursor(tmpcursor.par, tmpcursor.pos);
694 /* set font over selection and make a total rebreak of those paragraphs */
695 void LyXText::SetFont(LyXFont font, bool toggleall)
697 /* if there is no selection just set the current_font */
699 // Determine basis font
701 if (cursor.pos < BeginningOfMainBody(cursor.par))
702 layoutfont = GetFont(cursor.par, -2);
704 layoutfont = GetFont(cursor.par, -1);
706 // Update current font
707 real_current_font.update(font,toggleall);
709 // Reduce to implicit settings
710 current_font = real_current_font;
711 current_font.reduce(layoutfont);
712 // And resolve it completely
713 real_current_font.realize(layoutfont);
717 LyXCursor tmpcursor = cursor; /* store the current cursor */
719 /* ok we have a selection. This is always between sel_start_cursor
720 * and sel_end cursor */
723 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
724 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
725 cursor = sel_start_cursor;
726 while (cursor.par != sel_end_cursor.par ||
727 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
728 && cursor.pos < sel_end_cursor.pos))
730 if (cursor.pos < cursor.par->Last()
731 && cursor.par->footnoteflag
732 == sel_start_cursor.par->footnoteflag) { /* an open footnote
735 LyXFont newfont = GetFont(cursor.par,cursor.pos);
736 newfont.update(font,toggleall);
737 SetCharFont(cursor.par, cursor.pos, newfont);
741 cursor.par = cursor.par->Next();
745 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
747 /* we have to reset the selection, because the
748 * geometry could have changed */
749 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
751 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
754 SetCursor(tmpcursor.par, tmpcursor.pos);
758 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
761 LyXParagraph *first_phys_par;
766 y = cursor.y - tmprow->baseline;
767 SetHeightOfRow(tmprow);
768 first_phys_par = tmprow->par->FirstPhysicalPar();
769 /* find the first row of the paragraph */
770 if (first_phys_par != tmprow->par)
771 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
772 tmprow = tmprow->previous;
774 SetHeightOfRow(tmprow);
776 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
777 tmprow = tmprow->previous;
779 SetHeightOfRow(tmprow);
782 /* we can set the refreshing parameters now */
783 status = LyXText::NEED_MORE_REFRESH;
785 refresh_row = tmprow;
786 SetCursor(cursor.par, cursor.pos);
790 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
793 LyXParagraph *first_phys_par;
798 y = cursor.y - tmprow->baseline;
799 SetHeightOfRow(tmprow);
800 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)
828 Row *tmprow, *tmprow2;
829 LyXParagraph *tmppar, *first_phys_par;
834 y = cursor.y - tmprow->baseline;
836 if (!tmprow->previous){
837 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
840 first_phys_par = tmprow->par->FirstPhysicalPar();
841 /* find the first row of the paragraph */
842 if (first_phys_par != tmprow->par)
843 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
844 tmprow = tmprow->previous;
847 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
848 tmprow = tmprow->previous;
853 /* we can set the refreshing parameters now */
854 status = LyXText::NEED_MORE_REFRESH;
856 refresh_row = tmprow->previous; /* the real refresh row will
857 * be deleted, so I store
858 * the previous here */
861 tmppar = tmprow->next->par;
864 while (tmppar != endpar) {
865 RemoveRow(tmprow->next);
867 tmppar = tmprow->next->par;
872 /* remove the first one */
873 tmprow2 = tmprow; /* this is because tmprow->previous
875 tmprow = tmprow->previous;
878 tmppar = first_phys_par;
882 InsertParagraph(tmppar, tmprow);
885 while (tmprow->next && tmprow->next->par == tmppar)
886 tmprow = tmprow->next;
887 tmppar = tmppar->Next();
891 while (tmppar != endpar);
893 /* this is because of layout changes */
895 refresh_y -= refresh_row->height;
896 SetHeightOfRow(refresh_row);
899 refresh_row = firstrow;
901 SetHeightOfRow(refresh_row);
904 if (tmprow && tmprow->next)
905 SetHeightOfRow(tmprow->next);
907 /* restore the correct refresh row */
909 refresh_row = refresh_row->next;
911 refresh_row = firstrow;*/
915 int LyXText::FullRebreak()
917 if (need_break_row) {
918 BreakAgain(need_break_row);
919 need_break_row = NULL;
926 /* important for the screen */
929 /* the cursor set functions have a special mechanism. When they
930 * realize, that you left an empty paragraph, they will delete it.
931 * They also delet the corresponding row */
933 /* need the selection cursor: */
934 void LyXText::SetSelection()
937 last_sel_cursor = sel_cursor;
938 sel_start_cursor = sel_cursor;
939 sel_end_cursor = sel_cursor;
944 /* first the toggling area */
945 if (cursor.y < last_sel_cursor.y ||
946 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
947 toggle_end_cursor = last_sel_cursor;
948 toggle_cursor = cursor;
951 toggle_end_cursor = cursor;
952 toggle_cursor = last_sel_cursor;
955 last_sel_cursor = cursor;
957 /* and now the whole selection */
959 if (sel_cursor.y < cursor.y ||
960 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
961 sel_end_cursor = cursor;
962 sel_start_cursor = sel_cursor;
965 sel_end_cursor = sel_cursor;
966 sel_start_cursor = cursor;
969 /* a selection with no contents is not a selection */
970 if (sel_start_cursor.x == sel_end_cursor.x &&
971 sel_start_cursor.y == sel_end_cursor.y)
976 void LyXText::ClearSelection()
983 void LyXText::CursorHome()
985 SetCursor(cursor.par, cursor.row->pos);
989 void LyXText::CursorEnd()
991 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
992 SetCursor(cursor.par, RowLast(cursor.row) + 1);
994 if (cursor.par->Last() &&
995 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
996 || cursor.par->IsNewline(RowLast(cursor.row))))
997 SetCursor(cursor.par, RowLast(cursor.row));
999 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1001 if (cursor.par->table) {
1002 int cell = NumberOfCell(cursor.par, cursor.pos);
1003 if (cursor.par->table->RowHasContRow(cell) &&
1004 cursor.par->table->CellHasContRow(cell)<0) {
1005 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1006 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1008 if (cursor.par->Last() &&
1009 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1010 || cursor.par->IsNewline(RowLast(cursor.row))))
1011 SetCursor(cursor.par, RowLast(cursor.row));
1013 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1020 void LyXText::CursorTop()
1022 while (cursor.par->Previous())
1023 cursor.par = cursor.par->Previous();
1024 SetCursor(cursor.par, 0);
1028 void LyXText::CursorBottom()
1030 while (cursor.par->Next())
1031 cursor.par = cursor.par->Next();
1032 SetCursor(cursor.par, cursor.par->Last());
1036 /* returns a pointer to the row near the specified y-coordinate
1037 * (relative to the whole text). y is set to the real beginning
1039 Row* LyXText::GetRowNearY(long& y)
1045 tmprow = currentrow;
1046 tmpy = currentrow_y;
1054 while (tmprow->next && tmpy + tmprow->height <= y) {
1055 tmpy += tmprow->height;
1056 tmprow = tmprow->next;
1059 while (tmprow->previous && tmpy > y) {
1060 tmprow = tmprow->previous;
1061 tmpy -= tmprow->height;
1064 currentrow = tmprow;
1065 currentrow_y = tmpy;
1067 y = tmpy; /* return the real y */
1072 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1074 // If the mask is completely neutral, tell user
1075 if (font == LyXFont(LyXFont::ALL_IGNORE)){
1076 // Could only happen with user style
1077 minibuffer->Set(_("No font change defined. Use Character under"
1078 " the Layout menu to define font change."));
1082 // Try implicit word selection
1083 LyXCursor resetCursor = cursor;
1084 int implicitSelection = SelectWordWhenUnderCursor();
1087 SetFont(font,toggleall);
1088 //minibuffer->Set(_("Font style changed"));
1090 /* Implicit selections are cleared afterwards and cursor is set to the
1091 original position. */
1092 if (implicitSelection) {
1094 cursor = resetCursor;
1095 SetCursor( cursor.par, cursor.pos );
1096 sel_cursor = cursor;
1101 int LyXText::BeginningOfMainBody(LyXParagraph *par)
1103 if (lyxstyle.Style(parameters->textclass, par->GetLayout())->labeltype != LABEL_MANUAL)
1106 return par->BeginningOfMainBody();
1110 /* if there is a selection, reset every environment you can find
1111 * in the selection, otherwise just the environment you are in */
1112 void LyXText::MeltFootnoteEnvironment()
1114 LyXParagraph *tmppar, *firsttmppar;
1118 /* is is only allowed, if the cursor is IN an open footnote.
1119 * Otherwise it is too dangerous */
1120 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1123 SetUndo(Undo::FINISH,
1124 cursor.par->PreviousBeforeFootnote()->previous,
1125 cursor.par->NextAfterFootnote()->next);
1127 /* ok, move to the beginning of the footnote. */
1128 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1129 cursor.par = cursor.par->Previous();
1131 SetCursor(cursor.par, cursor.par->Last());
1132 /* this is just faster than using CursorLeft(); */
1134 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1135 tmppar = firsttmppar;
1136 /* tmppar is now the paragraph right before the footnote */
1138 char first_footnote_par_is_not_empty = tmppar->next->last;
1140 while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1141 tmppar = tmppar->next; /* I use next instead of Next(),
1142 * because there cannot be any
1143 * footnotes in a footnote
1145 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1147 /* remember the captions and empty paragraphs */
1148 if ((lyxstyle.Style(parameters->textclass,
1149 tmppar->GetLayout())->labeltype == LABEL_SENSITIVE)
1151 tmppar->SetLayout(0);
1154 /* now we will paste the ex-footnote, if the layouts allow it */
1155 /* first restore the layout of the paragraph right behind the footnote*/
1157 tmppar->next->MakeSameLayout(cursor.par);
1160 if ((!tmppar->GetLayout() && !tmppar->table)
1161 || (tmppar->Next() && (!tmppar->Next()->Last()
1162 || tmppar->Next()->HasSameLayout(tmppar)))) {
1163 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1164 tmppar->Next()->Erase(0);
1165 tmppar->PasteParagraph();
1168 tmppar = tmppar->Next(); /* make shure tmppar cannot be touched
1169 * by the pasting of the beginning */
1171 /* then the beginning */
1172 /* if there is no space between the text and the footnote, so we insert
1174 * (only if the previous par and the footnotepar are not empty!) */
1175 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1176 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1177 if (firsttmppar->last
1178 && !firsttmppar->IsSeparator(firsttmppar->last - 1)
1179 && first_footnote_par_is_not_empty) {
1180 firsttmppar->next->InsertChar(0, ' ');
1182 firsttmppar->PasteParagraph();
1185 /* now redo the paragaphs */
1186 RedoParagraphs(cursor, tmppar);
1188 SetCursor(cursor.par, cursor.pos);
1190 /* sometimes it can happen, that there is a counter change */
1191 Row *row = cursor.row;
1192 while (row->next && row->par != tmppar && row->next->par != tmppar)
1194 UpdateCounters(row);
1201 /* the DTP switches for paragraphs. LyX will store them in the
1202 * first physicla paragraph. When a paragraph is broken, the top settings
1203 * rest, the bottom settings are given to the new one. So I can make shure,
1204 * they do not duplicate themself and you cannnot make dirty things with
1207 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1208 bool pagebreak_top, bool pagebreak_bottom,
1209 VSpace space_top, VSpace space_bottom,
1211 LString labelwidthstring,
1214 LyXCursor tmpcursor;
1216 LyXParagraph *tmppar;
1218 sel_start_cursor = cursor;
1219 sel_end_cursor = cursor;
1222 // make sure that the depth behind the selection are restored, too
1223 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1224 LyXParagraph *undoendpar = endpar;
1226 if (endpar && endpar->GetDepth()) {
1227 while (endpar && endpar->GetDepth()) {
1228 endpar = endpar->LastPhysicalPar()->Next();
1229 undoendpar = endpar;
1233 endpar = endpar->Next(); /* because of parindents etc. */
1237 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1241 tmppar = sel_end_cursor.par;
1242 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous())
1244 SetCursor(tmppar->FirstPhysicalPar(), 0);
1245 status = LyXText::NEED_MORE_REFRESH;
1246 refresh_row = cursor.row;
1247 refresh_y = cursor.y - cursor.row->baseline;
1248 if (cursor.par->footnoteflag ==
1249 sel_start_cursor.par->footnoteflag) {
1250 cursor.par->line_top = line_top;
1251 cursor.par->line_bottom = line_bottom;
1252 cursor.par->pagebreak_top = pagebreak_top;
1253 cursor.par->pagebreak_bottom = pagebreak_bottom;
1254 cursor.par->added_space_top = space_top;
1255 cursor.par->added_space_bottom = space_bottom;
1256 /* does the layout allow the new alignment? */
1257 if (align == LYX_ALIGN_LAYOUT)
1258 align = lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->align;
1259 if (align & lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->alignpossible) {
1260 if (align == lyxstyle.Style(parameters->textclass, cursor.par->GetLayout())->align)
1261 cursor.par->align = LYX_ALIGN_LAYOUT;
1263 cursor.par->align = align;
1265 cursor.par->SetLabelWidthString(labelwidthstring);
1266 cursor.par->noindent = noindent;
1270 tmprow = cursor.row;
1271 while (tmprow->next && tmprow->next->par->previous != cursor.par->LastPhysicalPar())
1272 tmprow = tmprow->next;
1273 SetHeightOfRow(tmprow);
1274 SetHeightOfRow(cursor.row); */
1275 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1278 RedoParagraphs(sel_start_cursor, endpar);
1281 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1282 sel_cursor = cursor;
1283 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1285 SetCursor(tmpcursor.par, tmpcursor.pos);
1289 void LyXText::SetParagraphExtraOpt(int type,
1292 int alignment, bool hfill,
1293 bool start_minipage)
1295 LyXCursor tmpcursor;
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* 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* layout = lyxstyle.Style(parameters->textclass,
1378 LyXTextClass *textclass = lyxstyle.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 && !(lyxstyle.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 && lyxstyle.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 && lyxstyle.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.clean();
1475 if (layout->margintype == MARGIN_MANUAL) {
1476 if (par->labelwidthstring.empty()) {
1477 par->SetLabelWidthString(layout->labelstring);
1481 par->SetLabelWidthString(LString());
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.clean();
1501 if (!layout->labelstring_appendix.empty())
1502 par->labelstring = layout->labelstring_appendix;
1504 par->labelstring.clean();
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 LString 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 && ( lyxstyle.Style(parameters->textclass, par->layout)->margintype == MARGIN_DYNAMIC
1727 || lyxstyle.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 = NULL;
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 = NULL;
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;
1811 /* Check whether there are half footnotes in the selection */
1812 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1813 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1814 tmppar = sel_start_cursor.par;
1815 while (tmppar != sel_end_cursor.par){
1816 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1817 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1820 tmppar = tmppar->Next();
1824 /* table stuff -- begin*/
1825 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1826 if ( sel_start_cursor.par != sel_end_cursor.par){
1827 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1830 sel_start_cursor.par->table->Reinit();
1832 /* table stuff -- end*/
1834 // make sure that the depth behind the selection are restored, too
1835 LyXParagraph *endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1836 LyXParagraph *undoendpar = endpar;
1838 if (endpar && endpar->GetDepth()) {
1839 while (endpar && endpar->GetDepth()) {
1840 endpar = endpar->LastPhysicalPar()->Next();
1841 undoendpar = endpar;
1845 endpar = endpar->Next(); /* because of parindents etc. */
1848 SetUndo(Undo::DELETE,
1849 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
1852 /* delete the simple_cut_buffer */
1853 DeleteSimpleCutBuffer();
1855 /* set the textclass */
1856 simple_cut_buffer_textclass = parameters->textclass;
1858 #ifdef WITH_WARNINGS
1859 #warning Asger: Make cut more intelligent here.
1862 White paper for "intelligent" cutting:
1864 Example: "This is our text."
1865 Using " our " as selection, cutting will give "This istext.".
1866 Using "our" as selection, cutting will give "This is text.".
1867 Using " our" as selection, cutting will give "This is text.".
1868 Using "our " as selection, cutting will give "This is text.".
1870 All those four selections will (however) paste identically:
1871 Pasting with the cursor right after the "is" will give the
1872 original text with all four selections.
1874 The rationale is to be intelligent such that words are copied,
1875 cut and pasted in a functional manner.
1877 This is not implemented yet.
1880 char space_wrapped =
1881 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1882 if (sel_end_cursor.pos > 0
1883 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1884 sel_end_cursor.pos--; /* please break before a space at
1886 space_wrapped = True;
1889 // cut behind a space if there is one
1890 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1891 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1892 && (sel_start_cursor.par != sel_end_cursor.par
1893 || sel_start_cursor.pos < sel_end_cursor.pos))
1894 sel_start_cursor.pos++;
1896 /* there are two cases: cut only within one paragraph or
1897 * more than one paragraph */
1899 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1900 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1901 /* only within one paragraph */
1902 simple_cut_buffer = new LyXParagraph();
1903 for (i=sel_start_cursor.pos; i< sel_end_cursor.pos; i++){
1904 /* table stuff -- begin*/
1905 if (sel_start_cursor.par->table
1906 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1907 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1908 sel_start_cursor.pos++;
1910 /* table stuff -- end*/
1911 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1912 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1914 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1916 /* check for double spaces */
1917 if (sel_start_cursor.pos &&
1918 sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1919 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1920 sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1921 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1924 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1925 endpar = sel_end_cursor.par->Next();
1928 /* cut more than one paragraph */
1930 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1931 /* insert a space at the end if there was one */
1933 sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1935 sel_end_cursor.par = sel_end_cursor.par->Next();
1936 sel_end_cursor.pos = 0;
1938 cursor = sel_end_cursor;
1940 /* please break behind a space, if there is one. The space should
1942 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1943 sel_start_cursor.pos++;
1945 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1946 if (!sel_start_cursor.pos
1947 || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1948 || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1949 sel_start_cursor.par->Next()->InsertChar(0, ' ');
1952 /* store the endparagraph for redoing later */
1953 endpar = sel_end_cursor.par->Next(); /* needed because
1958 /*store the selection */
1959 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1960 simple_cut_buffer->previous = NULL;
1961 sel_end_cursor.par->previous->next = NULL;
1963 /* cut the selection */
1964 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
1965 = sel_end_cursor.par;
1967 sel_end_cursor.par->previous
1968 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1970 /* care about footnotes */
1971 if (simple_cut_buffer->footnoteflag) {
1972 LyXParagraph *tmppar = simple_cut_buffer;
1974 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1975 tmppar = tmppar->next;
1979 /* the cut selection should begin with standard layout */
1980 simple_cut_buffer->Clear();
1982 /* paste the paragraphs again, if possible */
1984 sel_start_cursor.par->Next()->ClearParagraph();
1985 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1987 !sel_start_cursor.par->Next()->Last())
1988 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1991 /* maybe a forgotten blank */
1992 if (sel_start_cursor.pos
1993 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1994 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1995 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2000 /* sometimes necessary */
2002 sel_start_cursor.par->ClearParagraph();
2004 RedoParagraphs(sel_start_cursor, endpar);
2007 cursor = sel_start_cursor;
2008 SetCursor(cursor.par, cursor.pos);
2009 sel_cursor = cursor;
2010 UpdateCounters(cursor.row);
2014 void LyXText::CopySelection()
2018 /* this doesnt make sense, if there is no selection */
2023 /* ok we have a selection. This is always between sel_start_cursor
2024 * and sel_end cursor */
2025 LyXParagraph *tmppar;
2027 /* check wether there are half footnotes in the selection */
2028 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2029 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2030 tmppar = sel_start_cursor.par;
2031 while (tmppar != sel_end_cursor.par){
2032 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2033 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2036 tmppar = tmppar->Next();
2040 /* table stuff -- begin*/
2041 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2042 if ( sel_start_cursor.par != sel_end_cursor.par){
2043 WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2047 /* table stuff -- end*/
2049 /* delete the simple_cut_buffer */
2050 DeleteSimpleCutBuffer();
2052 /* set the textclass */
2053 simple_cut_buffer_textclass = parameters->textclass;
2055 // copy behind a space if there is one
2056 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2057 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2058 && (sel_start_cursor.par != sel_end_cursor.par
2059 || sel_start_cursor.pos < sel_end_cursor.pos))
2060 sel_start_cursor.pos++;
2062 /* there are two cases: copy only within one paragraph or more than one paragraph */
2063 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2064 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2065 /* only within one paragraph */
2066 simple_cut_buffer = new LyXParagraph();
2067 for (i=sel_start_cursor.pos; i< sel_end_cursor.pos; i++){
2068 sel_start_cursor.par->CopyIntoMinibuffer(i);
2069 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2073 /* copy more than one paragraph */
2074 /* clone the paragraphs within the selection*/
2075 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2076 simple_cut_buffer = tmppar->Clone();
2077 LyXParagraph *tmppar2 = simple_cut_buffer;
2079 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2081 tmppar = tmppar->next;
2082 tmppar2->next = tmppar->Clone();
2083 tmppar2->next->previous = tmppar2;
2084 tmppar2=tmppar2->next;
2086 tmppar2->next = NULL;
2088 /* care about footnotes */
2089 if (simple_cut_buffer->footnoteflag) {
2090 tmppar = simple_cut_buffer;
2092 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2093 tmppar = tmppar->next;
2097 /* the simple_cut_buffer paragraph is too big */
2100 tmpi2 = sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2101 for (;tmpi2;tmpi2--)
2102 simple_cut_buffer->Erase(0);
2104 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2106 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2107 while (tmppar2->last > tmpi2) {
2108 tmppar2->Erase(tmppar2->last-1);
2115 void LyXText::PasteSelection()
2117 /* this does not make sense, if there is nothing to paste */
2118 if (!simple_cut_buffer)
2121 LyXParagraph *tmppar;
2122 LyXParagraph *endpar;
2124 LyXCursor tmpcursor;
2126 /* be carefull with footnotes in footnotes */
2127 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2129 /* check whether the cut_buffer includes a footnote */
2130 tmppar = simple_cut_buffer;
2131 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2132 tmppar = tmppar->next;
2135 WriteAlert(_("Impossible operation"),
2136 _("Can't paste float into float!"), _("Sorry."));
2141 /* table stuff -- begin*/
2142 if (cursor.par->table){
2143 if (simple_cut_buffer->next){
2144 WriteAlert(_("Impossible operation"),
2145 _("Table cell cannot include more than one paragraph!"),
2150 /* table stuff -- end*/
2152 SetUndo(Undo::INSERT,
2153 cursor.par->ParFromPos(cursor.pos)->previous,
2154 cursor.par->ParFromPos(cursor.pos)->next);
2158 /* There are two cases: cutbuffer only one paragraph or many */
2159 if (!simple_cut_buffer->next) {
2160 /* only within a paragraph */
2162 /* please break behind a space, if there is one */
2163 while (tmpcursor.par->Last() > tmpcursor.pos
2164 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2167 tmppar = simple_cut_buffer->Clone();
2168 /* table stuff -- begin*/
2169 bool table_too_small = false;
2170 if (tmpcursor.par->table) {
2171 while (simple_cut_buffer->last && !table_too_small){
2172 if (simple_cut_buffer->IsNewline(0)){
2173 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2175 simple_cut_buffer->Erase(0);
2176 if (tmpcursor.pos < tmpcursor.par->Last())
2179 table_too_small = true;
2181 simple_cut_buffer->CutIntoMinibuffer(0);
2182 simple_cut_buffer->Erase(0);
2183 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2188 /* table stuff -- end*/
2189 while (simple_cut_buffer->last){
2190 simple_cut_buffer->CutIntoMinibuffer(0);
2191 simple_cut_buffer->Erase(0);
2192 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2197 delete simple_cut_buffer;
2198 simple_cut_buffer = tmppar;
2199 endpar = tmpcursor.par->Next();
2201 /* many paragraphs */
2203 /* make a copy of the simple cut_buffer */
2204 tmppar = simple_cut_buffer;
2205 LyXParagraph *simple_cut_clone = tmppar->Clone();
2206 LyXParagraph *tmppar2 = simple_cut_clone;
2207 if (cursor.par->footnoteflag){
2208 tmppar->footnoteflag = cursor.par->footnoteflag;
2209 tmppar->footnotekind = cursor.par->footnotekind;
2211 while (tmppar->next) {
2212 tmppar = tmppar->next;
2213 tmppar2->next = tmppar->Clone();
2214 tmppar2->next->previous = tmppar2;
2215 tmppar2=tmppar2->next;
2216 if (cursor.par->footnoteflag){
2217 tmppar->footnoteflag = cursor.par->footnoteflag;
2218 tmppar->footnotekind = cursor.par->footnotekind;
2222 /* make sure there is no class difference */
2223 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2224 parameters->textclass,
2227 /* make the simple_cut_buffer exactly the same layout than
2228 the cursor paragraph */
2229 simple_cut_buffer->MakeSameLayout(cursor.par);
2231 /* find the end of the buffer */
2232 LyXParagraph *lastbuffer = simple_cut_buffer;
2233 while (lastbuffer->Next())
2234 lastbuffer=lastbuffer->Next();
2236 /* find the physical end of the buffer */
2237 lastbuffer = simple_cut_buffer;
2238 while (lastbuffer->Next())
2239 lastbuffer=lastbuffer->Next();
2241 /* please break behind a space, if there is one. The space
2242 * should be copied too */
2243 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2246 bool paste_the_end = false;
2248 /* open the paragraph for inserting the simple_cut_buffer
2250 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2251 cursor.par->BreakParagraphConservative(cursor.pos);
2252 paste_the_end = true;
2255 /* be careful with double spaces */
2256 if ((!cursor.par->Last()
2257 || cursor.par->IsLineSeparator(cursor.pos - 1)
2258 || cursor.par->IsNewline(cursor.pos - 1))
2259 && simple_cut_buffer->last
2260 && simple_cut_buffer->IsLineSeparator(0))
2261 simple_cut_buffer->Erase(0);
2263 /* set the end for redoing later */
2264 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2267 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2268 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2270 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2271 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2273 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2274 lastbuffer = cursor.par;
2276 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2278 /* store the new cursor position */
2279 tmpcursor.par = lastbuffer;
2280 tmpcursor.pos = lastbuffer->Last();
2282 /* maybe some pasting */
2283 if (lastbuffer->Next() && paste_the_end) {
2284 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2286 /* be careful witth double spaces */
2287 if ((!lastbuffer->Last()
2288 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2289 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2290 && lastbuffer->Next()->Last()
2291 && lastbuffer->Next()->IsLineSeparator(0))
2292 lastbuffer->Next()->Erase(0);
2294 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2297 else if (!lastbuffer->Next()->Last()) {
2298 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2300 /* be careful witth double spaces */
2301 if ((!lastbuffer->Last()
2302 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2303 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2304 && lastbuffer->Next()->Last()
2305 && lastbuffer->Next()->IsLineSeparator(0))
2306 lastbuffer->Next()->Erase(0);
2308 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2311 else if (!lastbuffer->Last()) {
2312 lastbuffer->MakeSameLayout(lastbuffer->next);
2314 /* be careful witth double spaces */
2315 if ((!lastbuffer->Last()
2316 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2317 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2318 && lastbuffer->Next()->Last()
2319 && lastbuffer->Next()->IsLineSeparator(0))
2320 lastbuffer->Next()->Erase(0);
2322 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2325 else lastbuffer->Next()->ClearParagraph();
2328 /* restore the simple cut buffer */
2329 simple_cut_buffer = simple_cut_clone;
2332 RedoParagraphs(cursor, endpar);
2334 SetCursor(cursor.par, cursor.pos);
2337 sel_cursor = cursor;
2338 SetCursor(tmpcursor.par, tmpcursor.pos);
2340 UpdateCounters(cursor.row);
2344 /* returns a pointer to the very first LyXParagraph */
2345 LyXParagraph* LyXText::FirstParagraph()
2347 return params->paragraph;
2351 /* returns true if the specified string is at the specified position */
2352 bool LyXText::IsStringInText(LyXParagraph *par, int pos, char const* string)
2356 while (pos+i < par->Last() && string[i] &&
2357 string[i]==par->GetChar(pos+i))
2369 /* sets the selection over the number of characters of string, no check!! */
2370 void LyXText::SetSelectionOverString(char const* string)
2372 sel_cursor = cursor;
2374 for (i=0; string[i]; i++)
2380 /* simple replacing. The font of the first selected character is used */
2381 void LyXText::ReplaceSelectionWithString(char const* string)
2386 if (!selection) { /* create a dummy selection */
2387 sel_end_cursor = cursor;
2388 sel_start_cursor = cursor;
2391 // Get font setting before we cut
2392 int pos = sel_end_cursor.pos;
2393 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2395 // Insert the new string
2396 for (int i=0; string[i];i++) {
2397 sel_end_cursor.par->InsertChar(pos, string[i]);
2398 sel_end_cursor.par->SetFont(pos, font);
2402 // Cut the selection
2409 /* if the string can be found: return true and set the cursor to
2410 * the new position */
2411 bool LyXText::SearchForward(char const* string)
2413 LyXParagraph *par = cursor.par;
2414 int pos = cursor.pos;
2416 while (par && !IsStringInText(par,pos,string)) {
2417 if (pos<par->Last()-1)
2433 bool LyXText::SearchBackward(char const* string)
2435 LyXParagraph *par = cursor.par;
2436 int pos = cursor.pos;
2442 // We skip empty paragraphs (Asger)
2444 par = par->Previous();
2446 pos = par->Last()-1;
2447 } while (par && pos<0);
2449 } while (par && !IsStringInText(par,pos,string));
2460 /* needed to insert the selection */
2461 void LyXText::InsertStringA(char* string)
2463 LyXParagraph *par = cursor.par;
2464 int pos = cursor.pos;
2467 LyXParagraph *endpar = cursor.par->Next();
2471 char flag = lyxstyle.Style(parameters->textclass,
2472 cursor.par->GetLayout())->isEnvironment();
2473 /* only to be sure, should not be neccessary */
2476 /* insert the string, don't insert doublespace */
2480 for (i2=i;string[i2]&&string[i2]!='\n';i2++);
2481 par->Enlarge(pos, i2 - i);
2483 if (string[i]!='\n') {
2484 if (string[i]==' ' && (string[i+1]!=' ')
2485 && pos && par->GetChar(pos-1)!=' ') {
2486 par->InsertChar(pos,' ');
2489 else if (par->table) {
2490 if (string[i] == '\t') {
2491 while((pos < par->last) &&
2492 (par->GetChar(pos) != LYX_META_NEWLINE))
2494 if (pos < par->last)
2496 else // no more fields to fill skip the rest
2498 } else if ((string[i] != 13) &&
2499 (((unsigned char) string[i] & 127) >= ' ')) {
2500 par->InsertChar(pos,string[i]);
2504 else if (string[i]==' ') {
2505 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2508 else if (string[i]=='\t') {
2509 for (a=pos; a<(pos/8+1)*8 ; a++) {
2510 par->InsertChar(a,LYX_META_PROTECTED_SEPARATOR);
2514 else if (string[i]!=13 &&
2515 // Ignore unprintables
2516 ((unsigned char) string[i] & 127) >= ' ') {
2517 par->InsertChar(pos,string[i]);
2526 while((pos < par->last) &&
2527 (par->GetChar(pos) != LYX_META_NEWLINE))
2530 cell=NumberOfCell(par,pos);
2531 while((pos < par->last) &&
2532 !(par->table->IsFirstCell(cell))) {
2533 while((pos < par->last) &&
2534 (par->GetChar(pos) != LYX_META_NEWLINE))
2537 cell=NumberOfCell(par,pos);
2539 if (pos >= par->last)
2540 // no more fields to fill skip the rest
2544 par->InsertChar(pos,LYX_META_PROTECTED_SEPARATOR);
2547 par->BreakParagraph(pos, flag);
2551 for (i2=i;string[i2]&&string[i2]!='\n';i2++);
2552 par->Enlarge(pos, i2 - i);
2558 RedoParagraphs(cursor,endpar);
2559 SetCursor(cursor.par, cursor.pos);
2560 sel_cursor = cursor;
2561 SetCursor(par, pos);
2565 /* turns double-CR to single CR, others where converted into one blank and 13s
2566 * that are ignored .Double spaces are also converted into one. Spaces at
2567 * the beginning of a paragraph are forbidden. tabs are converted into one
2568 * space. then InsertStringA is called */
2569 void LyXText::InsertStringB(char* string)
2571 LyXParagraph *par = cursor.par;
2574 if (string[i]=='\t' && !par->table)
2576 if (string[i]==' ' && string[i+1]==' ')
2578 if (string[i]=='\n' && string[i+1] && !par->table){
2579 if (string[i+1]!='\n') {
2580 if (string[i-1]!=' ')
2585 while (string[i+1] && (string[i+1]==' '
2586 || string[i+1]=='\t'
2587 || string[i+1]=='\n'
2588 || string[i+1]==13)) {
2595 InsertStringA(string);
2599 bool LyXText::GotoNextError()
2601 LyXCursor res=cursor;
2603 if (res.pos < res.par->Last()-1) {
2607 res.par=res.par->Next();
2612 !(res.par->GetChar(res.pos)==LYX_META_INSET
2613 && res.par->GetInset(res.pos)->AutoDelete()));
2616 SetCursor(res.par, res.pos);
2624 bool LyXText::GotoNextNote()
2626 LyXCursor res=cursor;
2628 if (res.pos < res.par->Last()-1) {
2632 res.par=res.par->Next();
2637 !(res.par->GetChar(res.pos)==LYX_META_INSET
2638 && res.par->GetInset(res.pos)->LyxCode()==Inset::IGNORE_CODE));
2641 SetCursor(res.par, res.pos);
2649 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2652 InsetError * new_inset = NULL;
2654 if (!par || class1 == class2)
2656 par = par->FirstPhysicalPar();
2658 LString name = lyxstyle.NameOfLayout(class1, par->layout);
2659 int lay = lyxstyle.NumberOfLayout(class2, name);
2660 if (lay == -1) // layout not found
2661 // use default layout "Stadard" (0)
2665 if (name != lyxstyle.NameOfLayout(class2, par->layout)) {
2667 LString s= "Layout had to be changed from\n"
2668 + name + " to " + lyxstyle.NameOfLayout(class2, par->layout)
2669 + "\nbecause of class conversion from\n"
2670 + lyxstyle.NameOfClass(class1) + " to "
2671 + lyxstyle.NameOfClass(class2);
2672 new_inset = new InsetError(s);
2673 par->InsertChar(0, LYX_META_INSET);
2674 par->InsertInset(0, new_inset);
2683 void LyXText::CheckParagraph(LyXParagraph* par, int pos)
2686 LyXCursor tmpcursor;
2688 /* table stuff -- begin*/
2691 CheckParagraphInTable(par, pos);
2694 /* table stuff -- end*/
2699 Row* row = GetRow(par, pos, y);
2701 /* is there a break one row above */
2702 if (row->previous && row->previous->par == row->par) {
2703 z = NextBreakPoint(row->previous, paperwidth);
2704 if ( z >= row->pos) {
2705 /* set the dimensions of the row above */
2706 y -= row->previous->height;
2708 refresh_row = row->previous;
2709 status = LyXText::NEED_MORE_REFRESH;
2711 BreakAgain(row->previous);
2713 /* set the cursor again. Otherwise dungling pointers are possible */
2714 SetCursor(cursor.par, cursor.pos);
2715 sel_cursor = cursor;
2720 int tmpheight = row->height;
2721 int tmplast = RowLast(row);
2726 if (row->height == tmpheight && RowLast(row) == tmplast)
2727 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2729 status = LyXText::NEED_MORE_REFRESH;
2731 /* check the special right address boxes */
2732 if (lyxstyle.Style(parameters->textclass, par->GetLayout())->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2733 tmpcursor.par = par;
2734 tmpcursor.row = row;
2737 tmpcursor.x_fix = 0;
2738 tmpcursor.pos = pos;
2739 RedoDrawingOfParagraph(tmpcursor);
2744 /* set the cursor again. Otherwise dangling pointers are possible */
2745 // also set the selection
2749 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2750 sel_cursor = cursor;
2751 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2752 sel_start_cursor = cursor;
2753 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2754 sel_end_cursor = cursor;
2755 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2756 last_sel_cursor = cursor;
2759 SetCursorIntern(cursor.par, cursor.pos);
2763 /* returns 0 if inset wasn't found */
2764 int LyXText::UpdateInset(Inset* inset)
2769 /* first check the current paragraph */
2770 pos = cursor.par->GetPositionOfInset(inset);
2772 CheckParagraph(cursor.par, pos);
2776 /* check every paragraph */
2778 par = FirstParagraph();
2780 /* make sure the paragraph is open */
2781 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2782 pos = par->GetPositionOfInset(inset);
2784 CheckParagraph(par, pos);
2795 void LyXText::SetCursor(LyXParagraph *par, int pos)
2797 LyXCursor old_cursor = cursor;
2798 SetCursorIntern(par, pos);
2799 DeleteEmptyParagraphMechanism(old_cursor);
2803 void LyXText::SetCursorIntern(LyXParagraph *par, int pos)
2808 LyXParagraph *tmppar;
2810 /* correct the cursor position if impossible */
2811 if (pos > par->Last()){
2812 tmppar = par->ParFromPos(pos);
2813 pos = par->PositionInParFromPos(pos);
2816 if (par->IsDummy() && par->previous &&
2817 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2818 while (par->previous &&
2819 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
2820 par = par->previous ;
2822 if (par->previous) {
2823 par = par->previous;
2825 pos += par->last + 1;
2831 /* get the cursor y position in text */
2832 row = GetRow(par, pos, y);
2833 /* y is now the beginning of the cursor row */
2835 /* y is now the cursor baseline */
2838 /* now get the cursors x position */
2841 float fill_separator, fill_hfill, fill_label_hfill;
2842 left_margin = LabelEnd(row);
2843 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2844 int main_body = BeginningOfMainBody(row->par);
2846 /* table stuff -- begin*/
2847 if (row->par->table) {
2848 int cell = NumberOfCell(row->par, row->pos);
2850 x += row->par->table->GetBeginningOfTextInCell(cell);
2851 for (pos = row->pos; pos < cursor.pos; pos++) {
2852 if (row->par->IsNewline(pos)) {
2853 x = x_old + row->par->table->WidthOfColumn(cell);
2856 x += row->par->table->GetBeginningOfTextInCell(cell);
2858 x += SingleWidth(row->par, pos);
2862 /* table stuff -- end*/
2864 for (pos = row->pos; pos < cursor.pos; pos++) {
2865 if (pos && pos == main_body
2866 && !row->par->IsLineSeparator(pos - 1)) {
2867 x += GetFont(row->par, -2).stringWidth(
2868 lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2869 if (x < left_margin)
2873 x += SingleWidth(row->par, pos);
2874 if (HfillExpansion(row, pos)) {
2875 if (pos >= main_body)
2878 x += fill_label_hfill;
2880 else if (pos >= main_body && row->par->IsSeparator(pos)) {
2884 if (pos + 1 == main_body
2885 && row->par->IsLineSeparator(pos)) {
2886 x += GetFont(row->par, -2).stringWidth(
2887 lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2888 if (row->par->IsLineSeparator(pos))
2889 x-= SingleWidth(row->par, pos);
2890 if (x < left_margin)
2897 cursor.x_fix = cursor.x;
2901 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2902 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2903 && !cursor.par->IsSeparator(cursor.pos))
2905 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2906 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2908 current_font = cursor.par->GetFontSettings(cursor.pos);
2909 real_current_font = GetFont(cursor.par, cursor.pos);
2914 void LyXText::SetCursorFromCoordinates(int x, long y)
2919 LyXCursor old_cursor;
2921 old_cursor = cursor;
2923 /* get the row first */
2925 row = GetRowNearY(y);
2927 cursor.par = row->par;
2929 column = GetColumnNearX(row, x);
2930 cursor.pos = row->pos + column;
2932 cursor.y = y + row->baseline;
2937 (cursor.pos == cursor.par->Last()
2938 || cursor.par->IsSeparator(cursor.pos)
2939 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2940 && !cursor.par->IsSeparator(cursor.pos))
2942 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2943 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2945 current_font = cursor.par->GetFontSettings(cursor.pos);
2946 real_current_font = GetFont(cursor.par, cursor.pos);
2948 DeleteEmptyParagraphMechanism(old_cursor);
2952 void LyXText::CursorLeft()
2955 if (cursor.par->table) {
2956 int cell = NumberOfCell(cursor.par, cursor.pos);
2957 if (cursor.par->table->IsContRow(cell) &&
2958 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2965 void LyXText::CursorLeftIntern()
2967 if (cursor.pos > 0) {
2968 SetCursor(cursor.par, cursor.pos - 1);
2970 else if (cursor.par->Previous()) {
2971 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2976 void LyXText::CursorRight()
2978 CursorRightIntern();
2979 if (cursor.par->table) {
2980 int cell = NumberOfCell(cursor.par, cursor.pos);
2981 if (cursor.par->table->IsContRow(cell) &&
2982 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2989 void LyXText::CursorRightIntern()
2991 if (cursor.pos < cursor.par->Last()) {
2992 SetCursor(cursor.par, cursor.pos + 1);
2994 else if (cursor.par->Next()) {
2995 SetCursor(cursor.par->Next(), 0);
3000 void LyXText::CursorUp()
3002 SetCursorFromCoordinates(cursor.x_fix,
3003 cursor.y - cursor.row->baseline - 1);
3004 if (cursor.par->table) {
3005 int cell = NumberOfCell(cursor.par, cursor.pos);
3006 if (cursor.par->table->IsContRow(cell) &&
3007 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3014 void LyXText::CursorDown()
3016 if (cursor.par->table &&
3017 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3020 SetCursorFromCoordinates(cursor.x_fix,
3021 cursor.y - cursor.row->baseline
3022 + cursor.row->height + 1);
3023 if (cursor.par->table) {
3024 int cell = NumberOfCell(cursor.par, cursor.pos);
3025 int cell_above = cursor.par->table->GetCellAbove(cell);
3026 while(cursor.par->table &&
3027 cursor.par->table->IsContRow(cell) &&
3028 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3029 SetCursorFromCoordinates(cursor.x_fix,
3030 cursor.y - cursor.row->baseline
3031 + cursor.row->height + 1);
3032 if (cursor.par->table) {
3033 cell = NumberOfCell(cursor.par, cursor.pos);
3034 cell_above = cursor.par->table->GetCellAbove(cell);
3041 void LyXText::CursorUpParagraph()
3043 if (cursor.pos > 0) {
3044 SetCursor(cursor.par, 0);
3046 else if (cursor.par->Previous()) {
3047 SetCursor(cursor.par->Previous(), 0);
3052 void LyXText::CursorDownParagraph()
3054 if (cursor.par->Next()) {
3055 SetCursor(cursor.par->Next(), 0);
3057 SetCursor(cursor.par,cursor.par->Last());
3063 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3065 bool deleted = false;
3067 /* this is the delete-empty-paragraph-mechanism. */
3071 // Paragraph should not be deleted if empty
3072 if ((lyxstyle.Style(parameters->textclass,
3073 old_cursor.par->GetLayout()))->keepempty)
3076 LyXCursor tmpcursor;
3078 if (old_cursor.par != cursor.par) {
3079 if ( (old_cursor.par->Last() == 0
3080 || (old_cursor.par->Last() == 1
3081 && (old_cursor.par->IsLineSeparator(0))))
3082 && old_cursor.par->FirstPhysicalPar()
3083 == old_cursor.par->LastPhysicalPar()
3085 // impossible to insert your own \caption with
3086 // this set. made it impossible to use the
3087 // optional argument...
3088 // also empty pars in fig or tab never was removed(?)(Lgb)
3089 //lyxstyle.Style(parameters->textclass,
3090 // old_cursor.par->GetLayout())->labeltype!=LABEL_SENSITIVE ||
3091 // (old_cursor.par->footnoteflag == LyXParagraph::NO_FOOTNOTE
3092 //|| (old_cursor.par->footnotekind != LyXParagraph::FIG
3093 // && old_cursor.par->footnotekind != LyXParagraph::TAB)))
3096 /* ok, we will delete anything */
3098 // make sure that you do not delete any environments
3099 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3100 !(old_cursor.row->previous
3101 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3102 && !(old_cursor.row->next
3103 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3105 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3106 ((old_cursor.row->previous
3107 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3109 (old_cursor.row->next
3110 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3112 status = LyXText::NEED_MORE_REFRESH;
3115 if (old_cursor.row->previous) {
3116 refresh_row = old_cursor.row->previous;
3117 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3119 cursor = old_cursor; // that undo can restore the right cursor position
3120 LyXParagraph *endpar = old_cursor.par->next;
3121 if (endpar && endpar->GetDepth()) {
3122 while (endpar && endpar->GetDepth()) {
3123 endpar = endpar->LastPhysicalPar()->Next();
3126 SetUndo(Undo::DELETE,
3127 old_cursor.par->previous,
3131 /* delete old row */
3132 RemoveRow(old_cursor.row);
3133 if (params->paragraph == old_cursor.par) {
3134 params->paragraph = params->paragraph->next;
3136 /* delete old par */
3137 delete old_cursor.par;
3139 /* Breakagain the next par. Needed
3140 * because of the parindent that
3141 * can occur or dissappear. The
3142 * next row can change its height,
3143 * if there is another layout before */
3144 if (refresh_row->next) {
3145 BreakAgain(refresh_row->next);
3146 UpdateCounters(refresh_row);
3148 SetHeightOfRow(refresh_row);
3151 refresh_row = old_cursor.row->next;
3152 refresh_y = old_cursor.y - old_cursor.row->baseline;
3155 cursor = old_cursor; // that undo can restore the right cursor position
3156 LyXParagraph *endpar = old_cursor.par->next;
3157 if (endpar && endpar->GetDepth()) {
3158 while (endpar && endpar->GetDepth()) {
3159 endpar = endpar->LastPhysicalPar()->Next();
3162 SetUndo(Undo::DELETE,
3163 old_cursor.par->previous,
3167 /* delete old row */
3168 RemoveRow(old_cursor.row);
3169 /* delete old par */
3170 if (params->paragraph == old_cursor.par) {
3171 params->paragraph = params->paragraph->next;
3173 delete old_cursor.par;
3175 /* Breakagain the next par. Needed because of
3176 * the parindent that can occur or dissappear.
3177 * The next row can change its height, if there
3178 * is another layout before */
3180 BreakAgain(refresh_row);
3181 UpdateCounters(refresh_row->previous);
3185 /* correct cursor y */
3186 SetCursor(cursor.par, cursor.pos);
3188 /* if (cursor.y > old_cursor.y)
3189 cursor.y -= old_cursor.row->height; */
3191 if (sel_cursor.par == old_cursor.par
3192 && sel_cursor.pos == sel_cursor.pos) {
3193 /* correct selection*/
3194 sel_cursor = cursor;
3200 if (old_cursor.par->ClearParagraph()){
3201 RedoParagraphs(old_cursor, old_cursor.par->Next());
3202 /* correct cursor y */
3203 SetCursor(cursor.par, cursor.pos);
3204 sel_cursor = cursor;
3207 } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3208 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3209 if (old_cursor.par->table->IsContRow(cell) &&
3210 IsEmptyTableRow(&old_cursor)) {
3211 RemoveTableRow(&old_cursor);
3218 LyXParagraph* LyXText::GetParFromID(int id)
3220 LyXParagraph* result = FirstParagraph();
3221 while (result && result->GetID() != id)
3222 result = result->next;
3228 bool LyXText::TextUndo()
3229 { // returns false if no undo possible
3230 Undo *undo = params->undostack.Pop();
3234 params->redostack.Push(CreateUndo(undo->kind,
3235 GetParFromID(undo->number_of_before_par),
3236 GetParFromID(undo->number_of_behind_par)));
3238 return TextHandleUndo(undo);
3242 bool LyXText::TextRedo()
3243 { // returns false if no redo possible
3244 Undo *undo = params->redostack.Pop();
3248 params->undostack.Push(CreateUndo(undo->kind,
3249 GetParFromID(undo->number_of_before_par),
3250 GetParFromID(undo->number_of_behind_par)));
3252 return TextHandleUndo(undo);
3256 bool LyXText::TextHandleUndo(Undo* undo){ // returns false if no undo possible
3257 bool result = false;
3259 LyXParagraph* before = GetParFromID(undo->number_of_before_par);
3260 LyXParagraph* behind = GetParFromID(undo->number_of_behind_par);
3261 LyXParagraph* tmppar;
3262 LyXParagraph* tmppar2;
3263 LyXParagraph* tmppar3;
3264 LyXParagraph* tmppar4;
3265 LyXParagraph* endpar;
3266 LyXParagraph* tmppar5;
3270 before->text[before->last] = 0;
3271 printf("before: %s\n", before->text);
3274 behind->text[behind->last] = 0;
3275 printf("behind: %s\n", behind->text);
3279 // if there's no before take the beginning of the document for redoing
3281 SetCursorIntern(FirstParagraph(), 0);
3283 // replace the paragraphs with the undo informations
3285 tmppar3 = undo->par;
3286 undo->par = NULL; // otherwise the undo destructor would delete the paragraph
3289 while (tmppar4->next)
3290 tmppar4 = tmppar4->next;
3291 } // get last undo par
3293 // now remove the old text if there is any
3294 if (before != behind || (!behind && !before)){
3296 tmppar5 = before->next;
3298 tmppar5 = params->paragraph;
3300 while (tmppar5 && tmppar5 != behind){
3302 tmppar5 = tmppar5->next;
3303 // a memory optimization for edit: Only layout information
3304 // is stored in the undo. So restore the text informations.
3305 if (undo->kind == Undo::EDIT){
3306 tmppar2->text = tmppar->text;
3307 tmppar->text = NULL;
3308 tmppar2 = tmppar2->next;
3310 if ( currentrow && currentrow->par == tmppar )
3311 currentrow = currentrow -> previous;
3316 // put the new stuff in the list if there is one
3319 before->next = tmppar3;
3321 params->paragraph = tmppar3;
3322 tmppar3->previous = before;
3326 params->paragraph = behind;
3329 tmppar4->next = behind;
3331 behind->previous = tmppar4;
3335 // Set the cursor for redoing
3337 SetCursorIntern(before->FirstSelfrowPar(), 0);
3338 // check wether before points to a closed float and open it if necessary
3339 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3340 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3342 while (tmppar4->previous &&
3343 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3344 tmppar4 = tmppar4->previous;
3345 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3346 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3347 tmppar4 = tmppar4->next;
3352 // open a cosed footnote at the end if necessary
3353 if (behind && behind->previous &&
3354 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3355 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3356 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3357 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3358 behind = behind->next;
3362 // calculate the endpar for redoing the paragraphs.
3364 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3365 endpar = behind->LastPhysicalPar()->Next();
3367 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3372 tmppar = GetParFromID(undo->number_of_cursor_par);
3373 RedoParagraphs(cursor, endpar);
3375 SetCursorIntern(tmppar, undo->cursor_pos);
3376 UpdateCounters(cursor.row);
3386 void LyXText::FinishUndo()
3387 { // makes sure the next operation will be stored
3388 undo_finished = True;
3392 void LyXText::FreezeUndo()
3393 { // this is dangerous and for internal use only
3398 void LyXText::UnFreezeUndo()
3399 { // this is dangerous and for internal use only
3400 undo_frozen = false;
3404 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3407 params->undostack.Push(CreateUndo(kind, before, behind));
3408 params->redostack.Clear();
3412 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3414 params->redostack.Push(CreateUndo(kind, before, behind));
3418 Undo* LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph *before,
3419 LyXParagraph *behind)
3421 int before_number = -1;
3422 int behind_number = -1;
3424 before_number = before->GetID();
3426 behind_number = behind->GetID();
3427 // Undo::EDIT and Undo::FINISH are
3428 // always finished. (no overlapping there)
3429 // overlapping only with insert and delete inside one paragraph:
3430 // Nobody wants all removed character
3431 // appear one by one when undoing.
3432 // EDIT is special since only layout information, not the
3433 // contents of a paragaph are stored.
3434 if (!undo_finished && kind != Undo::EDIT &&
3435 kind != Undo::FINISH){
3436 // check wether storing is needed
3437 if (params->undostack.Top() &&
3438 params->undostack.Top()->kind == kind &&
3439 params->undostack.Top()->number_of_before_par == before_number &&
3440 params->undostack.Top()->number_of_behind_par == behind_number ){
3445 // create a new Undo
3446 LyXParagraph* undopar;
3447 LyXParagraph* tmppar;
3448 LyXParagraph *tmppar2;
3450 LyXParagraph* start = NULL;
3451 LyXParagraph* end = NULL;
3454 start = before->next;
3456 start = FirstParagraph();
3458 end = behind->previous;
3460 end = FirstParagraph();
3465 if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3467 tmppar2 = tmppar->Clone();
3468 tmppar2->SetID(tmppar->GetID());
3470 // a memory optimization: Just store the layout information when only edit
3471 if (kind == Undo::EDIT){
3473 delete[] tmppar2->text;
3474 tmppar2->text = NULL;
3479 while (tmppar != end && tmppar->next) {
3480 tmppar = tmppar->next;
3481 tmppar2->next = tmppar->Clone();
3482 tmppar2->next->SetID(tmppar->GetID());
3483 // a memory optimization: Just store the layout information when only edit
3484 if (kind == Undo::EDIT){
3485 if (tmppar2->next->text)
3486 delete[] tmppar2->next->text;
3487 tmppar2->next->text = NULL;
3489 tmppar2->next->previous = tmppar2;
3490 tmppar2=tmppar2->next;
3492 tmppar2->next = NULL;
3495 undopar = NULL; // nothing to replace (undo of delete maybe)
3497 int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3498 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3500 Undo* undo = new Undo(kind,
3501 before_number, behind_number,
3502 cursor_par, cursor_pos,
3505 undo_finished = false;
3510 void LyXText::SetCursorParUndo()
3512 SetUndo(Undo::FINISH,
3513 cursor.par->ParFromPos(cursor.pos)->previous,
3514 cursor.par->ParFromPos(cursor.pos)->next);
3517 void LyXText::RemoveTableRow(LyXCursor *cursor)
3525 /* move to the previous row */
3526 cell_act = NumberOfCell(cursor->par, cursor->pos);
3529 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3531 while (cursor->pos &&
3532 !cursor->par->table->IsFirstCell(cell_act)){
3534 while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3539 /* now we have to pay attention if the actual table is the
3540 main row of TableContRows and if yes to delete all of them */
3545 /* delete up to the next row */
3546 while (cursor->pos < cursor->par->Last() &&
3548 || !cursor->par->table->IsFirstCell(cell_act))){
3549 while (cursor->pos < cursor->par->Last() &&
3550 !cursor->par->IsNewline(cursor->pos))
3551 cursor->par->Erase(cursor->pos);
3554 if (cursor->pos < cursor->par->Last())
3555 cursor->par-> Erase(cursor->pos);
3557 if (cursor->pos && cursor->pos == cursor->par->Last()){
3559 cursor->par->Erase(cursor->pos); // no newline at the very end!
3561 } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3562 !cursor->par->table->IsContRow(cell_org) &&
3563 cursor->par->table->IsContRow(cell));
3564 cursor->par->table->DeleteRow(cell_org);
3568 bool LyXText::IsEmptyTableRow(LyXCursor *old_cursor)
3570 if (!old_cursor->par->table)
3572 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3574 pos = old_cursor->pos,
3575 cell = NumberOfCell(old_cursor->par, pos);
3577 // search first charater of this table row
3578 while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3580 while (pos && !old_cursor->par->IsNewline(pos-1))
3584 if (!old_cursor->par->IsNewline(pos))
3588 while ((pos < old_cursor->par->Last()) &&
3589 !old_cursor->par->table->IsFirstCell(cell)) {
3590 if (!old_cursor->par->IsNewline(pos))
3601 bool LyXText::IsEmptyTableCell()
3603 int pos = cursor.pos - 1;
3605 while ((pos>=0) && (pos < cursor.par->Last()) &&
3606 !cursor.par->IsNewline(pos))
3608 return cursor.par->IsNewline(pos+1);
3611 void LyXText::toggleAppendix(){
3612 LyXParagraph* par = cursor.par->FirstPhysicalPar();
3613 bool start = !par->start_of_appendix;
3615 /* ensure that we have only one start_of_appendix in this document */
3616 LyXParagraph* tmp = FirstParagraph();
3617 for (;tmp;tmp=tmp->next)
3618 tmp->start_of_appendix = 0;
3619 par->start_of_appendix = start;
3621 /* we can set the refreshing parameters now */
3622 status = LyXText::NEED_MORE_REFRESH;
3624 refresh_row = 0; // not needed for full update
3626 SetCursor(cursor.par, cursor.pos);