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"
44 //#define USE_OLD_CUT_AND_PASTE 1
50 LyXText::LyXText(BufferView * bv)
58 LyXText::LyXText(InsetText * inset)
73 status = LyXText::UNCHANGED;
74 // set cursor at the very top position
75 selection = true; /* these setting is necessary
76 because of the delete-empty-
77 paragraph mechanism in
80 LyXParagraph * par = OwnerParagraph();
81 current_font = GetFont(bv_owner->buffer(), par, 0);
83 InsertParagraph(bv_owner, par, lastrow);
86 SetCursor(bv_owner, firstrow->par(), 0);
88 current_font = LyXFont(LyXFont::ALL_SANE);
94 // no rebreak necessary
100 // Default layouttype for copy environment type
104 // Dump all rowinformation:
105 Row * tmprow = firstrow;
106 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
108 lyxerr << tmprow->baseline() << '\t'
109 << tmprow->par << '\t'
110 << tmprow->pos() << '\t'
111 << tmprow->height << '\t'
112 << tmprow->ascent_of_text << '\t'
113 << tmprow->fill << '\n';
114 tmprow = tmprow->next();
121 void LyXText::init(BufferView * bview)
126 LyXParagraph * par = OwnerParagraph();
127 current_font = GetFont(bview->buffer(), par, 0);
129 InsertParagraph(bview, par, lastrow);
132 SetCursorIntern(bview, firstrow->par(), 0);
134 // Dump all rowinformation:
135 Row * tmprow = firstrow;
136 lyxerr << "Width = " << width << endl;
137 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
139 lyxerr << tmprow->baseline() << '\t'
140 << tmprow->par() << '\t'
141 << tmprow->pos() << '\t'
142 << tmprow->height() << '\t'
143 << tmprow->ascent_of_text() << '\t'
144 << tmprow->fill() << '\n';
145 tmprow = tmprow->next();
153 // Delete all rows, this does not touch the paragraphs!
154 Row * tmprow = firstrow;
156 tmprow = firstrow->next();
164 void LyXText::owner(BufferView * bv)
166 if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179 LyXParagraph::size_type pos) const
181 LyXLayout const & layout =
182 textclasslist.Style(buf->params.textclass, par->GetLayout());
184 char par_depth = par->GetDepth();
185 // We specialize the 95% common case:
186 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
189 if (layout.labeltype == LABEL_MANUAL
190 && pos < BeginningOfMainBody(buf, par)) {
192 return par->GetFontSettings(buf->params, pos).
193 realize(layout.reslabelfont);
195 return par->GetFontSettings(buf->params, pos).
196 realize(layout.resfont);
199 // process layoutfont for pos == -1 and labelfont for pos < -1
201 return layout.resfont;
203 return layout.reslabelfont;
207 // The uncommon case need not be optimized as much
209 LyXFont layoutfont, tmpfont;
213 if (pos < BeginningOfMainBody(buf, par)) {
215 layoutfont = layout.labelfont;
218 layoutfont = layout.font;
220 tmpfont = par->GetFontSettings(buf->params, pos);
221 tmpfont.realize(layoutfont);
224 // process layoutfont for pos == -1 and labelfont for pos < -1
226 tmpfont = layout.font;
228 tmpfont = layout.labelfont;
231 // Resolve against environment font information
232 while (par && par_depth && !tmpfont.resolved()) {
233 par = par->DepthHook(par_depth - 1);
235 tmpfont.realize(textclasslist.
236 Style(buf->params.textclass,
237 par->GetLayout()).font);
238 par_depth = par->GetDepth();
242 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
244 // Cosmetic improvement: If this is an open footnote, make the font
246 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
247 && par->footnotekind == LyXParagraph::FOOTNOTE) {
255 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
256 LyXParagraph::size_type pos,
260 // Let the insets convert their font
261 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
262 if (par->GetInset(pos))
263 font = par->GetInset(pos)->ConvertFont(font);
266 LyXLayout const & layout =
267 textclasslist.Style(buf->params.textclass,
270 // Get concrete layout font to reduce against
273 if (pos < BeginningOfMainBody(buf, par))
274 layoutfont = layout.labelfont;
276 layoutfont = layout.font;
278 // Realize against environment font information
279 if (par->GetDepth()){
280 LyXParagraph * tp = par;
281 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
282 tp = tp->DepthHook(tp->GetDepth()-1);
284 layoutfont.realize(textclasslist.
285 Style(buf->params.textclass,
286 tp->GetLayout()).font);
290 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
292 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
293 && par->footnotekind == LyXParagraph::FOOTNOTE) {
294 layoutfont.decSize();
297 // Now, reduce font against full layout font
298 font.reduce(layoutfont);
300 par->SetFont(pos, font);
304 /* inserts a new row behind the specified row, increments
305 * the touched counters */
306 void LyXText::InsertRow(Row * row, LyXParagraph * par,
307 LyXParagraph::size_type pos) const
309 Row * tmprow = new Row;
312 tmprow->next(firstrow);
315 tmprow->previous(row);
316 tmprow->next(row->next());
321 tmprow->next()->previous(tmprow);
323 if (tmprow->previous())
324 tmprow->previous()->next(tmprow);
332 ++number_of_rows; // one more row
336 // removes the row and reset the touched counters
337 void LyXText::RemoveRow(Row * row) const
339 /* this must not happen before the currentrow for clear reasons.
340 so the trick is just to set the current row onto the previous
343 GetRow(row->par(), row->pos(), unused_y);
346 row->next()->previous(row->previous());
347 if (!row->previous()) {
348 firstrow = row->next();
350 row->previous()->next(row->next());
353 lastrow = row->previous();
355 height -= row->height(); // the text becomes smaller
358 --number_of_rows; // one row less
362 // remove all following rows of the paragraph of the specified row.
363 void LyXText::RemoveParagraph(Row * row) const
365 LyXParagraph * tmppar = row->par();
369 while (row && row->par() == tmppar) {
370 tmprow = row->next();
377 // insert the specified paragraph behind the specified row
378 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
381 InsertRow(row, par, 0); /* insert a new row, starting
384 SetCounter(bview->buffer(), par); // set the counters
386 // and now append the whole paragraph behind the new row
389 AppendParagraph(bview, firstrow);
391 row->next()->height(0);
392 AppendParagraph(bview, row->next());
397 void LyXText::ToggleFootnote(BufferView * bview)
399 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
401 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
403 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
405 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
406 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);
430 void LyXText::CloseFootnote(BufferView * bview)
432 LyXParagraph * tmppar;
433 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
435 // if the cursor is not in an open footnote, or
436 // there is no open footnote in this paragraph, just return.
437 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
440 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
441 bview->owner()->getMiniBuffer()
442 ->Set(_("Nothing to do"));
446 // ok, move the cursor right before the footnote
447 // just a little faster than using CursorRight()
449 cursor.par()->ParFromPos(cursor.pos()) != par;) {
450 cursor.pos(cursor.pos() + 1);
453 // now the cursor is at the beginning of the physical par
454 SetCursor(bview, cursor.par(),
456 cursor.par()->ParFromPos(cursor.pos())->size());
458 /* we are in a footnote, so let us move at the beginning */
459 /* this is just faster than using just CursorLeft() */
461 tmppar = cursor.par();
462 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
463 // just a little bit faster than movin the cursor
464 tmppar = tmppar->Previous();
466 SetCursor(bview, tmppar, tmppar->Last());
469 // the cursor must be exactly before the footnote
470 par = cursor.par()->ParFromPos(cursor.pos());
472 status = LyXText::NEED_MORE_REFRESH;
473 refresh_row = cursor.row();
474 refresh_y = cursor.y() - cursor.row()->baseline();
476 tmppar = cursor.par();
477 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
478 Row * row = cursor.row();
480 tmppar->CloseFootnote(cursor.pos());
482 while (tmppar != endpar) {
483 RemoveRow(row->next());
485 tmppar = row->next()->par();
490 AppendParagraph(bview, cursor.row());
492 SetCursor(bview, cursor.par(), cursor.pos());
496 if (cursor.row()->next())
497 SetHeightOfRow(bview, cursor.row()->next());
501 /* used in setlayout */
502 // Asger is not sure we want to do this...
503 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
506 LyXLayout const & layout =
507 textclasslist.Style(buf->params.textclass, par->GetLayout());
509 LyXFont layoutfont, tmpfont;
510 for (LyXParagraph::size_type pos = 0;
511 pos < par->Last(); ++pos) {
512 if (pos < BeginningOfMainBody(buf, par))
513 layoutfont = layout.labelfont;
515 layoutfont = layout.font;
517 tmpfont = par->GetFontSettings(buf->params, pos);
518 tmpfont.reduce(layoutfont);
519 par->SetFont(pos, tmpfont);
523 LyXParagraph * LyXText::SetLayout(BufferView * bview,
524 LyXCursor & cur, LyXCursor & sstart_cur,
525 LyXCursor & send_cur,
526 LyXTextClass::size_type layout)
528 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
529 LyXParagraph * undoendpar = endpar;
531 if (endpar && endpar->GetDepth()) {
532 while (endpar && endpar->GetDepth()) {
533 endpar = endpar->LastPhysicalPar()->Next();
537 endpar = endpar->Next(); // because of parindents etc.
540 SetUndo(bview->buffer(), Undo::EDIT,
541 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
544 /* ok we have a selection. This is always between sstart_cur
545 * and sel_end cursor */
548 LyXLayout const & lyxlayout =
549 textclasslist.Style(bview->buffer()->params.textclass, layout);
551 while (cur.par() != send_cur.par()) {
552 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
553 cur.par()->SetLayout(bview->buffer()->params, layout);
554 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
555 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
556 fppar->added_space_top = lyxlayout.fill_top ?
557 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
558 fppar->added_space_bottom = lyxlayout.fill_bottom ?
559 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
560 if (lyxlayout.margintype == MARGIN_MANUAL)
561 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
562 if (lyxlayout.labeltype != LABEL_BIBLIO
564 delete fppar->bibkey;
568 cur.par(cur.par()->Next());
570 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
571 cur.par()->SetLayout(bview->buffer()->params, layout);
572 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
573 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
574 fppar->added_space_top = lyxlayout.fill_top ?
575 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
576 fppar->added_space_bottom = lyxlayout.fill_bottom ?
577 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
578 if (lyxlayout.margintype == MARGIN_MANUAL)
579 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
580 if (lyxlayout.labeltype != LABEL_BIBLIO
582 delete fppar->bibkey;
589 // set layout over selection and make a total rebreak of those paragraphs
590 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
593 tmpcursor = cursor; /* store the current cursor */
595 #ifdef USE_OLD_SET_LAYOUT
596 // if there is no selection just set the layout
597 // of the current paragraph */
599 sel_start_cursor = cursor; // dummy selection
600 sel_end_cursor = cursor;
603 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
604 LyXParagraph * undoendpar = endpar;
606 if (endpar && endpar->GetDepth()) {
607 while (endpar && endpar->GetDepth()) {
608 endpar = endpar->LastPhysicalPar()->Next();
613 endpar = endpar->Next(); // because of parindents etc.
617 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
620 /* ok we have a selection. This is always between sel_start_cursor
621 * and sel_end cursor */
622 cursor = sel_start_cursor;
624 LyXLayout const & lyxlayout =
625 textclasslist.Style(bview->buffer()->params.textclass, layout);
627 while (cursor.par() != sel_end_cursor.par()) {
628 if (cursor.par()->footnoteflag ==
629 sel_start_cursor.par()->footnoteflag) {
630 cursor.par()->SetLayout(layout);
631 MakeFontEntriesLayoutSpecific(cursor.par());
632 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
633 fppar->added_space_top = lyxlayout.fill_top ?
634 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
635 fppar->added_space_bottom = lyxlayout.fill_bottom ?
636 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
637 if (lyxlayout.margintype == MARGIN_MANUAL)
638 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
639 if (lyxlayout.labeltype != LABEL_BIBLIO
641 delete fppar->bibkey;
645 cursor.par() = cursor.par()->Next();
647 if (cursor.par()->footnoteflag ==
648 sel_start_cursor.par()->footnoteflag) {
649 cursor.par()->SetLayout(layout);
650 MakeFontEntriesLayoutSpecific(cursor.par());
651 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
652 fppar->added_space_top = lyxlayout.fill_top ?
653 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
654 fppar->added_space_bottom = lyxlayout.fill_bottom ?
655 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
656 if (lyxlayout.margintype == MARGIN_MANUAL)
657 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
658 if (lyxlayout.labeltype != LABEL_BIBLIO
660 delete fppar->bibkey;
665 // if there is no selection just set the layout
666 // of the current paragraph */
668 sel_start_cursor = cursor; // dummy selection
669 sel_end_cursor = cursor;
672 endpar = SetLayout(bview, cursor, sel_start_cursor,
673 sel_end_cursor, layout);
675 RedoParagraphs(bview, sel_start_cursor, endpar);
677 // we have to reset the selection, because the
678 // geometry could have changed */
679 SetCursor(bview, sel_start_cursor.par(),
680 sel_start_cursor.pos(), false);
682 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
684 UpdateCounters(bview, cursor.row());
687 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
691 // increment depth over selection and
692 // make a total rebreak of those paragraphs
693 void LyXText::IncDepth(BufferView * bview)
695 // If there is no selection, just use the current paragraph
697 sel_start_cursor = cursor; // dummy selection
698 sel_end_cursor = cursor;
701 // We end at the next paragraph with depth 0
702 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
703 LyXParagraph * undoendpar = endpar;
705 if (endpar && endpar->GetDepth()) {
706 while (endpar && endpar->GetDepth()) {
707 endpar = endpar->LastPhysicalPar()->Next();
712 endpar = endpar->Next(); // because of parindents etc.
715 SetUndo(bview->buffer(), Undo::EDIT,
717 .par()->ParFromPos(sel_start_cursor.pos())->previous,
720 LyXCursor tmpcursor = cursor; // store the current cursor
722 // ok we have a selection. This is always between sel_start_cursor
723 // and sel_end cursor
724 cursor = sel_start_cursor;
726 bool anything_changed = false;
729 // NOTE: you can't change the depth of a bibliography entry
730 if (cursor.par()->footnoteflag ==
731 sel_start_cursor.par()->footnoteflag
732 && textclasslist.Style(bview->buffer()->params.textclass,
733 cursor.par()->GetLayout()
734 ).labeltype != LABEL_BIBLIO) {
735 LyXParagraph * prev =
736 cursor.par()->FirstPhysicalPar()->Previous();
738 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
739 || (prev->GetDepth() == cursor.par()->GetDepth()
740 && textclasslist.Style(bview->buffer()->params.textclass,
741 prev->GetLayout()).isEnvironment()))) {
742 cursor.par()->FirstPhysicalPar()->depth++;
743 anything_changed = true;
746 if (cursor.par() == sel_end_cursor.par())
748 cursor.par(cursor.par()->Next());
751 // if nothing changed set all depth to 0
752 if (!anything_changed) {
753 cursor = sel_start_cursor;
754 while (cursor.par() != sel_end_cursor.par()) {
755 cursor.par()->FirstPhysicalPar()->depth = 0;
756 cursor.par(cursor.par()->Next());
758 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
759 cursor.par()->FirstPhysicalPar()->depth = 0;
762 RedoParagraphs(bview, sel_start_cursor, endpar);
764 // we have to reset the selection, because the
765 // geometry could have changed
766 SetCursor(bview, sel_start_cursor.par(),
767 sel_start_cursor.pos());
769 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
770 UpdateCounters(bview, cursor.row());
773 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
777 // decrement depth over selection and
778 // make a total rebreak of those paragraphs
779 void LyXText::DecDepth(BufferView * bview)
781 // if there is no selection just set the layout
782 // of the current paragraph
784 sel_start_cursor = cursor; // dummy selection
785 sel_end_cursor = cursor;
788 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
789 LyXParagraph * undoendpar = endpar;
791 if (endpar && endpar->GetDepth()) {
792 while (endpar && endpar->GetDepth()) {
793 endpar = endpar->LastPhysicalPar()->Next();
798 endpar = endpar->Next(); // because of parindents etc.
801 SetUndo(bview->buffer(), Undo::EDIT,
803 .par()->ParFromPos(sel_start_cursor.pos())->previous,
806 LyXCursor tmpcursor = cursor; // store the current cursor
808 // ok we have a selection. This is always between sel_start_cursor
809 // and sel_end cursor
810 cursor = sel_start_cursor;
813 if (cursor.par()->footnoteflag ==
814 sel_start_cursor.par()->footnoteflag) {
815 if (cursor.par()->FirstPhysicalPar()->depth)
816 cursor.par()->FirstPhysicalPar()->depth--;
818 if (cursor.par() == sel_end_cursor.par())
820 cursor.par(cursor.par()->Next());
823 RedoParagraphs(bview, sel_start_cursor, endpar);
825 // we have to reset the selection, because the
826 // geometry could have changed
827 SetCursor(bview, sel_start_cursor.par(),
828 sel_start_cursor.pos());
830 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
831 UpdateCounters(bview, cursor.row());
834 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
838 // set font over selection and make a total rebreak of those paragraphs
839 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
841 // if there is no selection just set the current_font
843 // Determine basis font
845 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
847 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
849 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
850 // Update current font
851 real_current_font.update(font,
852 bview->buffer()->params.language_info,
855 // Reduce to implicit settings
856 current_font = real_current_font;
857 current_font.reduce(layoutfont);
858 // And resolve it completely
859 real_current_font.realize(layoutfont);
863 LyXCursor tmpcursor = cursor; // store the current cursor
865 // ok we have a selection. This is always between sel_start_cursor
866 // and sel_end cursor
868 SetUndo(bview->buffer(), Undo::EDIT,
869 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
870 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
871 cursor = sel_start_cursor;
872 while (cursor.par() != sel_end_cursor.par() ||
873 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
874 && cursor.pos() < sel_end_cursor.pos()))
876 if (cursor.pos() < cursor.par()->Last()
877 && cursor.par()->footnoteflag
878 == sel_start_cursor.par()->footnoteflag) {
879 // an open footnote should behave
881 LyXFont newfont = GetFont(bview->buffer(),
882 cursor.par(), cursor.pos());
884 bview->buffer()->params.language_info,
886 SetCharFont(bview->buffer(),
887 cursor.par(), cursor.pos(), newfont);
888 cursor.pos(cursor.pos() + 1);
891 cursor.par(cursor.par()->Next());
895 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
897 // we have to reset the selection, because the
898 // geometry could have changed
899 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
901 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
904 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
905 tmpcursor.boundary());
909 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
911 Row * tmprow = cur.row();
912 long y = cur.y() - tmprow->baseline();
914 SetHeightOfRow(bview, tmprow);
915 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
916 // find the first row of the paragraph
917 if (first_phys_par != tmprow->par())
918 while (tmprow->previous()
919 && tmprow->previous()->par() != first_phys_par) {
920 tmprow = tmprow->previous();
921 y -= tmprow->height();
922 SetHeightOfRow(bview, tmprow);
924 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
925 tmprow = tmprow->previous();
926 y -= tmprow->height();
927 SetHeightOfRow(bview, tmprow);
930 // we can set the refreshing parameters now
931 status = LyXText::NEED_MORE_REFRESH;
933 refresh_row = tmprow;
934 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
938 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
940 Row * tmprow = cur.row();
942 long y = cur.y() - tmprow->baseline();
943 SetHeightOfRow(bview, tmprow);
944 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
945 // find the first row of the paragraph
946 if (first_phys_par != tmprow->par())
947 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
948 tmprow = tmprow->previous();
949 y -= tmprow->height();
951 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
952 tmprow = tmprow->previous();
953 y -= tmprow->height();
956 // we can set the refreshing parameters now
957 if (status == LyXText::UNCHANGED || y < refresh_y) {
959 refresh_row = tmprow;
961 status = LyXText::NEED_MORE_REFRESH;
962 SetCursor(bview, cur.par(), cur.pos());
966 /* deletes and inserts again all paragaphs between the cursor
967 * and the specified par
968 * This function is needed after SetLayout and SetFont etc. */
969 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
970 LyXParagraph const * endpar) const
973 LyXParagraph * tmppar = 0, * first_phys_par = 0;
975 Row * tmprow = cur.row();
977 long y = cur.y() - tmprow->baseline();
979 if (!tmprow->previous()){
980 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
982 first_phys_par = tmprow->par()->FirstPhysicalPar();
983 // find the first row of the paragraph
984 if (first_phys_par != tmprow->par())
985 while (tmprow->previous() &&
986 (tmprow->previous()->par() != first_phys_par)) {
987 tmprow = tmprow->previous();
988 y -= tmprow->height();
990 while (tmprow->previous()
991 && tmprow->previous()->par() == first_phys_par) {
992 tmprow = tmprow->previous();
993 y -= tmprow->height();
997 // we can set the refreshing parameters now
998 status = LyXText::NEED_MORE_REFRESH;
1000 refresh_row = tmprow->previous(); /* the real refresh row will
1001 be deleted, so I store
1002 the previous here */
1005 tmppar = tmprow->next()->par();
1008 while (tmppar != endpar) {
1009 RemoveRow(tmprow->next());
1011 tmppar = tmprow->next()->par();
1016 // remove the first one
1017 tmprow2 = tmprow; /* this is because tmprow->previous()
1019 tmprow = tmprow->previous();
1022 tmppar = first_phys_par;
1026 InsertParagraph(bview, tmppar, tmprow);
1029 while (tmprow->next() && tmprow->next()->par() == tmppar)
1030 tmprow = tmprow->next();
1031 tmppar = tmppar->Next();
1033 } while (tmppar != endpar);
1035 // this is because of layout changes
1037 refresh_y -= refresh_row->height();
1038 SetHeightOfRow(bview, refresh_row);
1040 refresh_row = firstrow;
1042 SetHeightOfRow(bview, refresh_row);
1045 if (tmprow && tmprow->next())
1046 SetHeightOfRow(bview, tmprow->next());
1050 bool LyXText::FullRebreak(BufferView * bview)
1056 if (need_break_row) {
1057 BreakAgain(bview, need_break_row);
1065 /* important for the screen */
1068 /* the cursor set functions have a special mechanism. When they
1069 * realize, that you left an empty paragraph, they will delete it.
1070 * They also delete the corresponding row */
1072 // need the selection cursor:
1073 void LyXText::SetSelection()
1076 last_sel_cursor = sel_cursor;
1077 sel_start_cursor = sel_cursor;
1078 sel_end_cursor = sel_cursor;
1083 // first the toggling area
1084 if (cursor.y() < last_sel_cursor.y()
1085 || (cursor.y() == last_sel_cursor.y()
1086 && cursor.x() < last_sel_cursor.x())) {
1087 toggle_end_cursor = last_sel_cursor;
1088 toggle_cursor = cursor;
1090 toggle_end_cursor = cursor;
1091 toggle_cursor = last_sel_cursor;
1094 last_sel_cursor = cursor;
1096 // and now the whole selection
1098 if (sel_cursor.par() == cursor.par())
1099 if (sel_cursor.pos() < cursor.pos()) {
1100 sel_end_cursor = cursor;
1101 sel_start_cursor = sel_cursor;
1103 sel_end_cursor = sel_cursor;
1104 sel_start_cursor = cursor;
1106 else if (sel_cursor.y() < cursor.y() ||
1107 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1108 sel_end_cursor = cursor;
1109 sel_start_cursor = sel_cursor;
1112 sel_end_cursor = sel_cursor;
1113 sel_start_cursor = cursor;
1116 // a selection with no contents is not a selection
1117 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1118 sel_start_cursor.pos() == sel_end_cursor.pos())
1123 string LyXText::selectionAsString(Buffer const * buffer) const
1125 if (!selection) return string();
1128 // Special handling if the whole selection is within one paragraph
1129 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1130 result += sel_start_cursor.par()->String(buffer,
1131 sel_start_cursor.pos(),
1132 sel_end_cursor.pos());
1136 // The selection spans more than one paragraph
1138 // First paragraph in selection
1139 result += sel_start_cursor.par()->String(buffer,
1140 sel_start_cursor.pos(),
1141 sel_start_cursor.par()->Last())
1144 // The paragraphs in between (if any)
1145 LyXCursor tmpcur(sel_start_cursor);
1146 tmpcur.par(tmpcur.par()->Next());
1147 while (tmpcur.par() != sel_end_cursor.par()) {
1148 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1149 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1152 // Last paragraph in selection
1153 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1159 void LyXText::ClearSelection() const
1166 void LyXText::CursorHome(BufferView * bview) const
1168 SetCursor(bview, cursor.par(), cursor.row()->pos());
1172 void LyXText::CursorEnd(BufferView * bview) const
1174 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1175 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1177 if (cursor.par()->Last() &&
1178 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1179 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1180 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1182 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1185 if (cursor.par()->table) {
1186 int cell = NumberOfCell(cursor.par(), cursor.pos());
1187 if (cursor.par()->table->RowHasContRow(cell) &&
1188 cursor.par()->table->CellHasContRow(cell)<0) {
1189 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1190 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1192 if (cursor.par()->Last() &&
1193 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1194 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1195 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1197 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1205 void LyXText::CursorTop(BufferView * bview) const
1207 while (cursor.par()->Previous())
1208 cursor.par(cursor.par()->Previous());
1209 SetCursor(bview, cursor.par(), 0);
1213 void LyXText::CursorBottom(BufferView * bview) const
1215 while (cursor.par()->Next())
1216 cursor.par(cursor.par()->Next());
1217 SetCursor(bview, cursor.par(), cursor.par()->Last());
1221 /* returns a pointer to the row near the specified y-coordinate
1222 * (relative to the whole text). y is set to the real beginning
1224 Row * LyXText::GetRowNearY(long & y) const
1226 Row * tmprow = firstrow;
1229 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1230 tmpy += tmprow->height();
1231 tmprow = tmprow->next();
1234 y = tmpy; // return the real y
1239 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1241 // If the mask is completely neutral, tell user
1242 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1243 // Could only happen with user style
1244 bview->owner()->getMiniBuffer()
1245 ->Set(_("No font change defined. Use Character under"
1246 " the Layout menu to define font change."));
1250 // Try implicit word selection
1251 // If there is a change in the language the implicit word selection
1253 LyXCursor resetCursor = cursor;
1254 bool implicitSelection = (font.language() == ignore_language)
1255 ? SelectWordWhenUnderCursor(bview) : false;
1258 SetFont(bview, font, toggleall);
1260 /* Implicit selections are cleared afterwards and cursor is set to the
1261 original position. */
1262 if (implicitSelection) {
1264 cursor = resetCursor;
1265 SetCursor(bview, cursor.par(), cursor.pos());
1266 sel_cursor = cursor;
1271 LyXParagraph::size_type
1272 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1274 if (textclasslist.Style(buf->params.textclass,
1275 par->GetLayout()).labeltype != LABEL_MANUAL)
1278 return par->BeginningOfMainBody();
1282 /* if there is a selection, reset every environment you can find
1283 * in the selection, otherwise just the environment you are in */
1284 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1286 LyXParagraph * tmppar, * firsttmppar;
1290 /* is is only allowed, if the cursor is IN an open footnote.
1291 * Otherwise it is too dangerous */
1292 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1295 SetUndo(bview->buffer(), Undo::FINISH,
1296 cursor.par()->PreviousBeforeFootnote()->previous,
1297 cursor.par()->NextAfterFootnote()->next);
1299 /* ok, move to the beginning of the footnote. */
1300 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1301 cursor.par(cursor.par()->Previous());
1303 SetCursor(bview, cursor.par(), cursor.par()->Last());
1304 /* this is just faster than using CursorLeft(); */
1306 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1307 tmppar = firsttmppar;
1308 /* tmppar is now the paragraph right before the footnote */
1310 bool first_footnote_par_is_not_empty = tmppar->next->size();
1313 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1314 tmppar = tmppar->next; /* I use next instead of Next(),
1315 * because there cannot be any
1316 * footnotes in a footnote
1318 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1320 /* remember the captions and empty paragraphs */
1321 if ((textclasslist.Style(bview->buffer()->params.textclass,
1322 tmppar->GetLayout())
1323 .labeltype == LABEL_SENSITIVE)
1325 tmppar->SetLayout(bview->buffer()->params, 0);
1328 // now we will paste the ex-footnote, if the layouts allow it
1329 // first restore the layout of the paragraph right behind
1332 tmppar->next->MakeSameLayout(cursor.par());
1335 if ((!tmppar->GetLayout() && !tmppar->table)
1337 && (!tmppar->Next()->Last()
1338 || tmppar->Next()->HasSameLayout(tmppar)))) {
1339 if (tmppar->Next()->Last()
1340 && tmppar->Next()->IsLineSeparator(0))
1341 tmppar->Next()->Erase(0);
1342 tmppar->PasteParagraph(bview->buffer()->params);
1345 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1346 * by the pasting of the beginning */
1348 /* then the beginning */
1349 /* if there is no space between the text and the footnote, so we insert
1351 * (only if the previous par and the footnotepar are not empty!) */
1352 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1353 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1354 if (firsttmppar->size()
1355 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1356 && first_footnote_par_is_not_empty) {
1357 firsttmppar->next->InsertChar(0, ' ');
1359 firsttmppar->PasteParagraph(bview->buffer()->params);
1362 /* now redo the paragaphs */
1363 RedoParagraphs(bview, cursor, tmppar);
1365 SetCursor(bview, cursor.par(), cursor.pos());
1367 /* sometimes it can happen, that there is a counter change */
1368 Row * row = cursor.row();
1369 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1371 UpdateCounters(bview, row);
1378 /* the DTP switches for paragraphs. LyX will store them in the
1379 * first physicla paragraph. When a paragraph is broken, the top settings
1380 * rest, the bottom settings are given to the new one. So I can make shure,
1381 * they do not duplicate themself and you cannnot make dirty things with
1384 void LyXText::SetParagraph(BufferView * bview,
1385 bool line_top, bool line_bottom,
1386 bool pagebreak_top, bool pagebreak_bottom,
1387 VSpace const & space_top,
1388 VSpace const & space_bottom,
1390 string labelwidthstring,
1393 LyXCursor tmpcursor = cursor;
1395 sel_start_cursor = cursor;
1396 sel_end_cursor = cursor;
1399 // make sure that the depth behind the selection are restored, too
1400 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1401 LyXParagraph * undoendpar = endpar;
1403 if (endpar && endpar->GetDepth()) {
1404 while (endpar && endpar->GetDepth()) {
1405 endpar = endpar->LastPhysicalPar()->Next();
1406 undoendpar = endpar;
1410 endpar = endpar->Next(); // because of parindents etc.
1413 SetUndo(bview->buffer(), Undo::EDIT,
1415 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1419 LyXParagraph * tmppar = sel_end_cursor.par();
1420 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1421 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1422 status = LyXText::NEED_MORE_REFRESH;
1423 refresh_row = cursor.row();
1424 refresh_y = cursor.y() - cursor.row()->baseline();
1425 if (cursor.par()->footnoteflag ==
1426 sel_start_cursor.par()->footnoteflag) {
1427 cursor.par()->line_top = line_top;
1428 cursor.par()->line_bottom = line_bottom;
1429 cursor.par()->pagebreak_top = pagebreak_top;
1430 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1431 cursor.par()->added_space_top = space_top;
1432 cursor.par()->added_space_bottom = space_bottom;
1433 // does the layout allow the new alignment?
1434 if (align == LYX_ALIGN_LAYOUT)
1435 align = textclasslist
1436 .Style(bview->buffer()->params.textclass,
1437 cursor.par()->GetLayout()).align;
1438 if (align & textclasslist
1439 .Style(bview->buffer()->params.textclass,
1440 cursor.par()->GetLayout()).alignpossible) {
1441 if (align == textclasslist
1442 .Style(bview->buffer()->params.textclass,
1443 cursor.par()->GetLayout()).align)
1444 cursor.par()->align = LYX_ALIGN_LAYOUT;
1446 cursor.par()->align = align;
1448 cursor.par()->SetLabelWidthString(labelwidthstring);
1449 cursor.par()->noindent = noindent;
1452 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1455 RedoParagraphs(bview, sel_start_cursor, endpar);
1458 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1459 sel_cursor = cursor;
1460 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1462 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1466 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1468 char const * widthp,
1469 int alignment, bool hfill,
1470 bool start_minipage)
1472 LyXCursor tmpcursor = cursor;
1473 LyXParagraph * tmppar;
1475 sel_start_cursor = cursor;
1476 sel_end_cursor = cursor;
1479 // make sure that the depth behind the selection are restored, too
1480 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1481 LyXParagraph * undoendpar = endpar;
1483 if (endpar && endpar->GetDepth()) {
1484 while (endpar && endpar->GetDepth()) {
1485 endpar = endpar->LastPhysicalPar()->Next();
1486 undoendpar = endpar;
1490 endpar = endpar->Next(); // because of parindents etc.
1493 SetUndo(bview->buffer(), Undo::EDIT,
1495 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1498 tmppar = sel_end_cursor.par();
1499 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1500 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1501 status = LyXText::NEED_MORE_REFRESH;
1502 refresh_row = cursor.row();
1503 refresh_y = cursor.y() - cursor.row()->baseline();
1504 if (cursor.par()->footnoteflag ==
1505 sel_start_cursor.par()->footnoteflag) {
1506 if (type == LyXParagraph::PEXTRA_NONE) {
1507 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1508 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1509 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1512 cursor.par()->SetPExtraType(bview->buffer()->params,
1513 type, width, widthp);
1514 cursor.par()->pextra_hfill = hfill;
1515 cursor.par()->pextra_start_minipage = start_minipage;
1516 cursor.par()->pextra_alignment = alignment;
1519 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1521 RedoParagraphs(bview, sel_start_cursor, endpar);
1523 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1524 sel_cursor = cursor;
1525 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1527 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1531 char loweralphaCounter(int n)
1533 if (n < 1 || n > 26)
1539 char alphaCounter(int n)
1541 if (n < 1 || n > 26)
1547 char hebrewCounter(int n)
1549 static const char hebrew[22] = {
1550 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1551 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1552 '÷', 'ø', 'ù', 'ú'
1554 if (n < 1 || n > 22)
1560 static char const * romanCounter(int n)
1562 static char const * roman[20] = {
1563 "i", "ii", "iii", "iv", "v",
1564 "vi", "vii", "viii", "ix", "x",
1565 "xi", "xii", "xiii", "xiv", "xv",
1566 "xvi", "xvii", "xviii", "xix", "xx"
1568 if (n < 1 || n > 20)
1574 // set the counter of a paragraph. This includes the labels
1575 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1577 // this is only relevant for the beginning of paragraph
1578 par = par->FirstPhysicalPar();
1580 LyXLayout const & layout =
1581 textclasslist.Style(buf->params.textclass,
1584 LyXTextClass const & textclass =
1585 textclasslist.TextClass(buf->params.textclass);
1587 /* copy the prev-counters to this one, unless this is the start of a
1588 footnote or of a bibliography or the very first paragraph */
1590 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1591 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1592 && par->footnotekind == LyXParagraph::FOOTNOTE)
1593 && !(textclasslist.Style(buf->params.textclass,
1594 par->Previous()->GetLayout()
1595 ).labeltype != LABEL_BIBLIO
1596 && layout.labeltype == LABEL_BIBLIO)) {
1597 for (int i = 0; i < 10; ++i) {
1598 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1600 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1601 if (!par->appendix && par->start_of_appendix){
1602 par->appendix = true;
1603 for (int i = 0; i < 10; ++i) {
1604 par->setCounter(i, 0);
1607 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1608 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1611 for (int i = 0; i < 10; ++i) {
1612 par->setCounter(i, 0);
1614 par->appendix = par->start_of_appendix;
1619 // if this is an open marginnote and this is the first
1620 // entry in the marginnote and the enclosing
1621 // environment is an enum/item then correct for the
1622 // LaTeX behaviour (ARRae)
1623 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1624 && par->footnotekind == LyXParagraph::MARGIN
1626 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1627 && (par->PreviousBeforeFootnote()
1628 && textclasslist.Style(buf->params.textclass,
1629 par->PreviousBeforeFootnote()->GetLayout()
1630 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1631 // Any itemize or enumerate environment in a marginnote
1632 // that is embedded in an itemize or enumerate
1633 // paragraph is seen by LaTeX as being at a deeper
1634 // level within that enclosing itemization/enumeration
1635 // even if there is a "standard" layout at the start of
1641 /* Maybe we have to increment the enumeration depth.
1642 * BUT, enumeration in a footnote is considered in isolation from its
1643 * surrounding paragraph so don't increment if this is the
1644 * first line of the footnote
1645 * AND, bibliographies can't have their depth changed ie. they
1646 * are always of depth 0
1649 && par->Previous()->GetDepth() < par->GetDepth()
1650 && textclasslist.Style(buf->params.textclass,
1651 par->Previous()->GetLayout()
1652 ).labeltype == LABEL_COUNTER_ENUMI
1653 && par->enumdepth < 3
1654 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1655 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1656 && par->footnotekind == LyXParagraph::FOOTNOTE)
1657 && layout.labeltype != LABEL_BIBLIO) {
1661 /* Maybe we have to decrement the enumeration depth, see note above */
1663 && par->Previous()->GetDepth() > par->GetDepth()
1664 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1665 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1666 && par->footnotekind == LyXParagraph::FOOTNOTE)
1667 && layout.labeltype != LABEL_BIBLIO) {
1668 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1669 par->setCounter(6 + par->enumdepth,
1670 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1671 /* reset the counters.
1672 * A depth change is like a breaking layout
1674 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1675 par->setCounter(i, 0);
1678 if (!par->labelstring.empty()) {
1679 par->labelstring.erase();
1682 if (layout.margintype == MARGIN_MANUAL) {
1683 if (par->labelwidthstring.empty()) {
1684 par->SetLabelWidthString(layout.labelstring());
1687 par->SetLabelWidthString(string());
1690 /* is it a layout that has an automatic label ? */
1691 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1693 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1694 if (i >= 0 && i<= buf->params.secnumdepth) {
1695 par->incCounter(i); // increment the counter
1697 // Is there a label? Useful for Chapter layout
1698 if (!par->appendix){
1699 if (!layout.labelstring().empty())
1700 par->labelstring = layout.labelstring();
1702 par->labelstring.erase();
1704 if (!layout.labelstring_appendix().empty())
1705 par->labelstring = layout.labelstring_appendix();
1707 par->labelstring.erase();
1711 std::ostringstream s;
1715 if (!par->appendix) {
1716 switch (2 * LABEL_FIRST_COUNTER -
1717 textclass.maxcounter() + i) {
1718 case LABEL_COUNTER_CHAPTER:
1719 s << par->getCounter(i);
1721 case LABEL_COUNTER_SECTION:
1722 s << par->getCounter(i - 1) << '.'
1723 << par->getCounter(i);
1725 case LABEL_COUNTER_SUBSECTION:
1726 s << par->getCounter(i - 2) << '.'
1727 << par->getCounter(i - 1) << '.'
1728 << par->getCounter(i);
1730 case LABEL_COUNTER_SUBSUBSECTION:
1731 s << par->getCounter(i - 3) << '.'
1732 << par->getCounter(i - 2) << '.'
1733 << par->getCounter(i - 1) << '.'
1734 << par->getCounter(i);
1737 case LABEL_COUNTER_PARAGRAPH:
1738 s << par->getCounter(i - 4) << '.'
1739 << par->getCounter(i - 3) << '.'
1740 << par->getCounter(i - 2) << '.'
1741 << par->getCounter(i - 1) << '.'
1742 << par->getCounter(i);
1744 case LABEL_COUNTER_SUBPARAGRAPH:
1745 s << par->getCounter(i - 5) << '.'
1746 << par->getCounter(i - 4) << '.'
1747 << par->getCounter(i - 3) << '.'
1748 << par->getCounter(i - 2) << '.'
1749 << par->getCounter(i - 1) << '.'
1750 << par->getCounter(i);
1754 s << par->getCounter(i) << '.';
1757 } else { // appendix
1758 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1759 case LABEL_COUNTER_CHAPTER:
1760 if (par->isRightToLeftPar(buf->params))
1761 s << hebrewCounter(par->getCounter(i));
1763 s << alphaCounter(par->getCounter(i));
1765 case LABEL_COUNTER_SECTION:
1766 if (par->isRightToLeftPar(buf->params))
1767 s << hebrewCounter(par->getCounter(i - 1));
1769 s << alphaCounter(par->getCounter(i - 1));
1772 << par->getCounter(i);
1775 case LABEL_COUNTER_SUBSECTION:
1776 if (par->isRightToLeftPar(buf->params))
1777 s << hebrewCounter(par->getCounter(i - 2));
1779 s << alphaCounter(par->getCounter(i - 2));
1782 << par->getCounter(i-1) << '.'
1783 << par->getCounter(i);
1786 case LABEL_COUNTER_SUBSUBSECTION:
1787 if (par->isRightToLeftPar(buf->params))
1788 s << hebrewCounter(par->getCounter(i-3));
1790 s << alphaCounter(par->getCounter(i-3));
1793 << par->getCounter(i-2) << '.'
1794 << par->getCounter(i-1) << '.'
1795 << par->getCounter(i);
1798 case LABEL_COUNTER_PARAGRAPH:
1799 if (par->isRightToLeftPar(buf->params))
1800 s << hebrewCounter(par->getCounter(i-4));
1802 s << alphaCounter(par->getCounter(i-4));
1805 << par->getCounter(i-3) << '.'
1806 << par->getCounter(i-2) << '.'
1807 << par->getCounter(i-1) << '.'
1808 << par->getCounter(i);
1811 case LABEL_COUNTER_SUBPARAGRAPH:
1812 if (par->isRightToLeftPar(buf->params))
1813 s << hebrewCounter(par->getCounter(i-5));
1815 s << alphaCounter(par->getCounter(i-5));
1818 << par->getCounter(i-4) << '.'
1819 << par->getCounter(i-3) << '.'
1820 << par->getCounter(i-2) << '.'
1821 << par->getCounter(i-1) << '.'
1822 << par->getCounter(i);
1826 // Can this ever be reached? And in the
1827 // case it is, how can this be correct?
1829 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1835 par->labelstring += s.str().c_str();
1836 // We really want to remove the c_str as soon as
1840 char * tmps = s.str();
1841 par->labelstring += tmps;
1845 for (i++; i < 10; ++i) {
1846 // reset the following counters
1847 par->setCounter(i, 0);
1849 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1850 for (i++; i < 10; ++i) {
1851 // reset the following counters
1852 par->setCounter(i, 0);
1854 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1855 par->incCounter(i + par->enumdepth);
1856 int number = par->getCounter(i + par->enumdepth);
1859 std::ostringstream s;
1863 switch (par->enumdepth) {
1865 if (par->isRightToLeftPar(buf->params))
1867 << hebrewCounter(number)
1871 << loweralphaCounter(number)
1875 if (par->isRightToLeftPar(buf->params))
1876 s << '.' << romanCounter(number);
1878 s << romanCounter(number) << '.';
1881 if (par->isRightToLeftPar(buf->params))
1883 << alphaCounter(number);
1885 s << alphaCounter(number)
1889 if (par->isRightToLeftPar(buf->params))
1896 par->labelstring = s.str().c_str();
1897 // we really want to get rid of that c_str()
1900 char * tmps = s.str();
1901 par->labelstring = tmps;
1905 for (i += par->enumdepth + 1; i < 10; ++i)
1906 par->setCounter(i, 0); /* reset the following counters */
1909 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1910 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1912 int number = par->getCounter(i);
1914 par->bibkey = new InsetBibKey();
1915 par->bibkey->setCounter(number);
1916 par->labelstring = layout.labelstring();
1918 // In biblio should't be following counters but...
1920 string s = layout.labelstring();
1922 // the caption hack:
1924 if (layout.labeltype == LABEL_SENSITIVE) {
1925 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1926 && (par->footnotekind == LyXParagraph::FIG
1927 || par->footnotekind == LyXParagraph::WIDE_FIG))
1928 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1929 ? ":øåéà " : "Figure:";
1930 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1931 && (par->footnotekind == LyXParagraph::TAB
1932 || par->footnotekind == LyXParagraph::WIDE_TAB))
1933 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1934 ? ":äìáè" : "Table:";
1935 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1936 && par->footnotekind == LyXParagraph::ALGORITHM)
1937 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1938 ? ":Ãúéøåâìà " : "Algorithm:";
1940 /* par->SetLayout(0);
1941 s = layout->labelstring; */
1942 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1943 ? " :úåòîùî øñç" : "Senseless: ";
1946 par->labelstring = s;
1948 /* reset the enumeration counter. They are always resetted
1949 * when there is any other layout between */
1950 for (int i = 6 + par->enumdepth; i < 10; ++i)
1951 par->setCounter(i, 0);
1956 /* Updates all counters BEHIND the row. Changed paragraphs
1957 * with a dynamic left margin will be rebroken. */
1958 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1966 if (row->par()->next
1967 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1968 par = row->par()->LastPhysicalPar()->Next();
1970 par = row->par()->next;
1975 while (row->par() != par)
1978 SetCounter(bview->buffer(), par);
1980 /* now check for the headline layouts. remember that they
1981 * have a dynamic left margin */
1983 && ( textclasslist.Style(bview->buffer()->params.textclass,
1984 par->layout).margintype == MARGIN_DYNAMIC
1985 || textclasslist.Style(bview->buffer()->params.textclass,
1986 par->layout).labeltype == LABEL_SENSITIVE)
1989 /* Rebreak the paragraph */
1990 RemoveParagraph(row);
1991 AppendParagraph(bview, row);
1993 /* think about the damned open footnotes! */
1994 while (par->Next() &&
1995 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1996 || par->Next()->IsDummy())){
1998 if (par->IsDummy()) {
1999 while (row->par() != par)
2001 RemoveParagraph(row);
2002 AppendParagraph(bview, row);
2007 par = par->LastPhysicalPar()->Next();
2013 /* insets an inset. */
2014 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2016 if (!cursor.par()->InsertInsetAllowed(inset))
2018 SetUndo(bview->buffer(), Undo::INSERT,
2019 cursor.par()->ParFromPos(cursor.pos())->previous,
2020 cursor.par()->ParFromPos(cursor.pos())->next);
2021 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2022 cursor.par()->InsertInset(cursor.pos(), inset);
2023 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2024 * The character will not be inserted a
2029 void LyXText::copyEnvironmentType()
2031 copylayouttype = cursor.par()->GetLayout();
2035 void LyXText::pasteEnvironmentType(BufferView * bview)
2037 SetLayout(bview, copylayouttype);
2041 void LyXText::CutSelection(BufferView * bview, bool doclear)
2043 // Stuff what we got on the clipboard. Even if there is no selection.
2045 // There is a problem with having the stuffing here in that the
2046 // larger the selection the slower LyX will get. This can be
2047 // solved by running the line below only when the selection has
2048 // finished. The solution used currently just works, to make it
2049 // faster we need to be more clever and probably also have more
2050 // calls to stuffClipboard. (Lgb)
2051 bview->stuffClipboard(selectionAsString(bview->buffer()));
2053 // This doesn't make sense, if there is no selection
2057 // OK, we have a selection. This is always between sel_start_cursor
2058 // and sel_end cursor
2059 LyXParagraph * tmppar;
2061 // Check whether there are half footnotes in the selection
2062 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2063 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2064 tmppar = sel_start_cursor.par();
2065 while (tmppar != sel_end_cursor.par()){
2066 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2067 WriteAlert(_("Impossible operation"),
2068 _("Don't know what to do with half floats."),
2072 tmppar = tmppar->Next();
2077 /* table stuff -- begin */
2078 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2079 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2080 WriteAlert(_("Impossible operation"),
2081 _("Don't know what to do with half tables."),
2085 sel_start_cursor.par()->table->Reinit();
2087 /* table stuff -- end */
2089 // make sure that the depth behind the selection are restored, too
2090 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2091 LyXParagraph * undoendpar = endpar;
2093 if (endpar && endpar->GetDepth()) {
2094 while (endpar && endpar->GetDepth()) {
2095 endpar = endpar->LastPhysicalPar()->Next();
2096 undoendpar = endpar;
2098 } else if (endpar) {
2099 endpar = endpar->Next(); // because of parindents etc.
2102 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2103 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2107 // there are two cases: cut only within one paragraph or
2108 // more than one paragraph
2109 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2110 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2111 // only within one paragraph
2112 endpar = sel_start_cursor.par();
2113 int pos = sel_end_cursor.pos();
2114 cap.cutSelection(sel_start_cursor.par(), &endpar,
2115 sel_start_cursor.pos(), pos,
2116 bview->buffer()->params.textclass, doclear);
2117 sel_end_cursor.pos(pos);
2119 endpar = sel_end_cursor.par();
2121 int pos = sel_end_cursor.pos();
2122 cap.cutSelection(sel_start_cursor.par(), &endpar,
2123 sel_start_cursor.pos(), pos,
2124 bview->buffer()->params.textclass, doclear);
2126 sel_end_cursor.par(endpar);
2127 sel_end_cursor.pos(pos);
2128 cursor.pos(sel_end_cursor.pos());
2130 endpar = endpar->Next();
2132 // sometimes necessary
2134 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2136 RedoParagraphs(bview, sel_start_cursor, endpar);
2139 cursor = sel_start_cursor;
2140 SetCursor(bview, cursor.par(), cursor.pos());
2141 sel_cursor = cursor;
2142 UpdateCounters(bview, cursor.row());
2146 void LyXText::CopySelection(BufferView * bview)
2148 // Stuff what we got on the clipboard. Even if there is no selection.
2150 // There is a problem with having the stuffing here in that the
2151 // larger the selection the slower LyX will get. This can be
2152 // solved by running the line below only when the selection has
2153 // finished. The solution used currently just works, to make it
2154 // faster we need to be more clever and probably also have more
2155 // calls to stuffClipboard. (Lgb)
2156 bview->stuffClipboard(selectionAsString(bview->buffer()));
2158 // this doesnt make sense, if there is no selection
2162 // ok we have a selection. This is always between sel_start_cursor
2163 // and sel_end cursor
2164 LyXParagraph * tmppar;
2166 /* check wether there are half footnotes in the selection */
2167 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2168 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2169 tmppar = sel_start_cursor.par();
2170 while (tmppar != sel_end_cursor.par()) {
2171 if (tmppar->footnoteflag !=
2172 sel_end_cursor.par()->footnoteflag) {
2173 WriteAlert(_("Impossible operation"),
2174 _("Don't know what to do"
2175 " with half floats."),
2179 tmppar = tmppar->Next();
2184 /* table stuff -- begin */
2185 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2186 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2187 WriteAlert(_("Impossible operation"),
2188 _("Don't know what to do with half tables."),
2193 /* table stuff -- end */
2196 // copy behind a space if there is one
2197 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2198 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2199 && (sel_start_cursor.par() != sel_end_cursor.par()
2200 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2201 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2205 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2206 sel_start_cursor.pos(), sel_end_cursor.pos(),
2207 bview->buffer()->params.textclass);
2211 void LyXText::PasteSelection(BufferView * bview)
2215 // this does not make sense, if there is nothing to paste
2216 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2219 SetUndo(bview->buffer(), Undo::INSERT,
2220 cursor.par()->ParFromPos(cursor.pos())->previous,
2221 cursor.par()->ParFromPos(cursor.pos())->next);
2223 LyXParagraph * endpar;
2224 LyXParagraph * actpar = cursor.par();
2226 int pos = cursor.pos();
2227 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2229 RedoParagraphs(bview, cursor, endpar);
2231 SetCursor(bview, cursor.par(), cursor.pos());
2234 sel_cursor = cursor;
2235 SetCursor(bview, actpar, pos);
2237 UpdateCounters(bview, cursor.row());
2241 // returns a pointer to the very first LyXParagraph
2242 LyXParagraph * LyXText::FirstParagraph() const
2244 return OwnerParagraph();
2248 // returns true if the specified string is at the specified position
2249 bool LyXText::IsStringInText(LyXParagraph * par,
2250 LyXParagraph::size_type pos,
2251 char const * str) const
2255 while (pos + i < par->Last() && str[i] &&
2256 str[i] == par->GetChar(pos + i)) {
2266 // sets the selection over the number of characters of string, no check!!
2267 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2269 sel_cursor = cursor;
2270 for (int i = 0; string[i]; ++i)
2276 // simple replacing. The font of the first selected character is used
2277 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2279 SetCursorParUndo(bview->buffer());
2282 if (!selection) { // create a dummy selection
2283 sel_end_cursor = cursor;
2284 sel_start_cursor = cursor;
2287 // Get font setting before we cut
2288 LyXParagraph::size_type pos = sel_end_cursor.pos();
2289 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2290 sel_start_cursor.pos());
2292 // Insert the new string
2293 for (int i = 0; str[i]; ++i) {
2294 sel_end_cursor.par()->InsertChar(pos, str[i]);
2295 sel_end_cursor.par()->SetFont(pos, font);
2299 // Cut the selection
2300 CutSelection(bview);
2306 // if the string can be found: return true and set the cursor to
2308 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2310 LyXParagraph * par = cursor.par();
2311 LyXParagraph::size_type pos = cursor.pos();
2312 while (par && !IsStringInText(par, pos, str)) {
2313 if (pos < par->Last() - 1)
2321 SetCursor(bview, par, pos);
2329 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2331 LyXParagraph * par = cursor.par();
2332 int pos = cursor.pos();
2338 // We skip empty paragraphs (Asger)
2340 par = par->Previous();
2342 pos = par->Last() - 1;
2343 } while (par && pos < 0);
2345 } while (par && !IsStringInText(par, pos, string));
2348 SetCursor(bview, par, pos);
2355 // needed to insert the selection
2356 void LyXText::InsertStringA(BufferView * bview, string const & str)
2358 LyXParagraph * par = cursor.par();
2359 LyXParagraph::size_type pos = cursor.pos();
2360 LyXParagraph::size_type a = 0;
2362 LyXParagraph * endpar = cursor.par()->Next();
2364 SetCursorParUndo(bview->buffer());
2367 textclasslist.Style(bview->buffer()->params.textclass,
2368 cursor.par()->GetLayout()).isEnvironment();
2369 // only to be sure, should not be neccessary
2372 // insert the string, don't insert doublespace
2373 string::size_type i = 0;
2374 while (i < str.length()) {
2375 if (str[i] != '\n') {
2377 && i + 1 < str.length() && str[i + 1] != ' '
2378 && pos && par->GetChar(pos - 1)!= ' ') {
2379 par->InsertChar(pos,' ');
2380 par->SetFont(pos, current_font);
2383 } else if (par->table) {
2384 if (str[i] == '\t') {
2385 while((pos < par->size()) &&
2386 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2388 if (pos < par->size())
2390 else // no more fields to fill skip the rest
2392 } else if ((str[i] != 13) &&
2393 ((str[i] & 127) >= ' ')) {
2394 par->InsertChar(pos, str[i]);
2395 par->SetFont(pos, current_font);
2399 } else if (str[i] == ' ') {
2400 InsetSpecialChar * new_inset =
2401 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2402 if (par->InsertInsetAllowed(new_inset)) {
2403 par->InsertChar(pos, LyXParagraph::META_INSET);
2404 par->SetFont(pos, current_font);
2405 par->InsertInset(pos, new_inset);
2410 } else if (str[i] == '\t') {
2411 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2412 InsetSpecialChar * new_inset =
2413 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2414 if (par->InsertInsetAllowed(new_inset)) {
2415 par->InsertChar(pos, LyXParagraph::META_INSET);
2416 par->SetFont(pos, current_font);
2417 par->InsertInset(pos, new_inset);
2423 } else if (str[i] != 13 &&
2424 // Ignore unprintables
2425 (str[i] & 127) >= ' ') {
2426 par->InsertChar(pos, str[i]);
2427 par->SetFont(pos, current_font);
2433 if ((i + 1) >= str.length()) {
2434 if (pos < par->size())
2438 while((pos < par->size()) &&
2439 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2442 cell = NumberOfCell(par, pos);
2443 while((pos < par->size()) &&
2444 !(par->table->IsFirstCell(cell))) {
2446 while((pos < par->size()) &&
2447 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2450 cell = NumberOfCell(par, pos);
2452 if (pos >= par->size())
2453 // no more fields to fill skip the rest
2457 if (!par->size()) { // par is empty
2458 InsetSpecialChar * new_inset =
2459 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2460 if (par->InsertInsetAllowed(new_inset)) {
2461 par->InsertChar(pos, LyXParagraph::META_INSET);
2462 par->SetFont(pos, current_font);
2463 par->InsertInset(pos, new_inset);
2469 par->BreakParagraph(bview->buffer()->params, pos, flag);
2479 RedoParagraphs(bview, cursor, endpar);
2480 SetCursor(bview, cursor.par(), cursor.pos());
2481 sel_cursor = cursor;
2482 SetCursor(bview, par, pos);
2487 /* turns double-CR to single CR, others where converted into one blank and 13s
2488 * that are ignored .Double spaces are also converted into one. Spaces at
2489 * the beginning of a paragraph are forbidden. tabs are converted into one
2490 * space. then InsertStringA is called */
2491 void LyXText::InsertStringB(BufferView * bview, string const & s)
2494 LyXParagraph * par = cursor.par();
2495 string::size_type i = 1;
2496 while (i < str.length()) {
2497 if (str[i] == '\t' && !par->table)
2499 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2501 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2502 if (str[i + 1] != '\n') {
2503 if (str[i - 1] != ' ')
2508 while (i + 1 < str.length()
2509 && (str[i + 1] == ' '
2510 || str[i + 1] == '\t'
2511 || str[i + 1] == '\n'
2512 || str[i + 1] == 13)) {
2519 InsertStringA(bview, str);
2523 bool LyXText::GotoNextError(BufferView * bview) const
2525 LyXCursor res = cursor;
2527 if (res.pos() < res.par()->Last() - 1) {
2528 res.pos(res.pos() + 1);
2530 res.par(res.par()->Next());
2534 } while (res.par() &&
2535 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2536 && res.par()->GetInset(res.pos())->AutoDelete()));
2539 SetCursor(bview, res.par(), res.pos());
2546 bool LyXText::GotoNextNote(BufferView * bview) const
2548 LyXCursor res = cursor;
2550 if (res.pos() < res.par()->Last() - 1) {
2551 res.pos(res.pos() + 1);
2553 res.par(res.par()->Next());
2557 } while (res.par() &&
2558 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2559 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2562 SetCursor(bview, res.par(), res.pos());
2569 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2570 LyXParagraph::size_type pos)
2572 LyXCursor tmpcursor;
2575 /* table stuff -- begin*/
2578 CheckParagraphInTable(bview, par, pos);
2582 /* table stuff -- end*/
2585 LyXParagraph::size_type z;
2586 Row * row = GetRow(par, pos, y);
2588 // is there a break one row above
2589 if (row->previous() && row->previous()->par() == row->par()) {
2590 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2591 if ( z >= row->pos()) {
2592 // set the dimensions of the row above
2593 y -= row->previous()->height();
2595 refresh_row = row->previous();
2596 status = LyXText::NEED_MORE_REFRESH;
2598 BreakAgain(bview, row->previous());
2600 // set the cursor again. Otherwise
2601 // dangling pointers are possible
2602 SetCursor(bview, cursor.par(), cursor.pos());
2603 sel_cursor = cursor;
2608 int tmpheight = row->height();
2609 LyXParagraph::size_type tmplast = RowLast(row);
2613 BreakAgain(bview, row);
2614 if (row->height() == tmpheight && RowLast(row) == tmplast)
2615 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2617 status = LyXText::NEED_MORE_REFRESH;
2619 // check the special right address boxes
2620 if (textclasslist.Style(bview->buffer()->params.textclass,
2621 par->GetLayout()).margintype
2622 == MARGIN_RIGHT_ADDRESS_BOX) {
2629 RedoDrawingOfParagraph(bview, tmpcursor);
2635 // set the cursor again. Otherwise dangling pointers are possible
2636 // also set the selection
2640 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2641 sel_cursor = cursor;
2642 SetCursorIntern(bview, sel_start_cursor.par(),
2643 sel_start_cursor.pos());
2644 sel_start_cursor = cursor;
2645 SetCursorIntern(bview, sel_end_cursor.par(),
2646 sel_end_cursor.pos());
2647 sel_end_cursor = cursor;
2648 SetCursorIntern(bview, last_sel_cursor.par(),
2649 last_sel_cursor.pos());
2650 last_sel_cursor = cursor;
2653 SetCursorIntern(bview, cursor.par(), cursor.pos());
2657 // returns false if inset wasn't found
2658 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2660 // first check the current paragraph
2661 int pos = cursor.par()->GetPositionOfInset(inset);
2663 CheckParagraph(bview, cursor.par(), pos);
2667 // check every paragraph
2669 LyXParagraph * par = FirstParagraph();
2671 // make sure the paragraph is open
2672 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2673 pos = par->GetPositionOfInset(inset);
2675 CheckParagraph(bview, par, pos);
2686 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2687 LyXParagraph::size_type pos,
2688 bool setfont, bool boundary) const
2690 LyXCursor old_cursor = cursor;
2691 SetCursorIntern(bview, par, pos, setfont, boundary);
2692 DeleteEmptyParagraphMechanism(bview, old_cursor);
2696 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2697 LyXParagraph::size_type pos, bool boundary) const
2699 // correct the cursor position if impossible
2700 if (pos > par->Last()){
2701 LyXParagraph * tmppar = par->ParFromPos(pos);
2702 pos = par->PositionInParFromPos(pos);
2705 if (par->IsDummy() && par->previous &&
2706 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2707 while (par->previous &&
2708 ((par->previous->IsDummy() &&
2709 (par->previous->previous->footnoteflag ==
2710 LyXParagraph::CLOSED_FOOTNOTE)) ||
2711 (par->previous->footnoteflag ==
2712 LyXParagraph::CLOSED_FOOTNOTE))) {
2713 par = par->previous ;
2714 if (par->IsDummy() &&
2715 (par->previous->footnoteflag ==
2716 LyXParagraph::CLOSED_FOOTNOTE))
2717 pos += par->size() + 1;
2719 if (par->previous) {
2720 par = par->previous;
2722 pos += par->size() + 1;
2727 cur.boundary(boundary);
2729 /* get the cursor y position in text */
2731 Row * row = GetRow(par, pos, y);
2732 /* y is now the beginning of the cursor row */
2733 y += row->baseline();
2734 /* y is now the cursor baseline */
2737 /* now get the cursors x position */
2739 float fill_separator, fill_hfill, fill_label_hfill;
2740 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2742 LyXParagraph::size_type cursor_vpos = 0;
2743 LyXParagraph::size_type last = RowLastPrintable(row);
2745 if (pos > last + 1) // This shouldn't happen.
2747 else if (pos < row->pos())
2750 if (last < row->pos())
2751 cursor_vpos = row->pos();
2752 else if (pos > last && !boundary)
2753 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2754 ? row->pos() : last + 1;
2755 else if (pos > row->pos() &&
2756 (pos > last || boundary ||
2757 (row->par()->table && row->par()->IsNewline(pos))))
2758 /// Place cursor after char at (logical) position pos - 1
2759 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2760 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2762 /// Place cursor before char at (logical) position pos
2763 cursor_vpos = (bidi_level(pos) % 2 == 0)
2764 ? log2vis(pos) : log2vis(pos) + 1;
2767 /* table stuff -- begin*/
2768 if (row->par()->table) {
2769 int cell = NumberOfCell(row->par(), row->pos());
2771 x += row->par()->table->GetBeginningOfTextInCell(cell);
2772 for (LyXParagraph::size_type vpos = row->pos();
2773 vpos < cursor_vpos; ++vpos) {
2774 pos = vis2log(vpos);
2775 if (row->par()->IsNewline(pos)) {
2776 x = x_old + row->par()->table->WidthOfColumn(cell);
2779 x += row->par()->table->GetBeginningOfTextInCell(cell);
2781 x += SingleWidth(bview, row->par(), pos);
2785 /* table stuff -- end*/
2787 LyXParagraph::size_type main_body =
2788 BeginningOfMainBody(bview->buffer(), row->par());
2789 if ((main_body > 0) &&
2790 ((main_body-1 > last) ||
2791 !row->par()->IsLineSeparator(main_body-1)))
2794 for (LyXParagraph::size_type vpos = row->pos();
2795 vpos < cursor_vpos; ++vpos) {
2796 pos = vis2log(vpos);
2797 if (main_body > 0 && pos == main_body-1) {
2798 x += fill_label_hfill +
2799 lyxfont::width(textclasslist.Style(
2800 bview->buffer()->params.textclass,
2801 row->par()->GetLayout())
2803 GetFont(bview->buffer(), row->par(), -2));
2804 if (row->par()->IsLineSeparator(main_body-1))
2805 x -= SingleWidth(bview, row->par(),main_body-1);
2807 if (HfillExpansion(bview->buffer(), row, pos)) {
2808 x += SingleWidth(bview, row->par(), pos);
2809 if (pos >= main_body)
2812 x += fill_label_hfill;
2813 } else if (row->par()->IsSeparator(pos)) {
2814 x += SingleWidth(bview, row->par(), pos);
2815 if (pos >= main_body)
2816 x += fill_separator;
2818 x += SingleWidth(bview, row->par(), pos);
2830 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2831 LyXParagraph::size_type pos,
2832 bool setfont, bool boundary) const
2834 SetCursor(bview, cursor, par, pos, boundary);
2835 // #warning Remove this when verified working (Jug 20000413)
2837 // correct the cursor position if impossible
2838 if (pos > par->Last()){
2839 LyXParagraph * tmppar = par->ParFromPos(pos);
2840 pos = par->PositionInParFromPos(pos);
2843 if (par->IsDummy() && par->previous &&
2844 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2845 while (par->previous &&
2846 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2847 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2848 par = par->previous ;
2849 if (par->IsDummy() &&
2850 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2851 pos += par->size() + 1;
2853 if (par->previous) {
2854 par = par->previous;
2856 pos += par->size() + 1;
2862 /* get the cursor y position in text */
2864 Row * row = GetRow(par, pos, y);
2865 /* y is now the beginning of the cursor row */
2866 y += row->baseline();
2867 /* y is now the cursor baseline */
2870 /* now get the cursors x position */
2872 float fill_separator, fill_hfill, fill_label_hfill;
2873 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2874 LyXParagraph::size_type cursor_vpos;
2875 LyXParagraph::size_type last = RowLastPrintable(row);
2877 if (pos > last + 1) // This shouldn't happen.
2880 if (last < row->pos())
2882 else if (pos > last ||
2883 (pos - 1 >= row->pos() &&
2884 (row->par()->IsSeparator(pos) ||
2885 (row->par()->table && row->par()->IsNewline(pos))
2887 /// Place cursor after char at (logical) position pos-1
2888 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2889 ? log2vis(pos-1) + 1 : log2vis(pos-1);
2891 /// Place cursor before char at (logical) position pos
2892 cursor_vpos = (bidi_level(pos) % 2 == 0)
2893 ? log2vis(pos) : log2vis(pos) + 1;
2896 /* table stuff -- begin*/
2897 if (row->par()->table) {
2898 int cell = NumberOfCell(row->par(), row->pos());
2900 x += row->par()->table->GetBeginningOfTextInCell(cell);
2901 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2902 pos = vis2log(vpos);
2903 if (row->par()->IsNewline(pos)) {
2904 x = x_old + row->par()->table->WidthOfColumn(cell);
2907 x += row->par()->table->GetBeginningOfTextInCell(cell);
2909 x += SingleWidth(row->par(), pos);
2913 /* table stuff -- end*/
2915 LyXParagraph::size_type main_body =
2916 BeginningOfMainBody(row->par());
2917 if (main_body > 0 &&
2918 (main_body-1 > last ||
2919 !row->par()->IsLineSeparator(main_body-1)))
2922 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2923 pos = vis2log(vpos);
2924 if (main_body > 0 && pos == main_body-1) {
2925 x += fill_label_hfill +
2926 lyxfont::width(textclasslist
2927 .Style(bview->buffer()->params.textclass,
2928 row->par()->GetLayout())
2930 GetFont(row->par(), -2));
2931 if (row->par()->IsLineSeparator(main_body-1))
2932 x -= SingleWidth(row->par(), main_body-1);
2934 if (HfillExpansion(row, pos)) {
2935 x += SingleWidth(row->par(), pos);
2936 if (pos >= main_body)
2939 x += fill_label_hfill;
2941 else if (row->par()->IsSeparator(pos)) {
2942 x += SingleWidth(row->par(), pos);
2943 if (pos >= main_body)
2944 x += fill_separator;
2946 x += SingleWidth(row->par(), pos);
2953 cursor.x_fix = cursor.x;
2957 SetCurrentFont(bview);
2960 void LyXText::SetCurrentFont(BufferView * bview) const
2962 LyXParagraph::size_type pos = cursor.pos();
2963 if (cursor.boundary() && pos > 0)
2967 if (pos == cursor.par()->Last() ||
2968 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2970 else if (cursor.par()->IsSeparator(pos)) {
2971 if (pos > cursor.row()->pos() &&
2972 bidi_level(pos) % 2 ==
2973 bidi_level(pos - 1) % 2)
2975 else if (pos + 1 < cursor.par()->Last())
2980 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2981 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2985 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2987 LyXCursor old_cursor = cursor;
2989 /* get the row first */
2991 Row * row = GetRowNearY(y);
2992 cursor.par(row->par());
2995 int column = GetColumnNearX(bview, row, x, bound);
2996 cursor.pos(row->pos() + column);
2998 cursor.y(y + row->baseline());
3000 cursor.boundary(bound);
3001 SetCurrentFont(bview);
3002 DeleteEmptyParagraphMechanism(bview, old_cursor);
3006 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3007 int x, long y) const
3009 /* get the row first */
3011 Row * row = GetRowNearY(y);
3013 int column = GetColumnNearX(bview, row, x, bound);
3015 cur.par(row->par());
3016 cur.pos(row->pos() + column);
3018 cur.y(y + row->baseline());
3020 cur.boundary(bound);
3024 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3026 CursorLeftIntern(bview, internal);
3028 if (cursor.par()->table) {
3029 int cell = NumberOfCell(cursor.par(), cursor.pos());
3030 if (cursor.par()->table->IsContRow(cell)
3031 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3039 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3041 if (cursor.pos() > 0) {
3042 bool boundary = cursor.boundary();
3043 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3044 if (!internal && !boundary &&
3045 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3046 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3047 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3048 LyXParagraph * par = cursor.par()->Previous();
3049 LyXParagraph::size_type pos = par->Last();
3050 SetCursor(bview, par, pos);
3051 if (IsBoundary(bview->buffer(), par, pos))
3052 SetCursor(bview, par, pos, false, true);
3057 void LyXText::CursorRight(BufferView * bview, bool internal) const
3059 CursorRightIntern(bview, internal);
3061 if (cursor.par()->table) {
3062 int cell = NumberOfCell(cursor.par(), cursor.pos());
3063 if (cursor.par()->table->IsContRow(cell) &&
3064 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3072 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3074 if (cursor.pos() < cursor.par()->Last()) {
3075 if (!internal && cursor.boundary() &&
3076 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3077 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3079 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3080 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3081 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3083 } else if (cursor.par()->Next())
3084 SetCursor(bview, cursor.par()->Next(), 0);
3088 void LyXText::CursorUp(BufferView * bview) const
3090 SetCursorFromCoordinates(bview, cursor.x_fix(),
3091 cursor.y() - cursor.row()->baseline() - 1);
3093 if (cursor.par()->table) {
3094 int cell = NumberOfCell(cursor.par(), cursor.pos());
3095 if (cursor.par()->table->IsContRow(cell) &&
3096 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3104 void LyXText::CursorDown(BufferView * bview) const
3107 if (cursor.par()->table &&
3108 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3109 !cursor.par()->next)
3113 SetCursorFromCoordinates(bview, cursor.x_fix(),
3114 cursor.y() - cursor.row()->baseline()
3115 + cursor.row()->height() + 1);
3117 if (cursor.par()->table) {
3118 int cell = NumberOfCell(cursor.par(), cursor.pos());
3119 int cell_above = cursor.par()->table->GetCellAbove(cell);
3120 while(cursor.par()->table &&
3121 cursor.par()->table->IsContRow(cell) &&
3122 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3123 SetCursorFromCoordinates(bview, cursor.x_fix(),
3124 cursor.y() - cursor.row()->baseline()
3125 + cursor.row()->height() + 1);
3126 if (cursor.par()->table) {
3127 cell = NumberOfCell(cursor.par(), cursor.pos());
3128 cell_above = cursor.par()->table->GetCellAbove(cell);
3136 void LyXText::CursorUpParagraph(BufferView * bview) const
3138 if (cursor.pos() > 0) {
3139 SetCursor(bview, cursor.par(), 0);
3141 else if (cursor.par()->Previous()) {
3142 SetCursor(bview, cursor.par()->Previous(), 0);
3147 void LyXText::CursorDownParagraph(BufferView * bview) const
3149 if (cursor.par()->Next()) {
3150 SetCursor(bview, cursor.par()->Next(), 0);
3152 SetCursor(bview, cursor.par(), cursor.par()->Last());
3157 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3158 LyXCursor const & old_cursor) const
3160 // Would be wrong to delete anything if we have a selection.
3161 if (selection) return;
3163 // We allow all kinds of "mumbo-jumbo" when freespacing.
3164 if (textclasslist.Style(bview->buffer()->params.textclass,
3165 old_cursor.par()->GetLayout()).free_spacing)
3168 bool deleted = false;
3170 /* Ok I'll put some comments here about what is missing.
3171 I have fixed BackSpace (and thus Delete) to not delete
3172 double-spaces automagically. I have also changed Cut,
3173 Copy and Paste to hopefully do some sensible things.
3174 There are still some small problems that can lead to
3175 double spaces stored in the document file or space at
3176 the beginning of paragraphs. This happens if you have
3177 the cursor betwenn to spaces and then save. Or if you
3178 cut and paste and the selection have a space at the
3179 beginning and then save right after the paste. I am
3180 sure none of these are very hard to fix, but I will
3181 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3182 that I can get some feedback. (Lgb)
3185 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3186 // delete the LineSeparator.
3189 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3190 // delete the LineSeparator.
3193 // If the pos around the old_cursor were spaces, delete one of them.
3194 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3195 // Only if the cursor has really moved
3197 if (old_cursor.pos() > 0
3198 && old_cursor.pos() < old_cursor.par()->Last()
3199 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3200 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3201 old_cursor.par()->Erase(old_cursor.pos() - 1);
3202 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3204 if (old_cursor.par() == cursor.par() &&
3205 cursor.pos() > old_cursor.pos()) {
3206 SetCursorIntern(bview, cursor.par(),
3209 SetCursorIntern(bview, cursor.par(),
3215 // Do not delete empty paragraphs with keepempty set.
3216 if ((textclasslist.Style(bview->buffer()->params.textclass,
3217 old_cursor.par()->GetLayout())).keepempty)
3220 LyXCursor tmpcursor;
3222 if (old_cursor.par() != cursor.par()) {
3223 if ( (old_cursor.par()->Last() == 0
3224 || (old_cursor.par()->Last() == 1
3225 && old_cursor.par()->IsLineSeparator(0)))
3226 && old_cursor.par()->FirstPhysicalPar()
3227 == old_cursor.par()->LastPhysicalPar()) {
3228 // ok, we will delete anything
3230 // make sure that you do not delete any environments
3231 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3232 !(old_cursor.row()->previous()
3233 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3234 && !(old_cursor.row()->next()
3235 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3236 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3237 && ((old_cursor.row()->previous()
3238 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3239 || (old_cursor.row()->next()
3240 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3242 status = LyXText::NEED_MORE_REFRESH;
3245 if (old_cursor.row()->previous()) {
3246 refresh_row = old_cursor.row()->previous();
3247 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3249 cursor = old_cursor; // that undo can restore the right cursor position
3250 LyXParagraph * endpar = old_cursor.par()->next;
3251 if (endpar && endpar->GetDepth()) {
3252 while (endpar && endpar->GetDepth()) {
3253 endpar = endpar->LastPhysicalPar()->Next();
3256 SetUndo(bview->buffer(), Undo::DELETE,
3257 old_cursor.par()->previous,
3262 RemoveRow(old_cursor.row());
3263 if (OwnerParagraph() == old_cursor.par()) {
3264 OwnerParagraph(OwnerParagraph()->next);
3267 delete old_cursor.par();
3269 /* Breakagain the next par. Needed
3270 * because of the parindent that
3271 * can occur or dissappear. The
3272 * next row can change its height,
3273 * if there is another layout before */
3274 if (refresh_row->next()) {
3275 BreakAgain(bview, refresh_row->next());
3276 UpdateCounters(bview, refresh_row);
3278 SetHeightOfRow(bview, refresh_row);
3280 refresh_row = old_cursor.row()->next();
3281 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3284 cursor = old_cursor; // that undo can restore the right cursor position
3285 LyXParagraph * endpar = old_cursor.par()->next;
3286 if (endpar && endpar->GetDepth()) {
3287 while (endpar && endpar->GetDepth()) {
3288 endpar = endpar->LastPhysicalPar()->Next();
3291 SetUndo(bview->buffer(), Undo::DELETE,
3292 old_cursor.par()->previous,
3297 RemoveRow(old_cursor.row());
3299 if (OwnerParagraph() == old_cursor.par()) {
3300 OwnerParagraph(OwnerParagraph()->next);
3302 delete old_cursor.par();
3304 /* Breakagain the next par. Needed
3305 because of the parindent that can
3306 occur or dissappear.
3307 The next row can change its height,
3308 if there is another layout before
3311 BreakAgain(bview, refresh_row);
3312 UpdateCounters(bview, refresh_row->previous());
3318 SetCursorIntern(bview, cursor.par(), cursor.pos());
3320 if (sel_cursor.par() == old_cursor.par()
3321 && sel_cursor.pos() == sel_cursor.pos()) {
3322 // correct selection
3323 sel_cursor = cursor;
3328 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3329 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3331 SetCursorIntern(bview, cursor.par(), cursor.pos());
3332 sel_cursor = cursor;
3339 LyXParagraph * LyXText::GetParFromID(int id)
3341 LyXParagraph * result = FirstParagraph();
3342 while (result && result->id() != id)
3343 result = result->next;
3349 bool LyXText::TextUndo(BufferView * bview)
3353 // returns false if no undo possible
3354 Undo * undo = bview->buffer()->undostack.pop();
3358 bview->buffer()->redostack
3359 .push(CreateUndo(bview->buffer(), undo->kind,
3360 GetParFromID(undo->number_of_before_par),
3361 GetParFromID(undo->number_of_behind_par)));
3363 return TextHandleUndo(bview, undo);
3367 bool LyXText::TextRedo(BufferView * bview)
3371 // returns false if no redo possible
3372 Undo * undo = bview->buffer()->redostack.pop();
3376 bview->buffer()->undostack
3377 .push(CreateUndo(bview->buffer(), undo->kind,
3378 GetParFromID(undo->number_of_before_par),
3379 GetParFromID(undo->number_of_behind_par)));
3381 return TextHandleUndo(bview, undo);
3385 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3389 // returns false if no undo possible
3390 bool result = false;
3392 LyXParagraph * before =
3393 GetParFromID(undo->number_of_before_par);
3394 LyXParagraph * behind =
3395 GetParFromID(undo->number_of_behind_par);
3396 LyXParagraph * tmppar;
3397 LyXParagraph * tmppar2;
3398 LyXParagraph * endpar;
3399 LyXParagraph * tmppar5;
3401 // if there's no before take the beginning
3402 // of the document for redoing
3404 SetCursorIntern(bview, FirstParagraph(), 0);
3406 // replace the paragraphs with the undo informations
3408 LyXParagraph * tmppar3 = undo->par;
3409 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3410 LyXParagraph * tmppar4 = tmppar3;
3412 while (tmppar4->next)
3413 tmppar4 = tmppar4->next;
3414 } // get last undo par
3416 // now remove the old text if there is any
3417 if (before != behind || (!behind && !before)){
3419 tmppar5 = before->next;
3421 tmppar5 = OwnerParagraph();
3423 while (tmppar5 && tmppar5 != behind){
3425 tmppar5 = tmppar5->next;
3426 // a memory optimization for edit: Only layout information
3427 // is stored in the undo. So restore the text informations.
3428 if (undo->kind == Undo::EDIT) {
3429 tmppar2->setContentsFromPar(tmppar);
3430 tmppar->clearContents();
3431 tmppar2 = tmppar2->next;
3436 // put the new stuff in the list if there is one
3439 before->next = tmppar3;
3441 OwnerParagraph(tmppar3);
3442 tmppar3->previous = before;
3446 OwnerParagraph(behind);
3449 tmppar4->next = behind;
3451 behind->previous = tmppar4;
3455 // Set the cursor for redoing
3457 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3458 // check wether before points to a closed float and open it if necessary
3459 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3460 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3462 while (tmppar4->previous &&
3463 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3464 tmppar4 = tmppar4->previous;
3465 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3466 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3467 tmppar4 = tmppar4->next;
3472 // open a cosed footnote at the end if necessary
3473 if (behind && behind->previous &&
3474 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3475 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3476 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3477 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3478 behind = behind->next;
3482 // calculate the endpar for redoing the paragraphs.
3484 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3485 endpar = behind->LastPhysicalPar()->Next();
3487 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3491 tmppar = GetParFromID(undo->number_of_cursor_par);
3492 RedoParagraphs(bview, cursor, endpar);
3494 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3495 UpdateCounters(bview, cursor.row());
3505 void LyXText::FinishUndo()
3509 // makes sure the next operation will be stored
3510 undo_finished = true;
3514 void LyXText::FreezeUndo()
3518 // this is dangerous and for internal use only
3523 void LyXText::UnFreezeUndo()
3527 // this is dangerous and for internal use only
3528 undo_frozen = false;
3532 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3533 LyXParagraph const * before,
3534 LyXParagraph const * behind) const
3539 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3540 buf->redostack.clear();
3544 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3545 LyXParagraph const * before, LyXParagraph const * behind)
3549 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3553 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3554 LyXParagraph const * before,
3555 LyXParagraph const * behind) const
3560 int before_number = -1;
3561 int behind_number = -1;
3563 before_number = before->id();
3565 behind_number = behind->id();
3566 // Undo::EDIT and Undo::FINISH are
3567 // always finished. (no overlapping there)
3568 // overlapping only with insert and delete inside one paragraph:
3569 // Nobody wants all removed character
3570 // appear one by one when undoing.
3571 // EDIT is special since only layout information, not the
3572 // contents of a paragaph are stored.
3573 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3574 // check wether storing is needed
3575 if (!buf->undostack.empty() &&
3576 buf->undostack.top()->kind == kind &&
3577 buf->undostack.top()->number_of_before_par == before_number &&
3578 buf->undostack.top()->number_of_behind_par == behind_number ){
3583 // create a new Undo
3584 LyXParagraph * undopar;
3585 LyXParagraph * tmppar;
3586 LyXParagraph * tmppar2;
3588 LyXParagraph * start = 0;
3589 LyXParagraph * end = 0;
3592 start = before->next;
3594 start = FirstParagraph();
3596 end = behind->previous;
3598 end = FirstParagraph();
3604 && start != end->next
3605 && (before != behind || (!before && !behind))) {
3607 tmppar2 = tmppar->Clone();
3608 tmppar2->id(tmppar->id());
3610 // a memory optimization: Just store the layout information
3612 if (kind == Undo::EDIT){
3613 //tmppar2->text.clear();
3614 tmppar2->clearContents();
3619 while (tmppar != end && tmppar->next) {
3620 tmppar = tmppar->next;
3621 tmppar2->next = tmppar->Clone();
3622 tmppar2->next->id(tmppar->id());
3623 // a memory optimization: Just store the layout
3624 // information when only edit
3625 if (kind == Undo::EDIT){
3626 //tmppar2->next->text.clear();
3627 tmppar2->clearContents();
3629 tmppar2->next->previous = tmppar2;
3630 tmppar2 = tmppar2->next;
3634 undopar = 0; // nothing to replace (undo of delete maybe)
3636 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3637 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3639 Undo * undo = new Undo(kind,
3640 before_number, behind_number,
3641 cursor_par, cursor_pos,
3644 undo_finished = false;
3649 void LyXText::SetCursorParUndo(Buffer * buf)
3653 SetUndo(buf, Undo::FINISH,
3654 cursor.par()->ParFromPos(cursor.pos())->previous,
3655 cursor.par()->ParFromPos(cursor.pos())->next);
3660 void LyXText::RemoveTableRow(LyXCursor & cur) const
3666 // move to the previous row
3667 int cell_act = NumberOfCell(cur.par(), cur.pos());
3670 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3671 cur.pos(cur.pos() - 1);
3673 !cur.par()->table->IsFirstCell(cell_act)) {
3674 cur.pos(cur.pos() - 1);
3675 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3676 cur.pos(cur.pos() - 1);
3680 // now we have to pay attention if the actual table is the
3681 // main row of TableContRows and if yes to delete all of them
3686 // delete up to the next row
3687 while (cur.pos() < cur.par()->Last() &&
3689 || !cur.par()->table->IsFirstCell(cell_act))) {
3690 while (cur.pos() < cur.par()->Last() &&
3691 !cur.par()->IsNewline(cur.pos()))
3692 cur.par()->Erase(cur.pos());
3695 if (cur.pos() < cur.par()->Last())
3696 cur.par()->Erase(cur.pos());
3698 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3699 cur.pos(cur.pos() - 1);
3700 cur.par()->Erase(cur.pos()); // no newline at very end!
3702 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3703 !cur.par()->table->IsContRow(cell_org) &&
3704 cur.par()->table->IsContRow(cell));
3705 cur.par()->table->DeleteRow(cell_org);
3712 bool LyXText::IsEmptyTableCell() const
3714 LyXParagraph::size_type pos = cursor.pos() - 1;
3715 while (pos >= 0 && pos < cursor.par()->Last()
3716 && !cursor.par()->IsNewline(pos))
3718 return cursor.par()->IsNewline(pos + 1);
3723 void LyXText::toggleAppendix(BufferView * bview)
3725 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3726 bool start = !par->start_of_appendix;
3728 // ensure that we have only one start_of_appendix in this document
3729 LyXParagraph * tmp = FirstParagraph();
3730 for (; tmp; tmp = tmp->next)
3731 tmp->start_of_appendix = 0;
3732 par->start_of_appendix = start;
3734 // we can set the refreshing parameters now
3735 status = LyXText::NEED_MORE_REFRESH;
3737 refresh_row = 0; // not needed for full update
3738 UpdateCounters(bview, 0);
3739 SetCursor(bview, cursor.par(), cursor.pos());
3742 LyXParagraph * LyXText::OwnerParagraph() const
3745 return inset_owner->par;
3747 return bv_owner->buffer()->paragraph;
3751 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3754 inset_owner->par = p;
3756 bv_owner->buffer()->paragraph = p;