1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
28 #include "support/textutils.h"
30 #include "minibuffer.h"
32 #include "bufferparams.h"
33 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
39 #include "CutAndPaste.h"
45 //#define USE_OLD_CUT_AND_PASTE 1
51 LyXText::LyXText(BufferView * bv)
59 LyXText::LyXText(InsetText * inset)
76 status = LyXText::UNCHANGED;
77 // set cursor at the very top position
78 selection = true; /* these setting is necessary
79 because of the delete-empty-
80 paragraph mechanism in
83 LyXParagraph * par = OwnerParagraph();
84 current_font = GetFont(bv_owner->buffer(), par, 0);
86 InsertParagraph(bv_owner, par, lastrow);
89 SetCursor(bv_owner, firstrow->par(), 0);
91 current_font = LyXFont(LyXFont::ALL_SANE);
97 // no rebreak necessary
100 undo_finished = true;
103 // Default layouttype for copy environment type
107 // Dump all rowinformation:
108 Row * tmprow = firstrow;
109 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
111 lyxerr << tmprow->baseline() << '\t'
112 << tmprow->par << '\t'
113 << tmprow->pos() << '\t'
114 << tmprow->height << '\t'
115 << tmprow->ascent_of_text << '\t'
116 << tmprow->fill << '\n';
117 tmprow = tmprow->next();
124 void LyXText::init(BufferView * bview)
129 LyXParagraph * par = OwnerParagraph();
130 current_font = GetFont(bview->buffer(), par, 0);
132 InsertParagraph(bview, par, lastrow);
135 SetCursorIntern(bview, firstrow->par(), 0);
138 // Dump all rowinformation:
139 Row * tmprow = firstrow;
140 lyxerr << "Width = " << width << endl;
141 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
143 lyxerr << tmprow->baseline() << '\t'
144 << tmprow->par() << '\t'
145 << tmprow->pos() << '\t'
146 << tmprow->height() << '\t'
147 << tmprow->ascent_of_text() << '\t'
148 << tmprow->fill() << '\n';
149 tmprow = tmprow->next();
157 // Delete all rows, this does not touch the paragraphs!
158 Row * tmprow = firstrow;
160 tmprow = firstrow->next();
167 // Gets the fully instantiated font at a given position in a paragraph
168 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
169 // The difference is that this one is used for displaying, and thus we
170 // are allowed to make cosmetic improvements. For instance make footnotes
172 // If position is -1, we get the layout font of the paragraph.
173 // If position is -2, we get the font of the manual label of the paragraph.
174 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
175 LyXParagraph::size_type pos) const
177 LyXLayout const & layout =
178 textclasslist.Style(buf->params.textclass, par->GetLayout());
180 char par_depth = par->GetDepth();
181 // We specialize the 95% common case:
182 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
185 if (layout.labeltype == LABEL_MANUAL
186 && pos < BeginningOfMainBody(buf, par)) {
188 return par->GetFontSettings(buf->params, pos).
189 realize(layout.reslabelfont);
191 return par->GetFontSettings(buf->params, pos).
192 realize(layout.resfont);
195 // process layoutfont for pos == -1 and labelfont for pos < -1
197 return layout.resfont;
199 return layout.reslabelfont;
203 // The uncommon case need not be optimized as much
205 LyXFont layoutfont, tmpfont;
209 if (pos < BeginningOfMainBody(buf, par)) {
211 layoutfont = layout.labelfont;
214 layoutfont = layout.font;
216 tmpfont = par->GetFontSettings(buf->params, pos);
217 tmpfont.realize(layoutfont);
220 // process layoutfont for pos == -1 and labelfont for pos < -1
222 tmpfont = layout.font;
224 tmpfont = layout.labelfont;
227 // Resolve against environment font information
228 while (par && par_depth && !tmpfont.resolved()) {
229 par = par->DepthHook(par_depth - 1);
231 tmpfont.realize(textclasslist.
232 Style(buf->params.textclass,
233 par->GetLayout()).font);
234 par_depth = par->GetDepth();
238 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
241 // Cosmetic improvement: If this is an open footnote, make the font
243 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
244 && par->footnotekind == LyXParagraph::FOOTNOTE) {
252 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
253 LyXParagraph::size_type pos,
257 // Let the insets convert their font
258 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
259 if (par->GetInset(pos))
260 font = par->GetInset(pos)->ConvertFont(font);
263 LyXLayout const & layout =
264 textclasslist.Style(buf->params.textclass,
267 // Get concrete layout font to reduce against
270 if (pos < BeginningOfMainBody(buf, par))
271 layoutfont = layout.labelfont;
273 layoutfont = layout.font;
275 // Realize against environment font information
276 if (par->GetDepth()){
277 LyXParagraph * tp = par;
278 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
279 tp = tp->DepthHook(tp->GetDepth()-1);
281 layoutfont.realize(textclasslist.
282 Style(buf->params.textclass,
283 tp->GetLayout()).font);
287 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
290 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
291 && par->footnotekind == LyXParagraph::FOOTNOTE) {
292 layoutfont.decSize();
295 // Now, reduce font against full layout font
296 font.reduce(layoutfont);
298 par->SetFont(pos, font);
302 /* inserts a new row behind the specified row, increments
303 * the touched counters */
304 void LyXText::InsertRow(Row * row, LyXParagraph * par,
305 LyXParagraph::size_type pos) const
307 Row * tmprow = new Row;
310 tmprow->next(firstrow);
313 tmprow->previous(row);
314 tmprow->next(row->next());
319 tmprow->next()->previous(tmprow);
321 if (tmprow->previous())
322 tmprow->previous()->next(tmprow);
330 ++number_of_rows; // one more row
334 // removes the row and reset the touched counters
335 void LyXText::RemoveRow(Row * row) const
337 /* this must not happen before the currentrow for clear reasons.
338 so the trick is just to set the current row onto the previous
341 GetRow(row->par(), row->pos(), unused_y);
344 row->next()->previous(row->previous());
345 if (!row->previous()) {
346 firstrow = row->next();
348 row->previous()->next(row->next());
351 lastrow = row->previous();
353 height -= row->height(); // the text becomes smaller
356 --number_of_rows; // one row less
360 // remove all following rows of the paragraph of the specified row.
361 void LyXText::RemoveParagraph(Row * row) const
363 LyXParagraph * tmppar = row->par();
367 while (row && row->par() == tmppar) {
368 tmprow = row->next();
375 // insert the specified paragraph behind the specified row
376 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
379 InsertRow(row, par, 0); /* insert a new row, starting
382 SetCounter(bview->buffer(), par); // set the counters
384 // and now append the whole paragraph behind the new row
387 AppendParagraph(bview, firstrow);
389 row->next()->height(0);
390 AppendParagraph(bview, row->next());
396 void LyXText::ToggleFootnote(BufferView * bview)
398 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
400 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
402 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
404 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
405 CloseFootnote(bview);
411 void LyXText::OpenStuff(BufferView * bview)
413 if (cursor.pos() == 0 && cursor.par()->bibkey){
414 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
416 else if (cursor.pos() < cursor.par()->Last()
417 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
418 && cursor.par()->GetInset(cursor.pos())->Editable()) {
419 bview->owner()->getMiniBuffer()
420 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
421 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
422 SetCursorParUndo(bview->buffer());
423 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
425 ToggleFootnote(bview);
431 void LyXText::CloseFootnote(BufferView * bview)
433 LyXParagraph * tmppar;
434 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
436 // if the cursor is not in an open footnote, or
437 // there is no open footnote in this paragraph, just return.
438 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
441 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
442 bview->owner()->getMiniBuffer()
443 ->Set(_("Nothing to do"));
447 // ok, move the cursor right before the footnote
448 // just a little faster than using CursorRight()
450 cursor.par()->ParFromPos(cursor.pos()) != par;) {
451 cursor.pos(cursor.pos() + 1);
454 // now the cursor is at the beginning of the physical par
455 SetCursor(bview, cursor.par(),
457 cursor.par()->ParFromPos(cursor.pos())->size());
459 /* we are in a footnote, so let us move at the beginning */
460 /* this is just faster than using just CursorLeft() */
462 tmppar = cursor.par();
463 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
464 // just a little bit faster than movin the cursor
465 tmppar = tmppar->Previous();
467 SetCursor(bview, tmppar, tmppar->Last());
470 // the cursor must be exactly before the footnote
471 par = cursor.par()->ParFromPos(cursor.pos());
473 status = LyXText::NEED_MORE_REFRESH;
474 refresh_row = cursor.row();
475 refresh_y = cursor.y() - cursor.row()->baseline();
477 tmppar = cursor.par();
478 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
479 Row * row = cursor.row();
481 tmppar->CloseFootnote(cursor.pos());
483 while (tmppar != endpar) {
484 RemoveRow(row->next());
486 tmppar = row->next()->par();
491 AppendParagraph(bview, cursor.row());
493 SetCursor(bview, cursor.par(), cursor.pos());
497 if (cursor.row()->next())
498 SetHeightOfRow(bview, cursor.row()->next());
503 /* used in setlayout */
504 // Asger is not sure we want to do this...
505 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
509 LyXLayout const & layout =
510 textclasslist.Style(buf->params.textclass, par->GetLayout());
512 LyXFont layoutfont, tmpfont;
513 for (LyXParagraph::size_type pos = 0;
514 pos < par->Last(); ++pos) {
515 if (pos < BeginningOfMainBody(buf, par))
516 layoutfont = layout.labelfont;
518 layoutfont = layout.font;
520 tmpfont = par->GetFontSettings(buf->params, pos);
521 tmpfont.reduce(layoutfont);
522 par->SetFont(pos, tmpfont);
527 LyXParagraph * LyXText::SetLayout(BufferView * bview,
528 LyXCursor & cur, LyXCursor & sstart_cur,
529 LyXCursor & send_cur,
530 LyXTextClass::size_type layout)
532 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
533 LyXParagraph * undoendpar = endpar;
535 if (endpar && endpar->GetDepth()) {
536 while (endpar && endpar->GetDepth()) {
537 endpar = endpar->LastPhysicalPar()->Next();
541 endpar = endpar->Next(); // because of parindents etc.
544 SetUndo(bview->buffer(), Undo::EDIT,
545 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
548 /* ok we have a selection. This is always between sstart_cur
549 * and sel_end cursor */
552 LyXLayout const & lyxlayout =
553 textclasslist.Style(bview->buffer()->params.textclass, layout);
555 while (cur.par() != send_cur.par()) {
556 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
557 cur.par()->SetLayout(bview->buffer()->params, layout);
558 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
559 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
560 fppar->added_space_top = lyxlayout.fill_top ?
561 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
562 fppar->added_space_bottom = lyxlayout.fill_bottom ?
563 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
564 if (lyxlayout.margintype == MARGIN_MANUAL)
565 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
566 if (lyxlayout.labeltype != LABEL_BIBLIO
568 delete fppar->bibkey;
572 cur.par(cur.par()->Next());
574 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
575 cur.par()->SetLayout(bview->buffer()->params, layout);
576 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
577 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
578 fppar->added_space_top = lyxlayout.fill_top ?
579 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
580 fppar->added_space_bottom = lyxlayout.fill_bottom ?
581 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
582 if (lyxlayout.margintype == MARGIN_MANUAL)
583 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
584 if (lyxlayout.labeltype != LABEL_BIBLIO
586 delete fppar->bibkey;
593 // set layout over selection and make a total rebreak of those paragraphs
594 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
597 tmpcursor = cursor; /* store the current cursor */
599 #ifdef USE_OLD_SET_LAYOUT
600 // if there is no selection just set the layout
601 // of the current paragraph */
603 sel_start_cursor = cursor; // dummy selection
604 sel_end_cursor = cursor;
607 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
608 LyXParagraph * undoendpar = endpar;
610 if (endpar && endpar->GetDepth()) {
611 while (endpar && endpar->GetDepth()) {
612 endpar = endpar->LastPhysicalPar()->Next();
617 endpar = endpar->Next(); // because of parindents etc.
621 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
624 /* ok we have a selection. This is always between sel_start_cursor
625 * and sel_end cursor */
626 cursor = sel_start_cursor;
628 LyXLayout const & lyxlayout =
629 textclasslist.Style(bview->buffer()->params.textclass, layout);
631 while (cursor.par() != sel_end_cursor.par()) {
632 if (cursor.par()->footnoteflag ==
633 sel_start_cursor.par()->footnoteflag) {
634 cursor.par()->SetLayout(layout);
635 MakeFontEntriesLayoutSpecific(cursor.par());
636 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
637 fppar->added_space_top = lyxlayout.fill_top ?
638 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
639 fppar->added_space_bottom = lyxlayout.fill_bottom ?
640 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
641 if (lyxlayout.margintype == MARGIN_MANUAL)
642 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
643 if (lyxlayout.labeltype != LABEL_BIBLIO
645 delete fppar->bibkey;
649 cursor.par() = cursor.par()->Next();
651 if (cursor.par()->footnoteflag ==
652 sel_start_cursor.par()->footnoteflag) {
653 cursor.par()->SetLayout(layout);
654 MakeFontEntriesLayoutSpecific(cursor.par());
655 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
656 fppar->added_space_top = lyxlayout.fill_top ?
657 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
658 fppar->added_space_bottom = lyxlayout.fill_bottom ?
659 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
660 if (lyxlayout.margintype == MARGIN_MANUAL)
661 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
662 if (lyxlayout.labeltype != LABEL_BIBLIO
664 delete fppar->bibkey;
669 // if there is no selection just set the layout
670 // of the current paragraph */
672 sel_start_cursor = cursor; // dummy selection
673 sel_end_cursor = cursor;
676 endpar = SetLayout(bview, cursor, sel_start_cursor,
677 sel_end_cursor, layout);
679 RedoParagraphs(bview, sel_start_cursor, endpar);
681 // we have to reset the selection, because the
682 // geometry could have changed */
683 SetCursor(bview, sel_start_cursor.par(),
684 sel_start_cursor.pos(), false);
686 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
688 UpdateCounters(bview, cursor.row());
691 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
695 // increment depth over selection and
696 // make a total rebreak of those paragraphs
697 void LyXText::IncDepth(BufferView * bview)
699 // If there is no selection, just use the current paragraph
701 sel_start_cursor = cursor; // dummy selection
702 sel_end_cursor = cursor;
705 // We end at the next paragraph with depth 0
706 LyXParagraph * endpar =
707 sel_end_cursor.par()->LastPhysicalPar()->Next();
708 LyXParagraph * undoendpar = endpar;
710 if (endpar && endpar->GetDepth()) {
711 while (endpar && endpar->GetDepth()) {
712 endpar = endpar->LastPhysicalPar()->Next();
717 endpar = endpar->Next(); // because of parindents etc.
720 SetUndo(bview->buffer(), Undo::EDIT,
722 .par()->ParFromPos(sel_start_cursor.pos())->previous,
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
729 cursor = sel_start_cursor;
731 bool anything_changed = false;
734 // NOTE: you can't change the depth of a bibliography entry
735 if (cursor.par()->footnoteflag ==
736 sel_start_cursor.par()->footnoteflag
737 && textclasslist.Style(bview->buffer()->params.textclass,
738 cursor.par()->GetLayout()
739 ).labeltype != LABEL_BIBLIO) {
740 LyXParagraph * prev =
741 cursor.par()->FirstPhysicalPar()->Previous();
743 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
744 || (prev->GetDepth() == cursor.par()->GetDepth()
745 && textclasslist.Style(bview->buffer()->params.textclass,
746 prev->GetLayout()).isEnvironment()))) {
747 cursor.par()->FirstPhysicalPar()->depth++;
748 anything_changed = true;
751 if (cursor.par() == sel_end_cursor.par())
753 cursor.par(cursor.par()->Next());
756 // if nothing changed set all depth to 0
757 if (!anything_changed) {
758 cursor = sel_start_cursor;
759 while (cursor.par() != sel_end_cursor.par()) {
760 cursor.par()->FirstPhysicalPar()->depth = 0;
761 cursor.par(cursor.par()->Next());
763 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
764 cursor.par()->FirstPhysicalPar()->depth = 0;
767 RedoParagraphs(bview, sel_start_cursor, endpar);
769 // we have to reset the selection, because the
770 // geometry could have changed
771 SetCursor(bview, sel_start_cursor.par(),
772 sel_start_cursor.pos());
774 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
775 UpdateCounters(bview, cursor.row());
778 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
782 // decrement depth over selection and
783 // make a total rebreak of those paragraphs
784 void LyXText::DecDepth(BufferView * bview)
786 // if there is no selection just set the layout
787 // of the current paragraph
789 sel_start_cursor = cursor; // dummy selection
790 sel_end_cursor = cursor;
793 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
794 LyXParagraph * undoendpar = endpar;
796 if (endpar && endpar->GetDepth()) {
797 while (endpar && endpar->GetDepth()) {
798 endpar = endpar->LastPhysicalPar()->Next();
803 endpar = endpar->Next(); // because of parindents etc.
806 SetUndo(bview->buffer(), Undo::EDIT,
808 .par()->ParFromPos(sel_start_cursor.pos())->previous,
811 LyXCursor tmpcursor = cursor; // store the current cursor
813 // ok we have a selection. This is always between sel_start_cursor
814 // and sel_end cursor
815 cursor = sel_start_cursor;
818 if (cursor.par()->footnoteflag ==
819 sel_start_cursor.par()->footnoteflag) {
820 if (cursor.par()->FirstPhysicalPar()->depth)
821 cursor.par()->FirstPhysicalPar()->depth--;
823 if (cursor.par() == sel_end_cursor.par())
825 cursor.par(cursor.par()->Next());
828 RedoParagraphs(bview, sel_start_cursor, endpar);
830 // we have to reset the selection, because the
831 // geometry could have changed
832 SetCursor(bview, sel_start_cursor.par(),
833 sel_start_cursor.pos());
835 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
836 UpdateCounters(bview, cursor.row());
839 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
843 // set font over selection and make a total rebreak of those paragraphs
844 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
846 // if there is no selection just set the current_font
848 // Determine basis font
850 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
852 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
854 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
855 // Update current font
856 real_current_font.update(font,
857 bview->buffer()->params.language_info,
860 // Reduce to implicit settings
861 current_font = real_current_font;
862 current_font.reduce(layoutfont);
863 // And resolve it completely
864 real_current_font.realize(layoutfont);
868 LyXCursor tmpcursor = cursor; // store the current cursor
870 // ok we have a selection. This is always between sel_start_cursor
871 // and sel_end cursor
873 SetUndo(bview->buffer(), Undo::EDIT,
874 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
875 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
876 cursor = sel_start_cursor;
877 while (cursor.par() != sel_end_cursor.par() ||
878 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
879 && cursor.pos() < sel_end_cursor.pos()))
881 if (cursor.pos() < cursor.par()->Last()
882 && cursor.par()->footnoteflag
883 == sel_start_cursor.par()->footnoteflag) {
884 // an open footnote should behave
886 LyXFont newfont = GetFont(bview->buffer(),
887 cursor.par(), cursor.pos());
889 bview->buffer()->params.language_info,
891 SetCharFont(bview->buffer(),
892 cursor.par(), cursor.pos(), newfont);
893 cursor.pos(cursor.pos() + 1);
896 cursor.par(cursor.par()->Next());
900 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
902 // we have to reset the selection, because the
903 // geometry could have changed
904 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
906 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
909 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
910 tmpcursor.boundary());
914 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
916 Row * tmprow = cur.row();
917 long y = cur.y() - tmprow->baseline();
919 SetHeightOfRow(bview, tmprow);
920 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
921 // find the first row of the paragraph
922 if (first_phys_par != tmprow->par())
923 while (tmprow->previous()
924 && tmprow->previous()->par() != first_phys_par) {
925 tmprow = tmprow->previous();
926 y -= tmprow->height();
927 SetHeightOfRow(bview, tmprow);
929 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
930 tmprow = tmprow->previous();
931 y -= tmprow->height();
932 SetHeightOfRow(bview, tmprow);
935 // we can set the refreshing parameters now
936 status = LyXText::NEED_MORE_REFRESH;
938 refresh_row = tmprow;
939 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
943 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
945 Row * tmprow = cur.row();
947 long y = cur.y() - tmprow->baseline();
948 SetHeightOfRow(bview, tmprow);
949 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
950 // find the first row of the paragraph
951 if (first_phys_par != tmprow->par())
952 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
953 tmprow = tmprow->previous();
954 y -= tmprow->height();
956 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
957 tmprow = tmprow->previous();
958 y -= tmprow->height();
961 // we can set the refreshing parameters now
962 if (status == LyXText::UNCHANGED || y < refresh_y) {
964 refresh_row = tmprow;
966 status = LyXText::NEED_MORE_REFRESH;
967 SetCursor(bview, cur.par(), cur.pos());
971 /* deletes and inserts again all paragaphs between the cursor
972 * and the specified par
973 * This function is needed after SetLayout and SetFont etc. */
974 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
975 LyXParagraph const * endpar) const
978 LyXParagraph * tmppar = 0, * first_phys_par = 0;
980 Row * tmprow = cur.row();
982 long y = cur.y() - tmprow->baseline();
984 if (!tmprow->previous()){
985 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
987 first_phys_par = tmprow->par()->FirstPhysicalPar();
988 // find the first row of the paragraph
989 if (first_phys_par != tmprow->par())
990 while (tmprow->previous() &&
991 (tmprow->previous()->par() != first_phys_par)) {
992 tmprow = tmprow->previous();
993 y -= tmprow->height();
995 while (tmprow->previous()
996 && tmprow->previous()->par() == first_phys_par) {
997 tmprow = tmprow->previous();
998 y -= tmprow->height();
1002 // we can set the refreshing parameters now
1003 status = LyXText::NEED_MORE_REFRESH;
1005 refresh_row = tmprow->previous(); /* the real refresh row will
1006 be deleted, so I store
1007 the previous here */
1010 tmppar = tmprow->next()->par();
1013 while (tmppar != endpar) {
1014 RemoveRow(tmprow->next());
1016 tmppar = tmprow->next()->par();
1021 // remove the first one
1022 tmprow2 = tmprow; /* this is because tmprow->previous()
1024 tmprow = tmprow->previous();
1027 tmppar = first_phys_par;
1031 InsertParagraph(bview, tmppar, tmprow);
1034 while (tmprow->next() && tmprow->next()->par() == tmppar)
1035 tmprow = tmprow->next();
1036 tmppar = tmppar->Next();
1038 } while (tmppar != endpar);
1040 // this is because of layout changes
1042 refresh_y -= refresh_row->height();
1043 SetHeightOfRow(bview, refresh_row);
1045 refresh_row = firstrow;
1047 SetHeightOfRow(bview, refresh_row);
1050 if (tmprow && tmprow->next())
1051 SetHeightOfRow(bview, tmprow->next());
1055 bool LyXText::FullRebreak(BufferView * bview)
1061 if (need_break_row) {
1062 BreakAgain(bview, need_break_row);
1070 /* important for the screen */
1073 /* the cursor set functions have a special mechanism. When they
1074 * realize, that you left an empty paragraph, they will delete it.
1075 * They also delete the corresponding row */
1077 // need the selection cursor:
1078 void LyXText::SetSelection()
1081 last_sel_cursor = sel_cursor;
1082 sel_start_cursor = sel_cursor;
1083 sel_end_cursor = sel_cursor;
1088 // first the toggling area
1089 if (cursor.y() < last_sel_cursor.y()
1090 || (cursor.y() == last_sel_cursor.y()
1091 && cursor.x() < last_sel_cursor.x())) {
1092 toggle_end_cursor = last_sel_cursor;
1093 toggle_cursor = cursor;
1095 toggle_end_cursor = cursor;
1096 toggle_cursor = last_sel_cursor;
1099 last_sel_cursor = cursor;
1101 // and now the whole selection
1103 if (sel_cursor.par() == cursor.par())
1104 if (sel_cursor.pos() < cursor.pos()) {
1105 sel_end_cursor = cursor;
1106 sel_start_cursor = sel_cursor;
1108 sel_end_cursor = sel_cursor;
1109 sel_start_cursor = cursor;
1111 else if (sel_cursor.y() < cursor.y() ||
1112 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1113 sel_end_cursor = cursor;
1114 sel_start_cursor = sel_cursor;
1117 sel_end_cursor = sel_cursor;
1118 sel_start_cursor = cursor;
1121 // a selection with no contents is not a selection
1122 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1123 sel_start_cursor.pos() == sel_end_cursor.pos())
1128 string LyXText::selectionAsString(Buffer const * buffer) const
1130 if (!selection) return string();
1133 // Special handling if the whole selection is within one paragraph
1134 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1135 result += sel_start_cursor.par()->String(buffer,
1136 sel_start_cursor.pos(),
1137 sel_end_cursor.pos());
1141 // The selection spans more than one paragraph
1143 // First paragraph in selection
1144 result += sel_start_cursor.par()->String(buffer,
1145 sel_start_cursor.pos(),
1146 sel_start_cursor.par()->Last())
1149 // The paragraphs in between (if any)
1150 LyXCursor tmpcur(sel_start_cursor);
1151 tmpcur.par(tmpcur.par()->Next());
1152 while (tmpcur.par() != sel_end_cursor.par()) {
1153 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1154 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1157 // Last paragraph in selection
1158 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1164 void LyXText::ClearSelection() const
1171 void LyXText::CursorHome(BufferView * bview) const
1173 SetCursor(bview, cursor.par(), cursor.row()->pos());
1177 void LyXText::CursorEnd(BufferView * bview) const
1179 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1180 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1182 if (cursor.par()->Last() &&
1183 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1184 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1185 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1187 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1190 if (cursor.par()->table) {
1191 int cell = NumberOfCell(cursor.par(), cursor.pos());
1192 if (cursor.par()->table->RowHasContRow(cell) &&
1193 cursor.par()->table->CellHasContRow(cell)<0) {
1194 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1195 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1197 if (cursor.par()->Last() &&
1198 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1199 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1200 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1202 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1210 void LyXText::CursorTop(BufferView * bview) const
1212 while (cursor.par()->Previous())
1213 cursor.par(cursor.par()->Previous());
1214 SetCursor(bview, cursor.par(), 0);
1218 void LyXText::CursorBottom(BufferView * bview) const
1220 while (cursor.par()->Next())
1221 cursor.par(cursor.par()->Next());
1222 SetCursor(bview, cursor.par(), cursor.par()->Last());
1226 /* returns a pointer to the row near the specified y-coordinate
1227 * (relative to the whole text). y is set to the real beginning
1229 Row * LyXText::GetRowNearY(long & y) const
1231 Row * tmprow = firstrow;
1234 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1235 tmpy += tmprow->height();
1236 tmprow = tmprow->next();
1239 y = tmpy; // return the real y
1244 void LyXText::ToggleFree(BufferView * bview,
1245 LyXFont const & font, bool toggleall)
1247 // If the mask is completely neutral, tell user
1248 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1249 // Could only happen with user style
1250 bview->owner()->getMiniBuffer()
1251 ->Set(_("No font change defined. Use Character under"
1252 " the Layout menu to define font change."));
1256 // Try implicit word selection
1257 // If there is a change in the language the implicit word selection
1259 LyXCursor resetCursor = cursor;
1260 bool implicitSelection = (font.language() == ignore_language)
1261 ? SelectWordWhenUnderCursor(bview) : false;
1264 SetFont(bview, font, toggleall);
1266 /* Implicit selections are cleared afterwards and cursor is set to the
1267 original position. */
1268 if (implicitSelection) {
1270 cursor = resetCursor;
1271 SetCursor(bview, cursor.par(), cursor.pos());
1272 sel_cursor = cursor;
1277 LyXParagraph::size_type
1278 LyXText::BeginningOfMainBody(Buffer const * buf,
1279 LyXParagraph const * par) const
1281 if (textclasslist.Style(buf->params.textclass,
1282 par->GetLayout()).labeltype != LABEL_MANUAL)
1285 return par->BeginningOfMainBody();
1290 /* if there is a selection, reset every environment you can find
1291 * in the selection, otherwise just the environment you are in */
1292 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1294 LyXParagraph * tmppar, * firsttmppar;
1298 /* is is only allowed, if the cursor is IN an open footnote.
1299 * Otherwise it is too dangerous */
1300 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1303 SetUndo(bview->buffer(), Undo::FINISH,
1304 cursor.par()->PreviousBeforeFootnote()->previous,
1305 cursor.par()->NextAfterFootnote()->next);
1307 /* ok, move to the beginning of the footnote. */
1308 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1309 cursor.par(cursor.par()->Previous());
1311 SetCursor(bview, cursor.par(), cursor.par()->Last());
1312 /* this is just faster than using CursorLeft(); */
1314 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1315 tmppar = firsttmppar;
1316 /* tmppar is now the paragraph right before the footnote */
1318 bool first_footnote_par_is_not_empty = tmppar->next->size();
1321 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1322 tmppar = tmppar->next; /* I use next instead of Next(),
1323 * because there cannot be any
1324 * footnotes in a footnote
1326 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1328 /* remember the captions and empty paragraphs */
1329 if ((textclasslist.Style(bview->buffer()->params.textclass,
1330 tmppar->GetLayout())
1331 .labeltype == LABEL_SENSITIVE)
1333 tmppar->SetLayout(bview->buffer()->params, 0);
1336 // now we will paste the ex-footnote, if the layouts allow it
1337 // first restore the layout of the paragraph right behind
1340 tmppar->next->MakeSameLayout(cursor.par());
1343 if ((!tmppar->GetLayout() && !tmppar->table)
1345 && (!tmppar->Next()->Last()
1346 || tmppar->Next()->HasSameLayout(tmppar)))) {
1347 if (tmppar->Next()->Last()
1348 && tmppar->Next()->IsLineSeparator(0))
1349 tmppar->Next()->Erase(0);
1350 tmppar->PasteParagraph(bview->buffer()->params);
1353 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1354 * by the pasting of the beginning */
1356 /* then the beginning */
1357 /* if there is no space between the text and the footnote, so we insert
1359 * (only if the previous par and the footnotepar are not empty!) */
1360 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1361 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1362 if (firsttmppar->size()
1363 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1364 && first_footnote_par_is_not_empty) {
1365 firsttmppar->next->InsertChar(0, ' ');
1367 firsttmppar->PasteParagraph(bview->buffer()->params);
1370 /* now redo the paragaphs */
1371 RedoParagraphs(bview, cursor, tmppar);
1373 SetCursor(bview, cursor.par(), cursor.pos());
1375 /* sometimes it can happen, that there is a counter change */
1376 Row * row = cursor.row();
1377 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1379 UpdateCounters(bview, row);
1387 /* the DTP switches for paragraphs. LyX will store them in the
1388 * first physicla paragraph. When a paragraph is broken, the top settings
1389 * rest, the bottom settings are given to the new one. So I can make shure,
1390 * they do not duplicate themself and you cannnot make dirty things with
1393 void LyXText::SetParagraph(BufferView * bview,
1394 bool line_top, bool line_bottom,
1395 bool pagebreak_top, bool pagebreak_bottom,
1396 VSpace const & space_top,
1397 VSpace const & space_bottom,
1399 string labelwidthstring,
1402 LyXCursor tmpcursor = cursor;
1404 sel_start_cursor = cursor;
1405 sel_end_cursor = cursor;
1408 // make sure that the depth behind the selection are restored, too
1409 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1410 LyXParagraph * undoendpar = endpar;
1412 if (endpar && endpar->GetDepth()) {
1413 while (endpar && endpar->GetDepth()) {
1414 endpar = endpar->LastPhysicalPar()->Next();
1415 undoendpar = endpar;
1419 endpar = endpar->Next(); // because of parindents etc.
1422 SetUndo(bview->buffer(), Undo::EDIT,
1424 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1428 LyXParagraph * tmppar = sel_end_cursor.par();
1429 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1430 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1431 status = LyXText::NEED_MORE_REFRESH;
1432 refresh_row = cursor.row();
1433 refresh_y = cursor.y() - cursor.row()->baseline();
1434 if (cursor.par()->footnoteflag ==
1435 sel_start_cursor.par()->footnoteflag) {
1436 cursor.par()->line_top = line_top;
1437 cursor.par()->line_bottom = line_bottom;
1438 cursor.par()->pagebreak_top = pagebreak_top;
1439 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1440 cursor.par()->added_space_top = space_top;
1441 cursor.par()->added_space_bottom = space_bottom;
1442 // does the layout allow the new alignment?
1443 if (align == LYX_ALIGN_LAYOUT)
1444 align = textclasslist
1445 .Style(bview->buffer()->params.textclass,
1446 cursor.par()->GetLayout()).align;
1447 if (align & textclasslist
1448 .Style(bview->buffer()->params.textclass,
1449 cursor.par()->GetLayout()).alignpossible) {
1450 if (align == textclasslist
1451 .Style(bview->buffer()->params.textclass,
1452 cursor.par()->GetLayout()).align)
1453 cursor.par()->align = LYX_ALIGN_LAYOUT;
1455 cursor.par()->align = align;
1457 cursor.par()->SetLabelWidthString(labelwidthstring);
1458 cursor.par()->noindent = noindent;
1461 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1464 RedoParagraphs(bview, sel_start_cursor, endpar);
1467 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1468 sel_cursor = cursor;
1469 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1471 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1475 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1477 char const * widthp,
1478 int alignment, bool hfill,
1479 bool start_minipage)
1481 LyXCursor tmpcursor = cursor;
1482 LyXParagraph * tmppar;
1484 sel_start_cursor = cursor;
1485 sel_end_cursor = cursor;
1488 // make sure that the depth behind the selection are restored, too
1489 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1490 LyXParagraph * undoendpar = endpar;
1492 if (endpar && endpar->GetDepth()) {
1493 while (endpar && endpar->GetDepth()) {
1494 endpar = endpar->LastPhysicalPar()->Next();
1495 undoendpar = endpar;
1499 endpar = endpar->Next(); // because of parindents etc.
1502 SetUndo(bview->buffer(), Undo::EDIT,
1504 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1507 tmppar = sel_end_cursor.par();
1508 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1509 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1510 status = LyXText::NEED_MORE_REFRESH;
1511 refresh_row = cursor.row();
1512 refresh_y = cursor.y() - cursor.row()->baseline();
1513 if (cursor.par()->footnoteflag ==
1514 sel_start_cursor.par()->footnoteflag) {
1515 if (type == LyXParagraph::PEXTRA_NONE) {
1516 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1517 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1518 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1521 cursor.par()->SetPExtraType(bview->buffer()->params,
1522 type, width, widthp);
1523 cursor.par()->pextra_hfill = hfill;
1524 cursor.par()->pextra_start_minipage = start_minipage;
1525 cursor.par()->pextra_alignment = alignment;
1528 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1530 RedoParagraphs(bview, sel_start_cursor, endpar);
1532 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1533 sel_cursor = cursor;
1534 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1536 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1540 char loweralphaCounter(int n)
1542 if (n < 1 || n > 26)
1548 char alphaCounter(int n)
1550 if (n < 1 || n > 26)
1556 char hebrewCounter(int n)
1558 static const char hebrew[22] = {
1559 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1560 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1561 '÷', 'ø', 'ù', 'ú'
1563 if (n < 1 || n > 22)
1569 static char const * romanCounter(int n)
1571 static char const * roman[20] = {
1572 "i", "ii", "iii", "iv", "v",
1573 "vi", "vii", "viii", "ix", "x",
1574 "xi", "xii", "xiii", "xiv", "xv",
1575 "xvi", "xvii", "xviii", "xix", "xx"
1577 if (n < 1 || n > 20)
1583 // set the counter of a paragraph. This includes the labels
1584 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1586 // this is only relevant for the beginning of paragraph
1587 par = par->FirstPhysicalPar();
1589 LyXLayout const & layout =
1590 textclasslist.Style(buf->params.textclass,
1593 LyXTextClass const & textclass =
1594 textclasslist.TextClass(buf->params.textclass);
1596 /* copy the prev-counters to this one, unless this is the start of a
1597 footnote or of a bibliography or the very first paragraph */
1599 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1600 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1601 && par->footnotekind == LyXParagraph::FOOTNOTE)
1602 && !(textclasslist.Style(buf->params.textclass,
1603 par->Previous()->GetLayout()
1604 ).labeltype != LABEL_BIBLIO
1605 && layout.labeltype == LABEL_BIBLIO)) {
1606 for (int i = 0; i < 10; ++i) {
1607 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1609 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1610 if (!par->appendix && par->start_of_appendix){
1611 par->appendix = true;
1612 for (int i = 0; i < 10; ++i) {
1613 par->setCounter(i, 0);
1616 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1617 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1620 for (int i = 0; i < 10; ++i) {
1621 par->setCounter(i, 0);
1623 par->appendix = par->start_of_appendix;
1629 // if this is an open marginnote and this is the first
1630 // entry in the marginnote and the enclosing
1631 // environment is an enum/item then correct for the
1632 // LaTeX behaviour (ARRae)
1633 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1634 && par->footnotekind == LyXParagraph::MARGIN
1636 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1637 && (par->PreviousBeforeFootnote()
1638 && textclasslist.Style(buf->params.textclass,
1639 par->PreviousBeforeFootnote()->GetLayout()
1640 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1641 // Any itemize or enumerate environment in a marginnote
1642 // that is embedded in an itemize or enumerate
1643 // paragraph is seen by LaTeX as being at a deeper
1644 // level within that enclosing itemization/enumeration
1645 // even if there is a "standard" layout at the start of
1651 /* Maybe we have to increment the enumeration depth.
1652 * BUT, enumeration in a footnote is considered in isolation from its
1653 * surrounding paragraph so don't increment if this is the
1654 * first line of the footnote
1655 * AND, bibliographies can't have their depth changed ie. they
1656 * are always of depth 0
1659 && par->Previous()->GetDepth() < par->GetDepth()
1660 && textclasslist.Style(buf->params.textclass,
1661 par->Previous()->GetLayout()
1662 ).labeltype == LABEL_COUNTER_ENUMI
1663 && par->enumdepth < 3
1664 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1665 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1666 && par->footnotekind == LyXParagraph::FOOTNOTE)
1667 && layout.labeltype != LABEL_BIBLIO) {
1671 /* Maybe we have to decrement the enumeration depth, see note above */
1673 && par->Previous()->GetDepth() > par->GetDepth()
1674 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1675 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1676 && par->footnotekind == LyXParagraph::FOOTNOTE)
1677 && layout.labeltype != LABEL_BIBLIO) {
1678 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1679 par->setCounter(6 + par->enumdepth,
1680 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1681 /* reset the counters.
1682 * A depth change is like a breaking layout
1684 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1685 par->setCounter(i, 0);
1688 if (!par->labelstring.empty()) {
1689 par->labelstring.erase();
1692 if (layout.margintype == MARGIN_MANUAL) {
1693 if (par->labelwidthstring.empty()) {
1694 par->SetLabelWidthString(layout.labelstring());
1697 par->SetLabelWidthString(string());
1700 /* is it a layout that has an automatic label ? */
1701 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1703 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1704 if (i >= 0 && i<= buf->params.secnumdepth) {
1705 par->incCounter(i); // increment the counter
1707 // Is there a label? Useful for Chapter layout
1708 if (!par->appendix){
1709 if (!layout.labelstring().empty())
1710 par->labelstring = layout.labelstring();
1712 par->labelstring.erase();
1714 if (!layout.labelstring_appendix().empty())
1715 par->labelstring = layout.labelstring_appendix();
1717 par->labelstring.erase();
1721 std::ostringstream s;
1725 if (!par->appendix) {
1726 switch (2 * LABEL_COUNTER_CHAPTER -
1727 textclass.maxcounter() + i) {
1728 case LABEL_COUNTER_CHAPTER:
1729 s << par->getCounter(i);
1731 case LABEL_COUNTER_SECTION:
1732 s << par->getCounter(i - 1) << '.'
1733 << par->getCounter(i);
1735 case LABEL_COUNTER_SUBSECTION:
1736 s << par->getCounter(i - 2) << '.'
1737 << par->getCounter(i - 1) << '.'
1738 << par->getCounter(i);
1740 case LABEL_COUNTER_SUBSUBSECTION:
1741 s << par->getCounter(i - 3) << '.'
1742 << par->getCounter(i - 2) << '.'
1743 << par->getCounter(i - 1) << '.'
1744 << par->getCounter(i);
1747 case LABEL_COUNTER_PARAGRAPH:
1748 s << par->getCounter(i - 4) << '.'
1749 << par->getCounter(i - 3) << '.'
1750 << par->getCounter(i - 2) << '.'
1751 << par->getCounter(i - 1) << '.'
1752 << par->getCounter(i);
1754 case LABEL_COUNTER_SUBPARAGRAPH:
1755 s << par->getCounter(i - 5) << '.'
1756 << par->getCounter(i - 4) << '.'
1757 << par->getCounter(i - 3) << '.'
1758 << par->getCounter(i - 2) << '.'
1759 << par->getCounter(i - 1) << '.'
1760 << par->getCounter(i);
1764 // Can this ever be reached? And in the
1765 // case it is, how can this be correct?
1767 s << par->getCounter(i) << '.';
1770 } else { // appendix
1771 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1772 case LABEL_COUNTER_CHAPTER:
1773 if (par->isRightToLeftPar(buf->params))
1774 s << hebrewCounter(par->getCounter(i));
1776 s << alphaCounter(par->getCounter(i));
1778 case LABEL_COUNTER_SECTION:
1779 if (par->isRightToLeftPar(buf->params))
1780 s << hebrewCounter(par->getCounter(i - 1));
1782 s << alphaCounter(par->getCounter(i - 1));
1785 << par->getCounter(i);
1788 case LABEL_COUNTER_SUBSECTION:
1789 if (par->isRightToLeftPar(buf->params))
1790 s << hebrewCounter(par->getCounter(i - 2));
1792 s << alphaCounter(par->getCounter(i - 2));
1795 << par->getCounter(i-1) << '.'
1796 << par->getCounter(i);
1799 case LABEL_COUNTER_SUBSUBSECTION:
1800 if (par->isRightToLeftPar(buf->params))
1801 s << hebrewCounter(par->getCounter(i-3));
1803 s << alphaCounter(par->getCounter(i-3));
1806 << par->getCounter(i-2) << '.'
1807 << par->getCounter(i-1) << '.'
1808 << par->getCounter(i);
1811 case LABEL_COUNTER_PARAGRAPH:
1812 if (par->isRightToLeftPar(buf->params))
1813 s << hebrewCounter(par->getCounter(i-4));
1815 s << alphaCounter(par->getCounter(i-4));
1818 << par->getCounter(i-3) << '.'
1819 << par->getCounter(i-2) << '.'
1820 << par->getCounter(i-1) << '.'
1821 << par->getCounter(i);
1824 case LABEL_COUNTER_SUBPARAGRAPH:
1825 if (par->isRightToLeftPar(buf->params))
1826 s << hebrewCounter(par->getCounter(i-5));
1828 s << alphaCounter(par->getCounter(i-5));
1831 << par->getCounter(i-4) << '.'
1832 << par->getCounter(i-3) << '.'
1833 << par->getCounter(i-2) << '.'
1834 << par->getCounter(i-1) << '.'
1835 << par->getCounter(i);
1839 // Can this ever be reached? And in the
1840 // case it is, how can this be correct?
1842 s << par->getCounter(i) << '.';
1848 par->labelstring += s.str().c_str();
1849 // We really want to remove the c_str as soon as
1853 char * tmps = s.str();
1854 par->labelstring += tmps;
1858 for (i++; i < 10; ++i) {
1859 // reset the following counters
1860 par->setCounter(i, 0);
1862 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1863 for (i++; i < 10; ++i) {
1864 // reset the following counters
1865 par->setCounter(i, 0);
1867 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1868 par->incCounter(i + par->enumdepth);
1869 int number = par->getCounter(i + par->enumdepth);
1872 std::ostringstream s;
1876 switch (par->enumdepth) {
1878 if (par->isRightToLeftPar(buf->params))
1880 << hebrewCounter(number)
1884 << loweralphaCounter(number)
1888 if (par->isRightToLeftPar(buf->params))
1889 s << '.' << romanCounter(number);
1891 s << romanCounter(number) << '.';
1894 if (par->isRightToLeftPar(buf->params))
1896 << alphaCounter(number);
1898 s << alphaCounter(number)
1902 if (par->isRightToLeftPar(buf->params))
1909 par->labelstring = s.str().c_str();
1910 // we really want to get rid of that c_str()
1913 char * tmps = s.str();
1914 par->labelstring = tmps;
1918 for (i += par->enumdepth + 1; i < 10; ++i)
1919 par->setCounter(i, 0); /* reset the following counters */
1922 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1923 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1925 int number = par->getCounter(i);
1927 par->bibkey = new InsetBibKey();
1928 par->bibkey->setCounter(number);
1929 par->labelstring = layout.labelstring();
1931 // In biblio should't be following counters but...
1933 string s = layout.labelstring();
1935 // the caption hack:
1936 if (layout.labeltype == LABEL_SENSITIVE) {
1937 bool isOK = (par->InInset() && par->InInset()->owner() &&
1938 (par->InInset()->owner()->LyxCode()==Inset::FLOAT_CODE));
1939 if ((isOK && (par->InInset()->owner()->getInsetName() == "figure")) ||
1940 (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1941 && (par->footnotekind == LyXParagraph::FIG
1942 || par->footnotekind == LyXParagraph::WIDE_FIG)))
1943 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1944 ? ":øåéà " : "Figure:";
1945 else if ((isOK && (par->InInset()->owner()->getInsetName() == "table")) ||
1946 (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1947 && (par->footnotekind == LyXParagraph::TAB
1948 || par->footnotekind == LyXParagraph::WIDE_TAB)))
1949 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1950 ? ":äìáè" : "Table:";
1951 else if ((isOK && (par->InInset()->owner()->getInsetName() == "algorithm")) ||
1952 (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1953 && par->footnotekind == LyXParagraph::ALGORITHM))
1954 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1955 ? ":Ãúéøåâìà " : "Algorithm:";
1957 /* par->SetLayout(0);
1958 s = layout->labelstring; */
1959 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1960 ? " :úåòîùî øñç" : "Senseless: ";
1963 par->labelstring = s;
1965 /* reset the enumeration counter. They are always resetted
1966 * when there is any other layout between */
1967 for (int i = 6 + par->enumdepth; i < 10; ++i)
1968 par->setCounter(i, 0);
1973 /* Updates all counters BEHIND the row. Changed paragraphs
1974 * with a dynamic left margin will be rebroken. */
1975 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1983 if (row->par()->next
1984 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1985 par = row->par()->LastPhysicalPar()->Next();
1987 par = row->par()->next;
1992 while (row->par() != par)
1995 SetCounter(bview->buffer(), par);
1997 /* now check for the headline layouts. remember that they
1998 * have a dynamic left margin */
2000 && ( textclasslist.Style(bview->buffer()->params.textclass,
2001 par->layout).margintype == MARGIN_DYNAMIC
2002 || textclasslist.Style(bview->buffer()->params.textclass,
2003 par->layout).labeltype == LABEL_SENSITIVE)
2006 /* Rebreak the paragraph */
2007 RemoveParagraph(row);
2008 AppendParagraph(bview, row);
2011 /* think about the damned open footnotes! */
2012 while (par->Next() &&
2013 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2014 || par->Next()->IsDummy())){
2016 if (par->IsDummy()) {
2017 while (row->par() != par)
2019 RemoveParagraph(row);
2020 AppendParagraph(bview, row);
2026 par = par->LastPhysicalPar()->Next();
2032 /* insets an inset. */
2033 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2035 if (!cursor.par()->InsertInsetAllowed(inset))
2037 SetUndo(bview->buffer(), Undo::INSERT,
2038 cursor.par()->ParFromPos(cursor.pos())->previous,
2039 cursor.par()->ParFromPos(cursor.pos())->next);
2040 cursor.par()->InsertInset(cursor.pos(), inset);
2041 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2042 * The character will not be inserted a
2047 void LyXText::copyEnvironmentType()
2049 copylayouttype = cursor.par()->GetLayout();
2053 void LyXText::pasteEnvironmentType(BufferView * bview)
2055 SetLayout(bview, copylayouttype);
2059 void LyXText::CutSelection(BufferView * bview, bool doclear)
2061 // Stuff what we got on the clipboard. Even if there is no selection.
2063 // There is a problem with having the stuffing here in that the
2064 // larger the selection the slower LyX will get. This can be
2065 // solved by running the line below only when the selection has
2066 // finished. The solution used currently just works, to make it
2067 // faster we need to be more clever and probably also have more
2068 // calls to stuffClipboard. (Lgb)
2069 bview->stuffClipboard(selectionAsString(bview->buffer()));
2071 // This doesn't make sense, if there is no selection
2075 // OK, we have a selection. This is always between sel_start_cursor
2076 // and sel_end cursor
2077 LyXParagraph * tmppar;
2080 // Check whether there are half footnotes in the selection
2081 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2082 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2083 tmppar = sel_start_cursor.par();
2084 while (tmppar != sel_end_cursor.par()){
2085 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2086 WriteAlert(_("Impossible operation"),
2087 _("Don't know what to do with half floats."),
2091 tmppar = tmppar->Next();
2096 /* table stuff -- begin */
2097 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2098 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2099 WriteAlert(_("Impossible operation"),
2100 _("Don't know what to do with half tables."),
2104 sel_start_cursor.par()->table->Reinit();
2106 /* table stuff -- end */
2108 // make sure that the depth behind the selection are restored, too
2109 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2110 LyXParagraph * undoendpar = endpar;
2112 if (endpar && endpar->GetDepth()) {
2113 while (endpar && endpar->GetDepth()) {
2114 endpar = endpar->LastPhysicalPar()->Next();
2115 undoendpar = endpar;
2117 } else if (endpar) {
2118 endpar = endpar->Next(); // because of parindents etc.
2121 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2122 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2126 // there are two cases: cut only within one paragraph or
2127 // more than one paragraph
2128 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2129 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2130 // only within one paragraph
2131 endpar = sel_start_cursor.par();
2132 int pos = sel_end_cursor.pos();
2133 cap.cutSelection(sel_start_cursor.par(), &endpar,
2134 sel_start_cursor.pos(), pos,
2135 bview->buffer()->params.textclass, doclear);
2136 sel_end_cursor.pos(pos);
2138 endpar = sel_end_cursor.par();
2140 int pos = sel_end_cursor.pos();
2141 cap.cutSelection(sel_start_cursor.par(), &endpar,
2142 sel_start_cursor.pos(), pos,
2143 bview->buffer()->params.textclass, doclear);
2145 sel_end_cursor.par(endpar);
2146 sel_end_cursor.pos(pos);
2147 cursor.pos(sel_end_cursor.pos());
2149 endpar = endpar->Next();
2151 // sometimes necessary
2153 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2155 RedoParagraphs(bview, sel_start_cursor, endpar);
2158 cursor = sel_start_cursor;
2159 SetCursor(bview, cursor.par(), cursor.pos());
2160 sel_cursor = cursor;
2161 UpdateCounters(bview, cursor.row());
2165 void LyXText::CopySelection(BufferView * bview)
2167 // Stuff what we got on the clipboard. Even if there is no selection.
2169 // There is a problem with having the stuffing here in that the
2170 // larger the selection the slower LyX will get. This can be
2171 // solved by running the line below only when the selection has
2172 // finished. The solution used currently just works, to make it
2173 // faster we need to be more clever and probably also have more
2174 // calls to stuffClipboard. (Lgb)
2175 bview->stuffClipboard(selectionAsString(bview->buffer()));
2177 // this doesnt make sense, if there is no selection
2181 // ok we have a selection. This is always between sel_start_cursor
2182 // and sel_end cursor
2183 LyXParagraph * tmppar;
2186 /* check wether there are half footnotes in the selection */
2187 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2188 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2189 tmppar = sel_start_cursor.par();
2190 while (tmppar != sel_end_cursor.par()) {
2191 if (tmppar->footnoteflag !=
2192 sel_end_cursor.par()->footnoteflag) {
2193 WriteAlert(_("Impossible operation"),
2194 _("Don't know what to do"
2195 " with half floats."),
2199 tmppar = tmppar->Next();
2204 /* table stuff -- begin */
2205 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2206 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2207 WriteAlert(_("Impossible operation"),
2208 _("Don't know what to do with half tables."),
2213 /* table stuff -- end */
2216 // copy behind a space if there is one
2217 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2218 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2219 && (sel_start_cursor.par() != sel_end_cursor.par()
2220 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2221 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2225 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2226 sel_start_cursor.pos(), sel_end_cursor.pos(),
2227 bview->buffer()->params.textclass);
2231 void LyXText::PasteSelection(BufferView * bview)
2235 // this does not make sense, if there is nothing to paste
2236 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2239 SetUndo(bview->buffer(), Undo::INSERT,
2240 cursor.par()->ParFromPos(cursor.pos())->previous,
2241 cursor.par()->ParFromPos(cursor.pos())->next);
2243 LyXParagraph * endpar;
2244 LyXParagraph * actpar = cursor.par();
2246 int pos = cursor.pos();
2247 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2249 RedoParagraphs(bview, cursor, endpar);
2251 SetCursor(bview, cursor.par(), cursor.pos());
2254 sel_cursor = cursor;
2255 SetCursor(bview, actpar, pos);
2257 UpdateCounters(bview, cursor.row());
2261 // returns a pointer to the very first LyXParagraph
2262 LyXParagraph * LyXText::FirstParagraph() const
2264 return OwnerParagraph();
2268 // returns true if the specified string is at the specified position
2269 bool LyXText::IsStringInText(LyXParagraph * par,
2270 LyXParagraph::size_type pos,
2271 char const * str) const
2275 while (pos + i < par->Last() && str[i] &&
2276 str[i] == par->GetChar(pos + i)) {
2286 // sets the selection over the number of characters of string, no check!!
2287 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2289 sel_cursor = cursor;
2290 for (int i = 0; string[i]; ++i)
2296 // simple replacing. The font of the first selected character is used
2297 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2299 SetCursorParUndo(bview->buffer());
2302 if (!selection) { // create a dummy selection
2303 sel_end_cursor = cursor;
2304 sel_start_cursor = cursor;
2307 // Get font setting before we cut
2308 LyXParagraph::size_type pos = sel_end_cursor.pos();
2309 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2310 sel_start_cursor.pos());
2312 // Insert the new string
2313 for (int i = 0; str[i]; ++i) {
2314 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2318 // Cut the selection
2319 CutSelection(bview);
2325 // if the string can be found: return true and set the cursor to
2327 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2329 LyXParagraph * par = cursor.par();
2330 LyXParagraph::size_type pos = cursor.pos();
2331 while (par && !IsStringInText(par, pos, str)) {
2332 if (pos < par->Last() - 1)
2340 SetCursor(bview, par, pos);
2348 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2350 LyXParagraph * par = cursor.par();
2351 int pos = cursor.pos();
2357 // We skip empty paragraphs (Asger)
2359 par = par->Previous();
2361 pos = par->Last() - 1;
2362 } while (par && pos < 0);
2364 } while (par && !IsStringInText(par, pos, string));
2367 SetCursor(bview, par, pos);
2374 // needed to insert the selection
2375 void LyXText::InsertStringA(BufferView * bview, string const & str)
2377 LyXParagraph * par = cursor.par();
2378 LyXParagraph::size_type pos = cursor.pos();
2379 LyXParagraph::size_type a = 0;
2381 LyXParagraph * endpar = cursor.par()->Next();
2383 SetCursorParUndo(bview->buffer());
2386 textclasslist.Style(bview->buffer()->params.textclass,
2387 cursor.par()->GetLayout()).isEnvironment();
2388 // only to be sure, should not be neccessary
2391 // insert the string, don't insert doublespace
2392 string::size_type i = 0;
2393 while (i < str.length()) {
2394 if (str[i] != '\n') {
2396 && i + 1 < str.length() && str[i + 1] != ' '
2397 && pos && par->GetChar(pos - 1)!= ' ') {
2398 par->InsertChar(pos, ' ', current_font);
2401 } else if (par->table) {
2402 if (str[i] == '\t') {
2403 while((pos < par->size()) &&
2404 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2406 if (pos < par->size())
2408 else // no more fields to fill skip the rest
2410 } else if ((str[i] != 13) &&
2411 ((str[i] & 127) >= ' ')) {
2412 par->InsertChar(pos, str[i],
2417 } else if (str[i] == ' ') {
2418 InsetSpecialChar * new_inset =
2419 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2420 if (par->InsertInsetAllowed(new_inset)) {
2421 par->InsertInset(pos, new_inset,
2427 } else if (str[i] == '\t') {
2428 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2429 InsetSpecialChar * new_inset =
2430 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2431 if (par->InsertInsetAllowed(new_inset)) {
2432 par->InsertInset(pos, new_inset,
2439 } else if (str[i] != 13 &&
2440 // Ignore unprintables
2441 (str[i] & 127) >= ' ') {
2442 par->InsertChar(pos, str[i], current_font);
2448 if ((i + 1) >= str.length()) {
2449 if (pos < par->size())
2453 while((pos < par->size()) &&
2454 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2457 cell = NumberOfCell(par, pos);
2458 while((pos < par->size()) &&
2459 !(par->table->IsFirstCell(cell))) {
2461 while((pos < par->size()) &&
2462 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2465 cell = NumberOfCell(par, pos);
2467 if (pos >= par->size())
2468 // no more fields to fill skip the rest
2472 if (!par->size()) { // par is empty
2473 InsetSpecialChar * new_inset =
2474 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2475 if (par->InsertInsetAllowed(new_inset)) {
2476 par->InsertInset(pos,
2484 par->BreakParagraph(bview->buffer()->params, pos, flag);
2494 RedoParagraphs(bview, cursor, endpar);
2495 SetCursor(bview, cursor.par(), cursor.pos());
2496 sel_cursor = cursor;
2497 SetCursor(bview, par, pos);
2502 /* turns double-CR to single CR, others where converted into one blank and 13s
2503 * that are ignored .Double spaces are also converted into one. Spaces at
2504 * the beginning of a paragraph are forbidden. tabs are converted into one
2505 * space. then InsertStringA is called */
2506 void LyXText::InsertStringB(BufferView * bview, string const & s)
2509 LyXParagraph * par = cursor.par();
2510 string::size_type i = 1;
2511 while (i < str.length()) {
2512 if (str[i] == '\t' && !par->table)
2514 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2516 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2517 if (str[i + 1] != '\n') {
2518 if (str[i - 1] != ' ')
2523 while (i + 1 < str.length()
2524 && (str[i + 1] == ' '
2525 || str[i + 1] == '\t'
2526 || str[i + 1] == '\n'
2527 || str[i + 1] == 13)) {
2534 InsertStringA(bview, str);
2538 bool LyXText::GotoNextError(BufferView * bview) const
2540 LyXCursor res = cursor;
2542 if (res.pos() < res.par()->Last() - 1) {
2543 res.pos(res.pos() + 1);
2545 res.par(res.par()->Next());
2549 } while (res.par() &&
2550 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2551 && res.par()->GetInset(res.pos())->AutoDelete()));
2554 SetCursor(bview, res.par(), res.pos());
2561 bool LyXText::GotoNextNote(BufferView * bview) const
2563 LyXCursor res = cursor;
2565 if (res.pos() < res.par()->Last() - 1) {
2566 res.pos(res.pos() + 1);
2568 res.par(res.par()->Next());
2572 } while (res.par() &&
2573 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2574 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2577 SetCursor(bview, res.par(), res.pos());
2584 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2585 LyXParagraph::size_type pos)
2587 LyXCursor tmpcursor;
2590 /* table stuff -- begin*/
2593 CheckParagraphInTable(bview, par, pos);
2597 /* table stuff -- end*/
2600 LyXParagraph::size_type z;
2601 Row * row = GetRow(par, pos, y);
2603 // is there a break one row above
2604 if (row->previous() && row->previous()->par() == row->par()) {
2605 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2606 if ( z >= row->pos()) {
2607 // set the dimensions of the row above
2608 y -= row->previous()->height();
2610 refresh_row = row->previous();
2611 status = LyXText::NEED_MORE_REFRESH;
2613 BreakAgain(bview, row->previous());
2615 // set the cursor again. Otherwise
2616 // dangling pointers are possible
2617 SetCursor(bview, cursor.par(), cursor.pos());
2618 sel_cursor = cursor;
2623 int tmpheight = row->height();
2624 LyXParagraph::size_type tmplast = RowLast(row);
2628 BreakAgain(bview, row);
2629 if (row->height() == tmpheight && RowLast(row) == tmplast)
2630 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2632 status = LyXText::NEED_MORE_REFRESH;
2634 // check the special right address boxes
2635 if (textclasslist.Style(bview->buffer()->params.textclass,
2636 par->GetLayout()).margintype
2637 == MARGIN_RIGHT_ADDRESS_BOX) {
2644 RedoDrawingOfParagraph(bview, tmpcursor);
2650 // set the cursor again. Otherwise dangling pointers are possible
2651 // also set the selection
2655 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2656 sel_cursor = cursor;
2657 SetCursorIntern(bview, sel_start_cursor.par(),
2658 sel_start_cursor.pos());
2659 sel_start_cursor = cursor;
2660 SetCursorIntern(bview, sel_end_cursor.par(),
2661 sel_end_cursor.pos());
2662 sel_end_cursor = cursor;
2663 SetCursorIntern(bview, last_sel_cursor.par(),
2664 last_sel_cursor.pos());
2665 last_sel_cursor = cursor;
2668 SetCursorIntern(bview, cursor.par(), cursor.pos());
2672 // returns false if inset wasn't found
2673 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2675 // first check the current paragraph
2676 int pos = cursor.par()->GetPositionOfInset(inset);
2678 CheckParagraph(bview, cursor.par(), pos);
2682 // check every paragraph
2684 LyXParagraph * par = FirstParagraph();
2686 // make sure the paragraph is open
2687 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2688 pos = par->GetPositionOfInset(inset);
2690 CheckParagraph(bview, par, pos);
2701 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2702 LyXParagraph::size_type pos,
2703 bool setfont, bool boundary) const
2705 LyXCursor old_cursor = cursor;
2706 SetCursorIntern(bview, par, pos, setfont, boundary);
2707 DeleteEmptyParagraphMechanism(bview, old_cursor);
2711 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2712 LyXParagraph::size_type pos, bool boundary) const
2714 // correct the cursor position if impossible
2715 if (pos > par->Last()){
2716 LyXParagraph * tmppar = par->ParFromPos(pos);
2717 pos = par->PositionInParFromPos(pos);
2721 if (par->IsDummy() && par->previous &&
2722 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2723 while (par->previous &&
2724 ((par->previous->IsDummy() &&
2725 (par->previous->previous->footnoteflag ==
2726 LyXParagraph::CLOSED_FOOTNOTE)) ||
2727 (par->previous->footnoteflag ==
2728 LyXParagraph::CLOSED_FOOTNOTE))) {
2729 par = par->previous ;
2730 if (par->IsDummy() &&
2731 (par->previous->footnoteflag ==
2732 LyXParagraph::CLOSED_FOOTNOTE))
2733 pos += par->size() + 1;
2735 if (par->previous) {
2736 par = par->previous;
2738 pos += par->size() + 1;
2743 cur.boundary(boundary);
2745 /* get the cursor y position in text */
2747 Row * row = GetRow(par, pos, y);
2748 /* y is now the beginning of the cursor row */
2749 y += row->baseline();
2750 /* y is now the cursor baseline */
2753 /* now get the cursors x position */
2755 float fill_separator, fill_hfill, fill_label_hfill;
2756 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2758 LyXParagraph::size_type cursor_vpos = 0;
2759 LyXParagraph::size_type last = RowLastPrintable(row);
2761 if (pos > last + 1) // This shouldn't happen.
2763 else if (pos < row->pos())
2766 if (last < row->pos())
2767 cursor_vpos = row->pos();
2768 else if (pos > last && !boundary)
2769 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2770 ? row->pos() : last + 1;
2771 else if (pos > row->pos() &&
2772 (pos > last || boundary ||
2773 (row->par()->table && row->par()->IsNewline(pos))))
2774 /// Place cursor after char at (logical) position pos - 1
2775 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2776 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2778 /// Place cursor before char at (logical) position pos
2779 cursor_vpos = (bidi_level(pos) % 2 == 0)
2780 ? log2vis(pos) : log2vis(pos) + 1;
2783 /* table stuff -- begin*/
2784 if (row->par()->table) {
2785 int cell = NumberOfCell(row->par(), row->pos());
2787 x += row->par()->table->GetBeginningOfTextInCell(cell);
2788 for (LyXParagraph::size_type vpos = row->pos();
2789 vpos < cursor_vpos; ++vpos) {
2790 pos = vis2log(vpos);
2791 if (row->par()->IsNewline(pos)) {
2792 x = x_old + row->par()->table->WidthOfColumn(cell);
2795 x += row->par()->table->GetBeginningOfTextInCell(cell);
2797 x += SingleWidth(bview, row->par(), pos);
2801 /* table stuff -- end*/
2803 LyXParagraph::size_type main_body =
2804 BeginningOfMainBody(bview->buffer(), row->par());
2805 if ((main_body > 0) &&
2806 ((main_body-1 > last) ||
2807 !row->par()->IsLineSeparator(main_body-1)))
2810 for (LyXParagraph::size_type vpos = row->pos();
2811 vpos < cursor_vpos; ++vpos) {
2812 pos = vis2log(vpos);
2813 if (main_body > 0 && pos == main_body-1) {
2814 x += fill_label_hfill +
2815 lyxfont::width(textclasslist.Style(
2816 bview->buffer()->params.textclass,
2817 row->par()->GetLayout())
2819 GetFont(bview->buffer(), row->par(), -2));
2820 if (row->par()->IsLineSeparator(main_body-1))
2821 x -= SingleWidth(bview, row->par(),main_body-1);
2823 if (HfillExpansion(bview->buffer(), row, pos)) {
2824 x += SingleWidth(bview, row->par(), pos);
2825 if (pos >= main_body)
2828 x += fill_label_hfill;
2829 } else if (row->par()->IsSeparator(pos)) {
2830 x += SingleWidth(bview, row->par(), pos);
2831 if (pos >= main_body)
2832 x += fill_separator;
2834 x += SingleWidth(bview, row->par(), pos);
2846 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2847 LyXParagraph::size_type pos,
2848 bool setfont, bool boundary) const
2850 SetCursor(bview, cursor, par, pos, boundary);
2852 SetCurrentFont(bview);
2855 void LyXText::SetCurrentFont(BufferView * bview) const
2857 LyXParagraph::size_type pos = cursor.pos();
2858 if (cursor.boundary() && pos > 0)
2862 if (pos == cursor.par()->Last() ||
2863 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2865 else if (cursor.par()->IsSeparator(pos)) {
2866 if (pos > cursor.row()->pos() &&
2867 bidi_level(pos) % 2 ==
2868 bidi_level(pos - 1) % 2)
2870 else if (pos + 1 < cursor.par()->Last())
2876 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2877 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2879 if (cursor.pos() == cursor.par()->Last() &&
2880 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2881 !cursor.boundary()) {
2882 Language const * lang =
2883 cursor.par()->getParLanguage(bview->buffer()->params);
2884 current_font.setLanguage(lang);
2885 real_current_font.setLanguage(lang);
2890 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2892 LyXCursor old_cursor = cursor;
2894 /* get the row first */
2896 Row * row = GetRowNearY(y);
2897 cursor.par(row->par());
2900 int column = GetColumnNearX(bview, row, x, bound);
2901 cursor.pos(row->pos() + column);
2903 cursor.y(y + row->baseline());
2905 cursor.boundary(bound);
2906 SetCurrentFont(bview);
2907 DeleteEmptyParagraphMechanism(bview, old_cursor);
2911 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2912 int x, long y) const
2914 /* get the row first */
2916 Row * row = GetRowNearY(y);
2918 int column = GetColumnNearX(bview, row, x, bound);
2920 cur.par(row->par());
2921 cur.pos(row->pos() + column);
2923 cur.y(y + row->baseline());
2925 cur.boundary(bound);
2929 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2931 CursorLeftIntern(bview, internal);
2933 if (cursor.par()->table) {
2934 int cell = NumberOfCell(cursor.par(), cursor.pos());
2935 if (cursor.par()->table->IsContRow(cell)
2936 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2944 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2946 if (cursor.pos() > 0) {
2947 bool boundary = cursor.boundary();
2948 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2949 if (!internal && !boundary &&
2950 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2951 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2952 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2953 LyXParagraph * par = cursor.par()->Previous();
2954 SetCursor(bview, par, par->Last());
2959 void LyXText::CursorRight(BufferView * bview, bool internal) const
2961 CursorRightIntern(bview, internal);
2963 if (cursor.par()->table) {
2964 int cell = NumberOfCell(cursor.par(), cursor.pos());
2965 if (cursor.par()->table->IsContRow(cell) &&
2966 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2974 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
2976 if (!internal && cursor.boundary() &&
2977 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
2978 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2979 else if (cursor.pos() < cursor.par()->Last()) {
2980 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2982 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2983 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2984 } else if (cursor.par()->Next())
2985 SetCursor(bview, cursor.par()->Next(), 0);
2989 void LyXText::CursorUp(BufferView * bview) const
2991 SetCursorFromCoordinates(bview, cursor.x_fix(),
2992 cursor.y() - cursor.row()->baseline() - 1);
2994 if (cursor.par()->table) {
2995 int cell = NumberOfCell(cursor.par(), cursor.pos());
2996 if (cursor.par()->table->IsContRow(cell) &&
2997 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3005 void LyXText::CursorDown(BufferView * bview) const
3008 if (cursor.par()->table &&
3009 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3010 !cursor.par()->next)
3014 SetCursorFromCoordinates(bview, cursor.x_fix(),
3015 cursor.y() - cursor.row()->baseline()
3016 + cursor.row()->height() + 1);
3018 if (cursor.par()->table) {
3019 int cell = NumberOfCell(cursor.par(), cursor.pos());
3020 int cell_above = cursor.par()->table->GetCellAbove(cell);
3021 while(cursor.par()->table &&
3022 cursor.par()->table->IsContRow(cell) &&
3023 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3024 SetCursorFromCoordinates(bview, cursor.x_fix(),
3025 cursor.y() - cursor.row()->baseline()
3026 + cursor.row()->height() + 1);
3027 if (cursor.par()->table) {
3028 cell = NumberOfCell(cursor.par(), cursor.pos());
3029 cell_above = cursor.par()->table->GetCellAbove(cell);
3037 void LyXText::CursorUpParagraph(BufferView * bview) const
3039 if (cursor.pos() > 0) {
3040 SetCursor(bview, cursor.par(), 0);
3042 else if (cursor.par()->Previous()) {
3043 SetCursor(bview, cursor.par()->Previous(), 0);
3048 void LyXText::CursorDownParagraph(BufferView * bview) const
3050 if (cursor.par()->Next()) {
3051 SetCursor(bview, cursor.par()->Next(), 0);
3053 SetCursor(bview, cursor.par(), cursor.par()->Last());
3058 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3059 LyXCursor const & old_cursor) const
3061 // Would be wrong to delete anything if we have a selection.
3062 if (selection) return;
3064 // We allow all kinds of "mumbo-jumbo" when freespacing.
3065 if (textclasslist.Style(bview->buffer()->params.textclass,
3066 old_cursor.par()->GetLayout()).free_spacing)
3069 bool deleted = false;
3071 /* Ok I'll put some comments here about what is missing.
3072 I have fixed BackSpace (and thus Delete) to not delete
3073 double-spaces automagically. I have also changed Cut,
3074 Copy and Paste to hopefully do some sensible things.
3075 There are still some small problems that can lead to
3076 double spaces stored in the document file or space at
3077 the beginning of paragraphs. This happens if you have
3078 the cursor betwenn to spaces and then save. Or if you
3079 cut and paste and the selection have a space at the
3080 beginning and then save right after the paste. I am
3081 sure none of these are very hard to fix, but I will
3082 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3083 that I can get some feedback. (Lgb)
3086 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3087 // delete the LineSeparator.
3090 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3091 // delete the LineSeparator.
3094 // If the pos around the old_cursor were spaces, delete one of them.
3095 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3096 // Only if the cursor has really moved
3098 if (old_cursor.pos() > 0
3099 && old_cursor.pos() < old_cursor.par()->Last()
3100 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3101 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3102 old_cursor.par()->Erase(old_cursor.pos() - 1);
3103 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3105 if (old_cursor.par() == cursor.par() &&
3106 cursor.pos() > old_cursor.pos()) {
3107 SetCursorIntern(bview, cursor.par(),
3110 SetCursorIntern(bview, cursor.par(),
3116 // Do not delete empty paragraphs with keepempty set.
3117 if ((textclasslist.Style(bview->buffer()->params.textclass,
3118 old_cursor.par()->GetLayout())).keepempty)
3121 LyXCursor tmpcursor;
3123 if (old_cursor.par() != cursor.par()) {
3124 if ( (old_cursor.par()->Last() == 0
3125 || (old_cursor.par()->Last() == 1
3126 && old_cursor.par()->IsLineSeparator(0)))
3127 && old_cursor.par()->FirstPhysicalPar()
3128 == old_cursor.par()->LastPhysicalPar()) {
3129 // ok, we will delete anything
3131 // make sure that you do not delete any environments
3132 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3133 !(old_cursor.row()->previous()
3134 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3135 && !(old_cursor.row()->next()
3136 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3137 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3138 && ((old_cursor.row()->previous()
3139 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3140 || (old_cursor.row()->next()
3141 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3143 status = LyXText::NEED_MORE_REFRESH;
3146 if (old_cursor.row()->previous()) {
3147 refresh_row = old_cursor.row()->previous();
3148 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3150 cursor = old_cursor; // that undo can restore the right cursor position
3151 LyXParagraph * endpar = old_cursor.par()->next;
3152 if (endpar && endpar->GetDepth()) {
3153 while (endpar && endpar->GetDepth()) {
3154 endpar = endpar->LastPhysicalPar()->Next();
3157 SetUndo(bview->buffer(), Undo::DELETE,
3158 old_cursor.par()->previous,
3163 RemoveRow(old_cursor.row());
3164 if (OwnerParagraph() == old_cursor.par()) {
3165 OwnerParagraph(OwnerParagraph()->next);
3168 delete old_cursor.par();
3170 /* Breakagain the next par. Needed
3171 * because of the parindent that
3172 * can occur or dissappear. The
3173 * next row can change its height,
3174 * if there is another layout before */
3175 if (refresh_row->next()) {
3176 BreakAgain(bview, refresh_row->next());
3177 UpdateCounters(bview, refresh_row);
3179 SetHeightOfRow(bview, refresh_row);
3181 refresh_row = old_cursor.row()->next();
3182 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3185 cursor = old_cursor; // that undo can restore the right cursor position
3186 LyXParagraph * endpar = old_cursor.par()->next;
3187 if (endpar && endpar->GetDepth()) {
3188 while (endpar && endpar->GetDepth()) {
3189 endpar = endpar->LastPhysicalPar()->Next();
3192 SetUndo(bview->buffer(), Undo::DELETE,
3193 old_cursor.par()->previous,
3198 RemoveRow(old_cursor.row());
3200 if (OwnerParagraph() == old_cursor.par()) {
3201 OwnerParagraph(OwnerParagraph()->next);
3203 delete old_cursor.par();
3205 /* Breakagain the next par. Needed
3206 because of the parindent that can
3207 occur or dissappear.
3208 The next row can change its height,
3209 if there is another layout before
3212 BreakAgain(bview, refresh_row);
3213 UpdateCounters(bview, refresh_row->previous());
3219 SetCursorIntern(bview, cursor.par(), cursor.pos());
3221 if (sel_cursor.par() == old_cursor.par()
3222 && sel_cursor.pos() == sel_cursor.pos()) {
3223 // correct selection
3224 sel_cursor = cursor;
3229 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3230 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3232 SetCursorIntern(bview, cursor.par(), cursor.pos());
3233 sel_cursor = cursor;
3240 LyXParagraph * LyXText::GetParFromID(int id)
3242 LyXParagraph * result = FirstParagraph();
3243 while (result && result->id() != id)
3244 result = result->next;
3250 bool LyXText::TextUndo(BufferView * bview)
3254 // returns false if no undo possible
3255 Undo * undo = bview->buffer()->undostack.pop();
3259 bview->buffer()->redostack
3260 .push(CreateUndo(bview->buffer(), undo->kind,
3261 GetParFromID(undo->number_of_before_par),
3262 GetParFromID(undo->number_of_behind_par)));
3264 return TextHandleUndo(bview, undo);
3268 bool LyXText::TextRedo(BufferView * bview)
3272 // returns false if no redo possible
3273 Undo * undo = bview->buffer()->redostack.pop();
3277 bview->buffer()->undostack
3278 .push(CreateUndo(bview->buffer(), undo->kind,
3279 GetParFromID(undo->number_of_before_par),
3280 GetParFromID(undo->number_of_behind_par)));
3282 return TextHandleUndo(bview, undo);
3286 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3290 // returns false if no undo possible
3291 bool result = false;
3293 LyXParagraph * before =
3294 GetParFromID(undo->number_of_before_par);
3295 LyXParagraph * behind =
3296 GetParFromID(undo->number_of_behind_par);
3297 LyXParagraph * tmppar;
3298 LyXParagraph * tmppar2;
3299 LyXParagraph * endpar;
3300 LyXParagraph * tmppar5;
3302 // if there's no before take the beginning
3303 // of the document for redoing
3305 SetCursorIntern(bview, FirstParagraph(), 0);
3307 // replace the paragraphs with the undo informations
3309 LyXParagraph * tmppar3 = undo->par;
3310 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3311 LyXParagraph * tmppar4 = tmppar3;
3313 while (tmppar4->next)
3314 tmppar4 = tmppar4->next;
3315 } // get last undo par
3317 // now remove the old text if there is any
3318 if (before != behind || (!behind && !before)){
3320 tmppar5 = before->next;
3322 tmppar5 = OwnerParagraph();
3324 while (tmppar5 && tmppar5 != behind){
3326 tmppar5 = tmppar5->next;
3327 // a memory optimization for edit: Only layout information
3328 // is stored in the undo. So restore the text informations.
3329 if (undo->kind == Undo::EDIT) {
3330 tmppar2->setContentsFromPar(tmppar);
3331 tmppar->clearContents();
3332 tmppar2 = tmppar2->next;
3337 // put the new stuff in the list if there is one
3340 before->next = tmppar3;
3342 OwnerParagraph(tmppar3);
3343 tmppar3->previous = before;
3347 OwnerParagraph(behind);
3350 tmppar4->next = behind;
3352 behind->previous = tmppar4;
3356 // Set the cursor for redoing
3358 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3359 // check wether before points to a closed float and open it if necessary
3360 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3361 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3363 while (tmppar4->previous &&
3364 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3365 tmppar4 = tmppar4->previous;
3366 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3367 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3368 tmppar4 = tmppar4->next;
3373 // open a cosed footnote at the end if necessary
3374 if (behind && behind->previous &&
3375 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3376 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3377 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3378 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3379 behind = behind->next;
3383 // calculate the endpar for redoing the paragraphs.
3385 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3386 endpar = behind->LastPhysicalPar()->Next();
3388 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3392 tmppar = GetParFromID(undo->number_of_cursor_par);
3393 RedoParagraphs(bview, cursor, endpar);
3395 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3396 UpdateCounters(bview, cursor.row());
3406 void LyXText::FinishUndo()
3410 // makes sure the next operation will be stored
3411 undo_finished = true;
3415 void LyXText::FreezeUndo()
3419 // this is dangerous and for internal use only
3424 void LyXText::UnFreezeUndo()
3428 // this is dangerous and for internal use only
3429 undo_frozen = false;
3433 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3434 LyXParagraph const * before,
3435 LyXParagraph const * behind) const
3440 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3441 buf->redostack.clear();
3445 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3446 LyXParagraph const * before, LyXParagraph const * behind)
3450 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3454 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3455 LyXParagraph const * before,
3456 LyXParagraph const * behind) const
3461 int before_number = -1;
3462 int behind_number = -1;
3464 before_number = before->id();
3466 behind_number = behind->id();
3467 // Undo::EDIT and Undo::FINISH are
3468 // always finished. (no overlapping there)
3469 // overlapping only with insert and delete inside one paragraph:
3470 // Nobody wants all removed character
3471 // appear one by one when undoing.
3472 // EDIT is special since only layout information, not the
3473 // contents of a paragaph are stored.
3474 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3475 // check wether storing is needed
3476 if (!buf->undostack.empty() &&
3477 buf->undostack.top()->kind == kind &&
3478 buf->undostack.top()->number_of_before_par == before_number &&
3479 buf->undostack.top()->number_of_behind_par == behind_number ){
3484 // create a new Undo
3485 LyXParagraph * undopar;
3486 LyXParagraph * tmppar;
3487 LyXParagraph * tmppar2;
3489 LyXParagraph * start = 0;
3490 LyXParagraph * end = 0;
3493 start = before->next;
3495 start = FirstParagraph();
3497 end = behind->previous;
3499 end = FirstParagraph();
3505 && start != end->next
3506 && (before != behind || (!before && !behind))) {
3508 tmppar2 = tmppar->Clone();
3509 tmppar2->id(tmppar->id());
3511 // a memory optimization: Just store the layout information
3513 if (kind == Undo::EDIT){
3514 //tmppar2->text.clear();
3515 tmppar2->clearContents();
3520 while (tmppar != end && tmppar->next) {
3521 tmppar = tmppar->next;
3522 tmppar2->next = tmppar->Clone();
3523 tmppar2->next->id(tmppar->id());
3524 // a memory optimization: Just store the layout
3525 // information when only edit
3526 if (kind == Undo::EDIT){
3527 //tmppar2->next->text.clear();
3528 tmppar2->clearContents();
3530 tmppar2->next->previous = tmppar2;
3531 tmppar2 = tmppar2->next;
3535 undopar = 0; // nothing to replace (undo of delete maybe)
3537 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3538 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3540 Undo * undo = new Undo(kind,
3541 before_number, behind_number,
3542 cursor_par, cursor_pos,
3545 undo_finished = false;
3550 void LyXText::SetCursorParUndo(Buffer * buf)
3554 SetUndo(buf, Undo::FINISH,
3555 cursor.par()->ParFromPos(cursor.pos())->previous,
3556 cursor.par()->ParFromPos(cursor.pos())->next);
3561 void LyXText::RemoveTableRow(LyXCursor & cur) const
3567 // move to the previous row
3568 int cell_act = NumberOfCell(cur.par(), cur.pos());
3571 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3572 cur.pos(cur.pos() - 1);
3574 !cur.par()->table->IsFirstCell(cell_act)) {
3575 cur.pos(cur.pos() - 1);
3576 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3577 cur.pos(cur.pos() - 1);
3581 // now we have to pay attention if the actual table is the
3582 // main row of TableContRows and if yes to delete all of them
3587 // delete up to the next row
3588 while (cur.pos() < cur.par()->Last() &&
3590 || !cur.par()->table->IsFirstCell(cell_act))) {
3591 while (cur.pos() < cur.par()->Last() &&
3592 !cur.par()->IsNewline(cur.pos()))
3593 cur.par()->Erase(cur.pos());
3596 if (cur.pos() < cur.par()->Last())
3597 cur.par()->Erase(cur.pos());
3599 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3600 cur.pos(cur.pos() - 1);
3601 cur.par()->Erase(cur.pos()); // no newline at very end!
3603 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3604 !cur.par()->table->IsContRow(cell_org) &&
3605 cur.par()->table->IsContRow(cell));
3606 cur.par()->table->DeleteRow(cell_org);
3613 bool LyXText::IsEmptyTableCell() const
3615 LyXParagraph::size_type pos = cursor.pos() - 1;
3616 while (pos >= 0 && pos < cursor.par()->Last()
3617 && !cursor.par()->IsNewline(pos))
3619 return cursor.par()->IsNewline(pos + 1);
3624 void LyXText::toggleAppendix(BufferView * bview)
3626 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3627 bool start = !par->start_of_appendix;
3629 // ensure that we have only one start_of_appendix in this document
3630 LyXParagraph * tmp = FirstParagraph();
3631 for (; tmp; tmp = tmp->next)
3632 tmp->start_of_appendix = 0;
3633 par->start_of_appendix = start;
3635 // we can set the refreshing parameters now
3636 status = LyXText::NEED_MORE_REFRESH;
3638 refresh_row = 0; // not needed for full update
3639 UpdateCounters(bview, 0);
3640 SetCursor(bview, cursor.par(), cursor.pos());
3643 LyXParagraph * LyXText::OwnerParagraph() const
3646 return inset_owner->par;
3648 return bv_owner->buffer()->paragraph;
3652 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3655 inset_owner->par = p;
3657 bv_owner->buffer()->paragraph = p;