1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
28 #include "support/textutils.h"
30 #include "minibuffer.h"
32 #include "bufferparams.h"
33 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
39 #include "CutAndPaste.h"
45 //#define USE_OLD_CUT_AND_PASTE 1
51 LyXText::LyXText(BufferView * bv)
59 LyXText::LyXText(InsetText * inset)
76 status = LyXText::UNCHANGED;
77 // set cursor at the very top position
78 selection = true; /* these setting is necessary
79 because of the delete-empty-
80 paragraph mechanism in
83 LyXParagraph * par = OwnerParagraph();
84 current_font = GetFont(bv_owner->buffer(), par, 0);
86 InsertParagraph(bv_owner, par, lastrow);
89 SetCursor(bv_owner, firstrow->par(), 0);
91 current_font = LyXFont(LyXFont::ALL_SANE);
97 // no rebreak necessary
100 undo_finished = true;
103 // Default layouttype for copy environment type
107 // Dump all rowinformation:
108 Row * tmprow = firstrow;
109 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
111 lyxerr << tmprow->baseline() << '\t'
112 << tmprow->par << '\t'
113 << tmprow->pos() << '\t'
114 << tmprow->height << '\t'
115 << tmprow->ascent_of_text << '\t'
116 << tmprow->fill << '\n';
117 tmprow = tmprow->next();
124 void LyXText::init(BufferView * bview)
129 LyXParagraph * par = OwnerParagraph();
130 current_font = GetFont(bview->buffer(), par, 0);
132 InsertParagraph(bview, par, lastrow);
135 SetCursorIntern(bview, firstrow->par(), 0);
138 // Dump all rowinformation:
139 Row * tmprow = firstrow;
140 lyxerr << "Width = " << width << endl;
141 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
143 lyxerr << tmprow->baseline() << '\t'
144 << tmprow->par() << '\t'
145 << tmprow->pos() << '\t'
146 << tmprow->height() << '\t'
147 << tmprow->ascent_of_text() << '\t'
148 << tmprow->fill() << '\n';
149 tmprow = tmprow->next();
157 // Delete all rows, this does not touch the paragraphs!
158 Row * tmprow = firstrow;
160 tmprow = firstrow->next();
167 // Gets the fully instantiated font at a given position in a paragraph
168 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
169 // The difference is that this one is used for displaying, and thus we
170 // are allowed to make cosmetic improvements. For instance make footnotes
172 // If position is -1, we get the layout font of the paragraph.
173 // If position is -2, we get the font of the manual label of the paragraph.
174 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
175 LyXParagraph::size_type pos) const
177 LyXLayout const & layout =
178 textclasslist.Style(buf->params.textclass, par->GetLayout());
180 char par_depth = par->GetDepth();
181 // We specialize the 95% common case:
182 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
185 if (layout.labeltype == LABEL_MANUAL
186 && pos < BeginningOfMainBody(buf, par)) {
188 return par->GetFontSettings(buf->params, pos).
189 realize(layout.reslabelfont);
191 return par->GetFontSettings(buf->params, pos).
192 realize(layout.resfont);
195 // process layoutfont for pos == -1 and labelfont for pos < -1
197 return layout.resfont;
199 return layout.reslabelfont;
203 // The uncommon case need not be optimized as much
205 LyXFont layoutfont, tmpfont;
209 if (pos < BeginningOfMainBody(buf, par)) {
211 layoutfont = layout.labelfont;
214 layoutfont = layout.font;
216 tmpfont = par->GetFontSettings(buf->params, pos);
217 tmpfont.realize(layoutfont);
220 // process layoutfont for pos == -1 and labelfont for pos < -1
222 tmpfont = layout.font;
224 tmpfont = layout.labelfont;
227 // Resolve against environment font information
228 while (par && par_depth && !tmpfont.resolved()) {
229 par = par->DepthHook(par_depth - 1);
231 tmpfont.realize(textclasslist.
232 Style(buf->params.textclass,
233 par->GetLayout()).font);
234 par_depth = par->GetDepth();
238 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
241 // Cosmetic improvement: If this is an open footnote, make the font
243 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
244 && par->footnotekind == LyXParagraph::FOOTNOTE) {
252 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
253 LyXParagraph::size_type pos,
257 // Let the insets convert their font
258 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
259 if (par->GetInset(pos))
260 font = par->GetInset(pos)->ConvertFont(font);
263 LyXLayout const & layout =
264 textclasslist.Style(buf->params.textclass,
267 // Get concrete layout font to reduce against
270 if (pos < BeginningOfMainBody(buf, par))
271 layoutfont = layout.labelfont;
273 layoutfont = layout.font;
275 // Realize against environment font information
276 if (par->GetDepth()){
277 LyXParagraph * tp = par;
278 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
279 tp = tp->DepthHook(tp->GetDepth()-1);
281 layoutfont.realize(textclasslist.
282 Style(buf->params.textclass,
283 tp->GetLayout()).font);
287 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
290 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
291 && par->footnotekind == LyXParagraph::FOOTNOTE) {
292 layoutfont.decSize();
295 // Now, reduce font against full layout font
296 font.reduce(layoutfont);
298 par->SetFont(pos, font);
302 /* inserts a new row behind the specified row, increments
303 * the touched counters */
304 void LyXText::InsertRow(Row * row, LyXParagraph * par,
305 LyXParagraph::size_type pos) const
307 Row * tmprow = new Row;
310 tmprow->next(firstrow);
313 tmprow->previous(row);
314 tmprow->next(row->next());
319 tmprow->next()->previous(tmprow);
321 if (tmprow->previous())
322 tmprow->previous()->next(tmprow);
330 ++number_of_rows; // one more row
334 // removes the row and reset the touched counters
335 void LyXText::RemoveRow(Row * row) const
337 /* this must not happen before the currentrow for clear reasons.
338 so the trick is just to set the current row onto the previous
341 GetRow(row->par(), row->pos(), unused_y);
344 row->next()->previous(row->previous());
345 if (!row->previous()) {
346 firstrow = row->next();
348 row->previous()->next(row->next());
351 lastrow = row->previous();
353 height -= row->height(); // the text becomes smaller
356 --number_of_rows; // one row less
360 // remove all following rows of the paragraph of the specified row.
361 void LyXText::RemoveParagraph(Row * row) const
363 LyXParagraph * tmppar = row->par();
367 while (row && row->par() == tmppar) {
368 tmprow = row->next();
375 // insert the specified paragraph behind the specified row
376 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
379 InsertRow(row, par, 0); /* insert a new row, starting
382 SetCounter(bview->buffer(), par); // set the counters
384 // and now append the whole paragraph behind the new row
387 AppendParagraph(bview, firstrow);
389 row->next()->height(0);
390 AppendParagraph(bview, row->next());
396 void LyXText::ToggleFootnote(BufferView * bview)
398 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
400 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
402 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
404 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
405 CloseFootnote(bview);
411 void LyXText::OpenStuff(BufferView * bview)
413 if (cursor.pos() == 0 && cursor.par()->bibkey){
414 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
416 else if (cursor.pos() < cursor.par()->Last()
417 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
418 && cursor.par()->GetInset(cursor.pos())->Editable()) {
419 bview->owner()->getMiniBuffer()
420 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
421 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
422 SetCursorParUndo(bview->buffer());
423 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
425 ToggleFootnote(bview);
431 void LyXText::CloseFootnote(BufferView * bview)
433 LyXParagraph * tmppar;
434 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
436 // if the cursor is not in an open footnote, or
437 // there is no open footnote in this paragraph, just return.
438 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
441 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
442 bview->owner()->getMiniBuffer()
443 ->Set(_("Nothing to do"));
447 // ok, move the cursor right before the footnote
448 // just a little faster than using CursorRight()
450 cursor.par()->ParFromPos(cursor.pos()) != par;) {
451 cursor.pos(cursor.pos() + 1);
454 // now the cursor is at the beginning of the physical par
455 SetCursor(bview, cursor.par(),
457 cursor.par()->ParFromPos(cursor.pos())->size());
459 /* we are in a footnote, so let us move at the beginning */
460 /* this is just faster than using just CursorLeft() */
462 tmppar = cursor.par();
463 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
464 // just a little bit faster than movin the cursor
465 tmppar = tmppar->Previous();
467 SetCursor(bview, tmppar, tmppar->Last());
470 // the cursor must be exactly before the footnote
471 par = cursor.par()->ParFromPos(cursor.pos());
473 status = LyXText::NEED_MORE_REFRESH;
474 refresh_row = cursor.row();
475 refresh_y = cursor.y() - cursor.row()->baseline();
477 tmppar = cursor.par();
478 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
479 Row * row = cursor.row();
481 tmppar->CloseFootnote(cursor.pos());
483 while (tmppar != endpar) {
484 RemoveRow(row->next());
486 tmppar = row->next()->par();
491 AppendParagraph(bview, cursor.row());
493 SetCursor(bview, cursor.par(), cursor.pos());
497 if (cursor.row()->next())
498 SetHeightOfRow(bview, cursor.row()->next());
503 /* used in setlayout */
504 // Asger is not sure we want to do this...
505 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
509 LyXLayout const & layout =
510 textclasslist.Style(buf->params.textclass, par->GetLayout());
512 LyXFont layoutfont, tmpfont;
513 for (LyXParagraph::size_type pos = 0;
514 pos < par->Last(); ++pos) {
515 if (pos < BeginningOfMainBody(buf, par))
516 layoutfont = layout.labelfont;
518 layoutfont = layout.font;
520 tmpfont = par->GetFontSettings(buf->params, pos);
521 tmpfont.reduce(layoutfont);
522 par->SetFont(pos, tmpfont);
527 LyXParagraph * LyXText::SetLayout(BufferView * bview,
528 LyXCursor & cur, LyXCursor & sstart_cur,
529 LyXCursor & send_cur,
530 LyXTextClass::size_type layout)
532 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
533 LyXParagraph * undoendpar = endpar;
535 if (endpar && endpar->GetDepth()) {
536 while (endpar && endpar->GetDepth()) {
537 endpar = endpar->LastPhysicalPar()->Next();
541 endpar = endpar->Next(); // because of parindents etc.
544 SetUndo(bview->buffer(), Undo::EDIT,
545 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
548 /* ok we have a selection. This is always between sstart_cur
549 * and sel_end cursor */
552 LyXLayout const & lyxlayout =
553 textclasslist.Style(bview->buffer()->params.textclass, layout);
555 while (cur.par() != send_cur.par()) {
556 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
557 cur.par()->SetLayout(bview->buffer()->params, layout);
558 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
559 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
560 fppar->added_space_top = lyxlayout.fill_top ?
561 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
562 fppar->added_space_bottom = lyxlayout.fill_bottom ?
563 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
564 if (lyxlayout.margintype == MARGIN_MANUAL)
565 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
566 if (lyxlayout.labeltype != LABEL_BIBLIO
568 delete fppar->bibkey;
572 cur.par(cur.par()->Next());
574 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
575 cur.par()->SetLayout(bview->buffer()->params, layout);
576 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
577 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
578 fppar->added_space_top = lyxlayout.fill_top ?
579 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
580 fppar->added_space_bottom = lyxlayout.fill_bottom ?
581 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
582 if (lyxlayout.margintype == MARGIN_MANUAL)
583 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
584 if (lyxlayout.labeltype != LABEL_BIBLIO
586 delete fppar->bibkey;
593 // set layout over selection and make a total rebreak of those paragraphs
594 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
597 tmpcursor = cursor; /* store the current cursor */
599 #ifdef USE_OLD_SET_LAYOUT
600 // if there is no selection just set the layout
601 // of the current paragraph */
603 sel_start_cursor = cursor; // dummy selection
604 sel_end_cursor = cursor;
607 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
608 LyXParagraph * undoendpar = endpar;
610 if (endpar && endpar->GetDepth()) {
611 while (endpar && endpar->GetDepth()) {
612 endpar = endpar->LastPhysicalPar()->Next();
617 endpar = endpar->Next(); // because of parindents etc.
621 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
624 /* ok we have a selection. This is always between sel_start_cursor
625 * and sel_end cursor */
626 cursor = sel_start_cursor;
628 LyXLayout const & lyxlayout =
629 textclasslist.Style(bview->buffer()->params.textclass, layout);
631 while (cursor.par() != sel_end_cursor.par()) {
632 if (cursor.par()->footnoteflag ==
633 sel_start_cursor.par()->footnoteflag) {
634 cursor.par()->SetLayout(layout);
635 MakeFontEntriesLayoutSpecific(cursor.par());
636 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
637 fppar->added_space_top = lyxlayout.fill_top ?
638 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
639 fppar->added_space_bottom = lyxlayout.fill_bottom ?
640 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
641 if (lyxlayout.margintype == MARGIN_MANUAL)
642 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
643 if (lyxlayout.labeltype != LABEL_BIBLIO
645 delete fppar->bibkey;
649 cursor.par() = cursor.par()->Next();
651 if (cursor.par()->footnoteflag ==
652 sel_start_cursor.par()->footnoteflag) {
653 cursor.par()->SetLayout(layout);
654 MakeFontEntriesLayoutSpecific(cursor.par());
655 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
656 fppar->added_space_top = lyxlayout.fill_top ?
657 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
658 fppar->added_space_bottom = lyxlayout.fill_bottom ?
659 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
660 if (lyxlayout.margintype == MARGIN_MANUAL)
661 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
662 if (lyxlayout.labeltype != LABEL_BIBLIO
664 delete fppar->bibkey;
669 // if there is no selection just set the layout
670 // of the current paragraph */
672 sel_start_cursor = cursor; // dummy selection
673 sel_end_cursor = cursor;
676 endpar = SetLayout(bview, cursor, sel_start_cursor,
677 sel_end_cursor, layout);
679 RedoParagraphs(bview, sel_start_cursor, endpar);
681 // we have to reset the selection, because the
682 // geometry could have changed */
683 SetCursor(bview, sel_start_cursor.par(),
684 sel_start_cursor.pos(), false);
686 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
688 UpdateCounters(bview, cursor.row());
691 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
695 // increment depth over selection and
696 // make a total rebreak of those paragraphs
697 void LyXText::IncDepth(BufferView * bview)
699 // If there is no selection, just use the current paragraph
701 sel_start_cursor = cursor; // dummy selection
702 sel_end_cursor = cursor;
705 // We end at the next paragraph with depth 0
706 LyXParagraph * endpar =
707 sel_end_cursor.par()->LastPhysicalPar()->Next();
708 LyXParagraph * undoendpar = endpar;
710 if (endpar && endpar->GetDepth()) {
711 while (endpar && endpar->GetDepth()) {
712 endpar = endpar->LastPhysicalPar()->Next();
717 endpar = endpar->Next(); // because of parindents etc.
720 SetUndo(bview->buffer(), Undo::EDIT,
722 .par()->ParFromPos(sel_start_cursor.pos())->previous,
725 LyXCursor tmpcursor = cursor; // store the current cursor
727 // ok we have a selection. This is always between sel_start_cursor
728 // and sel_end cursor
729 cursor = sel_start_cursor;
731 bool anything_changed = false;
734 // NOTE: you can't change the depth of a bibliography entry
735 if (cursor.par()->footnoteflag ==
736 sel_start_cursor.par()->footnoteflag
737 && textclasslist.Style(bview->buffer()->params.textclass,
738 cursor.par()->GetLayout()
739 ).labeltype != LABEL_BIBLIO) {
740 LyXParagraph * prev =
741 cursor.par()->FirstPhysicalPar()->Previous();
743 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
744 || (prev->GetDepth() == cursor.par()->GetDepth()
745 && textclasslist.Style(bview->buffer()->params.textclass,
746 prev->GetLayout()).isEnvironment()))) {
747 cursor.par()->FirstPhysicalPar()->depth++;
748 anything_changed = true;
751 if (cursor.par() == sel_end_cursor.par())
753 cursor.par(cursor.par()->Next());
756 // if nothing changed set all depth to 0
757 if (!anything_changed) {
758 cursor = sel_start_cursor;
759 while (cursor.par() != sel_end_cursor.par()) {
760 cursor.par()->FirstPhysicalPar()->depth = 0;
761 cursor.par(cursor.par()->Next());
763 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
764 cursor.par()->FirstPhysicalPar()->depth = 0;
767 RedoParagraphs(bview, sel_start_cursor, endpar);
769 // we have to reset the selection, because the
770 // geometry could have changed
771 SetCursor(bview, sel_start_cursor.par(),
772 sel_start_cursor.pos());
774 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
775 UpdateCounters(bview, cursor.row());
778 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
782 // decrement depth over selection and
783 // make a total rebreak of those paragraphs
784 void LyXText::DecDepth(BufferView * bview)
786 // if there is no selection just set the layout
787 // of the current paragraph
789 sel_start_cursor = cursor; // dummy selection
790 sel_end_cursor = cursor;
793 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
794 LyXParagraph * undoendpar = endpar;
796 if (endpar && endpar->GetDepth()) {
797 while (endpar && endpar->GetDepth()) {
798 endpar = endpar->LastPhysicalPar()->Next();
803 endpar = endpar->Next(); // because of parindents etc.
806 SetUndo(bview->buffer(), Undo::EDIT,
808 .par()->ParFromPos(sel_start_cursor.pos())->previous,
811 LyXCursor tmpcursor = cursor; // store the current cursor
813 // ok we have a selection. This is always between sel_start_cursor
814 // and sel_end cursor
815 cursor = sel_start_cursor;
818 if (cursor.par()->footnoteflag ==
819 sel_start_cursor.par()->footnoteflag) {
820 if (cursor.par()->FirstPhysicalPar()->depth)
821 cursor.par()->FirstPhysicalPar()->depth--;
823 if (cursor.par() == sel_end_cursor.par())
825 cursor.par(cursor.par()->Next());
828 RedoParagraphs(bview, sel_start_cursor, endpar);
830 // we have to reset the selection, because the
831 // geometry could have changed
832 SetCursor(bview, sel_start_cursor.par(),
833 sel_start_cursor.pos());
835 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
836 UpdateCounters(bview, cursor.row());
839 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
843 // set font over selection and make a total rebreak of those paragraphs
844 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
846 // if there is no selection just set the current_font
848 // Determine basis font
850 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
852 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
854 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
855 // Update current font
856 real_current_font.update(font,
857 bview->buffer()->params.language_info,
860 // Reduce to implicit settings
861 current_font = real_current_font;
862 current_font.reduce(layoutfont);
863 // And resolve it completely
864 real_current_font.realize(layoutfont);
868 LyXCursor tmpcursor = cursor; // store the current cursor
870 // ok we have a selection. This is always between sel_start_cursor
871 // and sel_end cursor
873 SetUndo(bview->buffer(), Undo::EDIT,
874 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
875 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
876 cursor = sel_start_cursor;
877 while (cursor.par() != sel_end_cursor.par() ||
878 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
879 && cursor.pos() < sel_end_cursor.pos()))
881 if (cursor.pos() < cursor.par()->Last()
882 && cursor.par()->footnoteflag
883 == sel_start_cursor.par()->footnoteflag) {
884 // an open footnote should behave
886 LyXFont newfont = GetFont(bview->buffer(),
887 cursor.par(), cursor.pos());
889 bview->buffer()->params.language_info,
891 SetCharFont(bview->buffer(),
892 cursor.par(), cursor.pos(), newfont);
893 cursor.pos(cursor.pos() + 1);
896 cursor.par(cursor.par()->Next());
900 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
902 // we have to reset the selection, because the
903 // geometry could have changed
904 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
906 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
909 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
910 tmpcursor.boundary());
914 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
916 Row * tmprow = cur.row();
917 long y = cur.y() - tmprow->baseline();
919 SetHeightOfRow(bview, tmprow);
920 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
921 // find the first row of the paragraph
922 if (first_phys_par != tmprow->par())
923 while (tmprow->previous()
924 && tmprow->previous()->par() != first_phys_par) {
925 tmprow = tmprow->previous();
926 y -= tmprow->height();
927 SetHeightOfRow(bview, tmprow);
929 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
930 tmprow = tmprow->previous();
931 y -= tmprow->height();
932 SetHeightOfRow(bview, tmprow);
935 // we can set the refreshing parameters now
936 status = LyXText::NEED_MORE_REFRESH;
938 refresh_row = tmprow;
939 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
943 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
945 Row * tmprow = cur.row();
947 long y = cur.y() - tmprow->baseline();
948 SetHeightOfRow(bview, tmprow);
949 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
950 // find the first row of the paragraph
951 if (first_phys_par != tmprow->par())
952 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
953 tmprow = tmprow->previous();
954 y -= tmprow->height();
956 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
957 tmprow = tmprow->previous();
958 y -= tmprow->height();
961 // we can set the refreshing parameters now
962 if (status == LyXText::UNCHANGED || y < refresh_y) {
964 refresh_row = tmprow;
966 status = LyXText::NEED_MORE_REFRESH;
967 SetCursor(bview, cur.par(), cur.pos());
971 /* deletes and inserts again all paragaphs between the cursor
972 * and the specified par
973 * This function is needed after SetLayout and SetFont etc. */
974 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
975 LyXParagraph const * endpar) const
978 LyXParagraph * tmppar = 0, * first_phys_par = 0;
980 Row * tmprow = cur.row();
982 long y = cur.y() - tmprow->baseline();
984 if (!tmprow->previous()){
985 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
987 first_phys_par = tmprow->par()->FirstPhysicalPar();
988 // find the first row of the paragraph
989 if (first_phys_par != tmprow->par())
990 while (tmprow->previous() &&
991 (tmprow->previous()->par() != first_phys_par)) {
992 tmprow = tmprow->previous();
993 y -= tmprow->height();
995 while (tmprow->previous()
996 && tmprow->previous()->par() == first_phys_par) {
997 tmprow = tmprow->previous();
998 y -= tmprow->height();
1002 // we can set the refreshing parameters now
1003 status = LyXText::NEED_MORE_REFRESH;
1005 refresh_row = tmprow->previous(); /* the real refresh row will
1006 be deleted, so I store
1007 the previous here */
1010 tmppar = tmprow->next()->par();
1013 while (tmppar != endpar) {
1014 RemoveRow(tmprow->next());
1016 tmppar = tmprow->next()->par();
1021 // remove the first one
1022 tmprow2 = tmprow; /* this is because tmprow->previous()
1024 tmprow = tmprow->previous();
1027 tmppar = first_phys_par;
1031 InsertParagraph(bview, tmppar, tmprow);
1034 while (tmprow->next() && tmprow->next()->par() == tmppar)
1035 tmprow = tmprow->next();
1036 tmppar = tmppar->Next();
1038 } while (tmppar != endpar);
1040 // this is because of layout changes
1042 refresh_y -= refresh_row->height();
1043 SetHeightOfRow(bview, refresh_row);
1045 refresh_row = firstrow;
1047 SetHeightOfRow(bview, refresh_row);
1050 if (tmprow && tmprow->next())
1051 SetHeightOfRow(bview, tmprow->next());
1055 bool LyXText::FullRebreak(BufferView * bview)
1061 if (need_break_row) {
1062 BreakAgain(bview, need_break_row);
1070 /* important for the screen */
1073 /* the cursor set functions have a special mechanism. When they
1074 * realize, that you left an empty paragraph, they will delete it.
1075 * They also delete the corresponding row */
1077 // need the selection cursor:
1078 void LyXText::SetSelection()
1081 last_sel_cursor = sel_cursor;
1082 sel_start_cursor = sel_cursor;
1083 sel_end_cursor = sel_cursor;
1088 // first the toggling area
1089 if (cursor.y() < last_sel_cursor.y()
1090 || (cursor.y() == last_sel_cursor.y()
1091 && cursor.x() < last_sel_cursor.x())) {
1092 toggle_end_cursor = last_sel_cursor;
1093 toggle_cursor = cursor;
1095 toggle_end_cursor = cursor;
1096 toggle_cursor = last_sel_cursor;
1099 last_sel_cursor = cursor;
1101 // and now the whole selection
1103 if (sel_cursor.par() == cursor.par())
1104 if (sel_cursor.pos() < cursor.pos()) {
1105 sel_end_cursor = cursor;
1106 sel_start_cursor = sel_cursor;
1108 sel_end_cursor = sel_cursor;
1109 sel_start_cursor = cursor;
1111 else if (sel_cursor.y() < cursor.y() ||
1112 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1113 sel_end_cursor = cursor;
1114 sel_start_cursor = sel_cursor;
1117 sel_end_cursor = sel_cursor;
1118 sel_start_cursor = cursor;
1121 // a selection with no contents is not a selection
1122 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1123 sel_start_cursor.pos() == sel_end_cursor.pos())
1128 string LyXText::selectionAsString(Buffer const * buffer) const
1130 if (!selection) return string();
1133 // Special handling if the whole selection is within one paragraph
1134 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1135 result += sel_start_cursor.par()->String(buffer,
1136 sel_start_cursor.pos(),
1137 sel_end_cursor.pos());
1141 // The selection spans more than one paragraph
1143 // First paragraph in selection
1144 result += sel_start_cursor.par()->String(buffer,
1145 sel_start_cursor.pos(),
1146 sel_start_cursor.par()->Last())
1149 // The paragraphs in between (if any)
1150 LyXCursor tmpcur(sel_start_cursor);
1151 tmpcur.par(tmpcur.par()->Next());
1152 while (tmpcur.par() != sel_end_cursor.par()) {
1153 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1154 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1157 // Last paragraph in selection
1158 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1164 void LyXText::ClearSelection() const
1171 void LyXText::CursorHome(BufferView * bview) const
1173 SetCursor(bview, cursor.par(), cursor.row()->pos());
1177 void LyXText::CursorEnd(BufferView * bview) const
1179 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1180 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1182 if (cursor.par()->Last() &&
1183 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1184 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1185 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1187 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1190 if (cursor.par()->table) {
1191 int cell = NumberOfCell(cursor.par(), cursor.pos());
1192 if (cursor.par()->table->RowHasContRow(cell) &&
1193 cursor.par()->table->CellHasContRow(cell)<0) {
1194 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1195 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1197 if (cursor.par()->Last() &&
1198 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1199 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1200 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1202 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1210 void LyXText::CursorTop(BufferView * bview) const
1212 while (cursor.par()->Previous())
1213 cursor.par(cursor.par()->Previous());
1214 SetCursor(bview, cursor.par(), 0);
1218 void LyXText::CursorBottom(BufferView * bview) const
1220 while (cursor.par()->Next())
1221 cursor.par(cursor.par()->Next());
1222 SetCursor(bview, cursor.par(), cursor.par()->Last());
1226 /* returns a pointer to the row near the specified y-coordinate
1227 * (relative to the whole text). y is set to the real beginning
1229 Row * LyXText::GetRowNearY(long & y) const
1231 Row * tmprow = firstrow;
1234 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1235 tmpy += tmprow->height();
1236 tmprow = tmprow->next();
1239 y = tmpy; // return the real y
1244 void LyXText::ToggleFree(BufferView * bview,
1245 LyXFont const & font, bool toggleall)
1247 // If the mask is completely neutral, tell user
1248 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1249 // Could only happen with user style
1250 bview->owner()->getMiniBuffer()
1251 ->Set(_("No font change defined. Use Character under"
1252 " the Layout menu to define font change."));
1256 // Try implicit word selection
1257 // If there is a change in the language the implicit word selection
1259 LyXCursor resetCursor = cursor;
1260 bool implicitSelection = (font.language() == ignore_language)
1261 ? SelectWordWhenUnderCursor(bview) : false;
1264 SetFont(bview, font, toggleall);
1266 /* Implicit selections are cleared afterwards and cursor is set to the
1267 original position. */
1268 if (implicitSelection) {
1270 cursor = resetCursor;
1271 SetCursor(bview, cursor.par(), cursor.pos());
1272 sel_cursor = cursor;
1277 LyXParagraph::size_type
1278 LyXText::BeginningOfMainBody(Buffer const * buf,
1279 LyXParagraph const * par) const
1281 if (textclasslist.Style(buf->params.textclass,
1282 par->GetLayout()).labeltype != LABEL_MANUAL)
1285 return par->BeginningOfMainBody();
1290 /* if there is a selection, reset every environment you can find
1291 * in the selection, otherwise just the environment you are in */
1292 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1294 LyXParagraph * tmppar, * firsttmppar;
1298 /* is is only allowed, if the cursor is IN an open footnote.
1299 * Otherwise it is too dangerous */
1300 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1303 SetUndo(bview->buffer(), Undo::FINISH,
1304 cursor.par()->PreviousBeforeFootnote()->previous,
1305 cursor.par()->NextAfterFootnote()->next);
1307 /* ok, move to the beginning of the footnote. */
1308 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1309 cursor.par(cursor.par()->Previous());
1311 SetCursor(bview, cursor.par(), cursor.par()->Last());
1312 /* this is just faster than using CursorLeft(); */
1314 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1315 tmppar = firsttmppar;
1316 /* tmppar is now the paragraph right before the footnote */
1318 bool first_footnote_par_is_not_empty = tmppar->next->size();
1321 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1322 tmppar = tmppar->next; /* I use next instead of Next(),
1323 * because there cannot be any
1324 * footnotes in a footnote
1326 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1328 /* remember the captions and empty paragraphs */
1329 if ((textclasslist.Style(bview->buffer()->params.textclass,
1330 tmppar->GetLayout())
1331 .labeltype == LABEL_SENSITIVE)
1333 tmppar->SetLayout(bview->buffer()->params, 0);
1336 // now we will paste the ex-footnote, if the layouts allow it
1337 // first restore the layout of the paragraph right behind
1340 tmppar->next->MakeSameLayout(cursor.par());
1343 if ((!tmppar->GetLayout() && !tmppar->table)
1345 && (!tmppar->Next()->Last()
1346 || tmppar->Next()->HasSameLayout(tmppar)))) {
1347 if (tmppar->Next()->Last()
1348 && tmppar->Next()->IsLineSeparator(0))
1349 tmppar->Next()->Erase(0);
1350 tmppar->PasteParagraph(bview->buffer()->params);
1353 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1354 * by the pasting of the beginning */
1356 /* then the beginning */
1357 /* if there is no space between the text and the footnote, so we insert
1359 * (only if the previous par and the footnotepar are not empty!) */
1360 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1361 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1362 if (firsttmppar->size()
1363 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1364 && first_footnote_par_is_not_empty) {
1365 firsttmppar->next->InsertChar(0, ' ');
1367 firsttmppar->PasteParagraph(bview->buffer()->params);
1370 /* now redo the paragaphs */
1371 RedoParagraphs(bview, cursor, tmppar);
1373 SetCursor(bview, cursor.par(), cursor.pos());
1375 /* sometimes it can happen, that there is a counter change */
1376 Row * row = cursor.row();
1377 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1379 UpdateCounters(bview, row);
1387 /* the DTP switches for paragraphs. LyX will store them in the
1388 * first physicla paragraph. When a paragraph is broken, the top settings
1389 * rest, the bottom settings are given to the new one. So I can make shure,
1390 * they do not duplicate themself and you cannnot make dirty things with
1393 void LyXText::SetParagraph(BufferView * bview,
1394 bool line_top, bool line_bottom,
1395 bool pagebreak_top, bool pagebreak_bottom,
1396 VSpace const & space_top,
1397 VSpace const & space_bottom,
1399 string labelwidthstring,
1402 LyXCursor tmpcursor = cursor;
1404 sel_start_cursor = cursor;
1405 sel_end_cursor = cursor;
1408 // make sure that the depth behind the selection are restored, too
1409 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1410 LyXParagraph * undoendpar = endpar;
1412 if (endpar && endpar->GetDepth()) {
1413 while (endpar && endpar->GetDepth()) {
1414 endpar = endpar->LastPhysicalPar()->Next();
1415 undoendpar = endpar;
1419 endpar = endpar->Next(); // because of parindents etc.
1422 SetUndo(bview->buffer(), Undo::EDIT,
1424 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1428 LyXParagraph * tmppar = sel_end_cursor.par();
1429 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1430 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1431 status = LyXText::NEED_MORE_REFRESH;
1432 refresh_row = cursor.row();
1433 refresh_y = cursor.y() - cursor.row()->baseline();
1434 if (cursor.par()->footnoteflag ==
1435 sel_start_cursor.par()->footnoteflag) {
1436 cursor.par()->line_top = line_top;
1437 cursor.par()->line_bottom = line_bottom;
1438 cursor.par()->pagebreak_top = pagebreak_top;
1439 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1440 cursor.par()->added_space_top = space_top;
1441 cursor.par()->added_space_bottom = space_bottom;
1442 // does the layout allow the new alignment?
1443 if (align == LYX_ALIGN_LAYOUT)
1444 align = textclasslist
1445 .Style(bview->buffer()->params.textclass,
1446 cursor.par()->GetLayout()).align;
1447 if (align & textclasslist
1448 .Style(bview->buffer()->params.textclass,
1449 cursor.par()->GetLayout()).alignpossible) {
1450 if (align == textclasslist
1451 .Style(bview->buffer()->params.textclass,
1452 cursor.par()->GetLayout()).align)
1453 cursor.par()->align = LYX_ALIGN_LAYOUT;
1455 cursor.par()->align = align;
1457 cursor.par()->SetLabelWidthString(labelwidthstring);
1458 cursor.par()->noindent = noindent;
1461 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1464 RedoParagraphs(bview, sel_start_cursor, endpar);
1467 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1468 sel_cursor = cursor;
1469 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1471 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1475 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1477 char const * widthp,
1478 int alignment, bool hfill,
1479 bool start_minipage)
1481 LyXCursor tmpcursor = cursor;
1482 LyXParagraph * tmppar;
1484 sel_start_cursor = cursor;
1485 sel_end_cursor = cursor;
1488 // make sure that the depth behind the selection are restored, too
1489 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1490 LyXParagraph * undoendpar = endpar;
1492 if (endpar && endpar->GetDepth()) {
1493 while (endpar && endpar->GetDepth()) {
1494 endpar = endpar->LastPhysicalPar()->Next();
1495 undoendpar = endpar;
1499 endpar = endpar->Next(); // because of parindents etc.
1502 SetUndo(bview->buffer(), Undo::EDIT,
1504 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1507 tmppar = sel_end_cursor.par();
1508 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1509 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1510 status = LyXText::NEED_MORE_REFRESH;
1511 refresh_row = cursor.row();
1512 refresh_y = cursor.y() - cursor.row()->baseline();
1513 if (cursor.par()->footnoteflag ==
1514 sel_start_cursor.par()->footnoteflag) {
1515 if (type == LyXParagraph::PEXTRA_NONE) {
1516 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1517 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1518 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1521 cursor.par()->SetPExtraType(bview->buffer()->params,
1522 type, width, widthp);
1523 cursor.par()->pextra_hfill = hfill;
1524 cursor.par()->pextra_start_minipage = start_minipage;
1525 cursor.par()->pextra_alignment = alignment;
1528 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1530 RedoParagraphs(bview, sel_start_cursor, endpar);
1532 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1533 sel_cursor = cursor;
1534 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1536 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1540 char loweralphaCounter(int n)
1542 if (n < 1 || n > 26)
1548 char alphaCounter(int n)
1550 if (n < 1 || n > 26)
1556 char hebrewCounter(int n)
1558 static const char hebrew[22] = {
1559 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1560 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1561 '÷', 'ø', 'ù', 'ú'
1563 if (n < 1 || n > 22)
1569 static char const * romanCounter(int n)
1571 static char const * roman[20] = {
1572 "i", "ii", "iii", "iv", "v",
1573 "vi", "vii", "viii", "ix", "x",
1574 "xi", "xii", "xiii", "xiv", "xv",
1575 "xvi", "xvii", "xviii", "xix", "xx"
1577 if (n < 1 || n > 20)
1583 // set the counter of a paragraph. This includes the labels
1584 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1586 // this is only relevant for the beginning of paragraph
1587 par = par->FirstPhysicalPar();
1589 LyXLayout const & layout =
1590 textclasslist.Style(buf->params.textclass,
1593 LyXTextClass const & textclass =
1594 textclasslist.TextClass(buf->params.textclass);
1596 /* copy the prev-counters to this one, unless this is the start of a
1597 footnote or of a bibliography or the very first paragraph */
1599 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1600 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1601 && par->footnotekind == LyXParagraph::FOOTNOTE)
1602 && !(textclasslist.Style(buf->params.textclass,
1603 par->Previous()->GetLayout()
1604 ).labeltype != LABEL_BIBLIO
1605 && layout.labeltype == LABEL_BIBLIO)) {
1606 for (int i = 0; i < 10; ++i) {
1607 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1609 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1610 if (!par->appendix && par->start_of_appendix){
1611 par->appendix = true;
1612 for (int i = 0; i < 10; ++i) {
1613 par->setCounter(i, 0);
1616 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1617 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1620 for (int i = 0; i < 10; ++i) {
1621 par->setCounter(i, 0);
1623 par->appendix = par->start_of_appendix;
1629 // if this is an open marginnote and this is the first
1630 // entry in the marginnote and the enclosing
1631 // environment is an enum/item then correct for the
1632 // LaTeX behaviour (ARRae)
1633 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1634 && par->footnotekind == LyXParagraph::MARGIN
1636 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1637 && (par->PreviousBeforeFootnote()
1638 && textclasslist.Style(buf->params.textclass,
1639 par->PreviousBeforeFootnote()->GetLayout()
1640 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1641 // Any itemize or enumerate environment in a marginnote
1642 // that is embedded in an itemize or enumerate
1643 // paragraph is seen by LaTeX as being at a deeper
1644 // level within that enclosing itemization/enumeration
1645 // even if there is a "standard" layout at the start of
1651 /* Maybe we have to increment the enumeration depth.
1652 * BUT, enumeration in a footnote is considered in isolation from its
1653 * surrounding paragraph so don't increment if this is the
1654 * first line of the footnote
1655 * AND, bibliographies can't have their depth changed ie. they
1656 * are always of depth 0
1659 && par->Previous()->GetDepth() < par->GetDepth()
1660 && textclasslist.Style(buf->params.textclass,
1661 par->Previous()->GetLayout()
1662 ).labeltype == LABEL_COUNTER_ENUMI
1663 && par->enumdepth < 3
1664 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1665 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1666 && par->footnotekind == LyXParagraph::FOOTNOTE)
1667 && layout.labeltype != LABEL_BIBLIO) {
1671 /* Maybe we have to decrement the enumeration depth, see note above */
1673 && par->Previous()->GetDepth() > par->GetDepth()
1674 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1675 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1676 && par->footnotekind == LyXParagraph::FOOTNOTE)
1677 && layout.labeltype != LABEL_BIBLIO) {
1678 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1679 par->setCounter(6 + par->enumdepth,
1680 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1681 /* reset the counters.
1682 * A depth change is like a breaking layout
1684 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1685 par->setCounter(i, 0);
1688 if (!par->labelstring.empty()) {
1689 par->labelstring.erase();
1692 if (layout.margintype == MARGIN_MANUAL) {
1693 if (par->labelwidthstring.empty()) {
1694 par->SetLabelWidthString(layout.labelstring());
1697 par->SetLabelWidthString(string());
1700 /* is it a layout that has an automatic label ? */
1701 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1703 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1704 if (i >= 0 && i<= buf->params.secnumdepth) {
1705 par->incCounter(i); // increment the counter
1707 // Is there a label? Useful for Chapter layout
1708 if (!par->appendix){
1709 if (!layout.labelstring().empty())
1710 par->labelstring = layout.labelstring();
1712 par->labelstring.erase();
1714 if (!layout.labelstring_appendix().empty())
1715 par->labelstring = layout.labelstring_appendix();
1717 par->labelstring.erase();
1721 std::ostringstream s;
1725 if (!par->appendix) {
1726 switch (2 * LABEL_FIRST_COUNTER -
1727 textclass.maxcounter() + i) {
1728 case LABEL_COUNTER_CHAPTER:
1729 s << par->getCounter(i);
1731 case LABEL_COUNTER_SECTION:
1732 s << par->getCounter(i - 1) << '.'
1733 << par->getCounter(i);
1735 case LABEL_COUNTER_SUBSECTION:
1736 s << par->getCounter(i - 2) << '.'
1737 << par->getCounter(i - 1) << '.'
1738 << par->getCounter(i);
1740 case LABEL_COUNTER_SUBSUBSECTION:
1741 s << par->getCounter(i - 3) << '.'
1742 << par->getCounter(i - 2) << '.'
1743 << par->getCounter(i - 1) << '.'
1744 << par->getCounter(i);
1747 case LABEL_COUNTER_PARAGRAPH:
1748 s << par->getCounter(i - 4) << '.'
1749 << par->getCounter(i - 3) << '.'
1750 << par->getCounter(i - 2) << '.'
1751 << par->getCounter(i - 1) << '.'
1752 << par->getCounter(i);
1754 case LABEL_COUNTER_SUBPARAGRAPH:
1755 s << par->getCounter(i - 5) << '.'
1756 << par->getCounter(i - 4) << '.'
1757 << par->getCounter(i - 3) << '.'
1758 << par->getCounter(i - 2) << '.'
1759 << par->getCounter(i - 1) << '.'
1760 << par->getCounter(i);
1764 s << par->getCounter(i) << '.';
1767 } else { // appendix
1768 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1769 case LABEL_COUNTER_CHAPTER:
1770 if (par->isRightToLeftPar(buf->params))
1771 s << hebrewCounter(par->getCounter(i));
1773 s << alphaCounter(par->getCounter(i));
1775 case LABEL_COUNTER_SECTION:
1776 if (par->isRightToLeftPar(buf->params))
1777 s << hebrewCounter(par->getCounter(i - 1));
1779 s << alphaCounter(par->getCounter(i - 1));
1782 << par->getCounter(i);
1785 case LABEL_COUNTER_SUBSECTION:
1786 if (par->isRightToLeftPar(buf->params))
1787 s << hebrewCounter(par->getCounter(i - 2));
1789 s << alphaCounter(par->getCounter(i - 2));
1792 << par->getCounter(i-1) << '.'
1793 << par->getCounter(i);
1796 case LABEL_COUNTER_SUBSUBSECTION:
1797 if (par->isRightToLeftPar(buf->params))
1798 s << hebrewCounter(par->getCounter(i-3));
1800 s << alphaCounter(par->getCounter(i-3));
1803 << par->getCounter(i-2) << '.'
1804 << par->getCounter(i-1) << '.'
1805 << par->getCounter(i);
1808 case LABEL_COUNTER_PARAGRAPH:
1809 if (par->isRightToLeftPar(buf->params))
1810 s << hebrewCounter(par->getCounter(i-4));
1812 s << alphaCounter(par->getCounter(i-4));
1815 << par->getCounter(i-3) << '.'
1816 << par->getCounter(i-2) << '.'
1817 << par->getCounter(i-1) << '.'
1818 << par->getCounter(i);
1821 case LABEL_COUNTER_SUBPARAGRAPH:
1822 if (par->isRightToLeftPar(buf->params))
1823 s << hebrewCounter(par->getCounter(i-5));
1825 s << alphaCounter(par->getCounter(i-5));
1828 << par->getCounter(i-4) << '.'
1829 << par->getCounter(i-3) << '.'
1830 << par->getCounter(i-2) << '.'
1831 << par->getCounter(i-1) << '.'
1832 << par->getCounter(i);
1836 // Can this ever be reached? And in the
1837 // case it is, how can this be correct?
1839 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1845 par->labelstring += s.str().c_str();
1846 // We really want to remove the c_str as soon as
1850 char * tmps = s.str();
1851 par->labelstring += tmps;
1855 for (i++; i < 10; ++i) {
1856 // reset the following counters
1857 par->setCounter(i, 0);
1859 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1860 for (i++; i < 10; ++i) {
1861 // reset the following counters
1862 par->setCounter(i, 0);
1864 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1865 par->incCounter(i + par->enumdepth);
1866 int number = par->getCounter(i + par->enumdepth);
1869 std::ostringstream s;
1873 switch (par->enumdepth) {
1875 if (par->isRightToLeftPar(buf->params))
1877 << hebrewCounter(number)
1881 << loweralphaCounter(number)
1885 if (par->isRightToLeftPar(buf->params))
1886 s << '.' << romanCounter(number);
1888 s << romanCounter(number) << '.';
1891 if (par->isRightToLeftPar(buf->params))
1893 << alphaCounter(number);
1895 s << alphaCounter(number)
1899 if (par->isRightToLeftPar(buf->params))
1906 par->labelstring = s.str().c_str();
1907 // we really want to get rid of that c_str()
1910 char * tmps = s.str();
1911 par->labelstring = tmps;
1915 for (i += par->enumdepth + 1; i < 10; ++i)
1916 par->setCounter(i, 0); /* reset the following counters */
1919 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1920 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1922 int number = par->getCounter(i);
1924 par->bibkey = new InsetBibKey();
1925 par->bibkey->setCounter(number);
1926 par->labelstring = layout.labelstring();
1928 // In biblio should't be following counters but...
1930 string s = layout.labelstring();
1932 // the caption hack:
1934 if (layout.labeltype == LABEL_SENSITIVE) {
1935 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1936 && (par->footnotekind == LyXParagraph::FIG
1937 || par->footnotekind == LyXParagraph::WIDE_FIG))
1938 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1939 ? ":øåéà " : "Figure:";
1940 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1941 && (par->footnotekind == LyXParagraph::TAB
1942 || par->footnotekind == LyXParagraph::WIDE_TAB))
1943 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1944 ? ":äìáè" : "Table:";
1945 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1946 && par->footnotekind == LyXParagraph::ALGORITHM)
1947 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1948 ? ":Ãúéøåâìà " : "Algorithm:";
1950 /* par->SetLayout(0);
1951 s = layout->labelstring; */
1952 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1953 ? " :úåòîùî øñç" : "Senseless: ";
1956 par->labelstring = s;
1958 /* reset the enumeration counter. They are always resetted
1959 * when there is any other layout between */
1960 for (int i = 6 + par->enumdepth; i < 10; ++i)
1961 par->setCounter(i, 0);
1966 /* Updates all counters BEHIND the row. Changed paragraphs
1967 * with a dynamic left margin will be rebroken. */
1968 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1976 if (row->par()->next
1977 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1978 par = row->par()->LastPhysicalPar()->Next();
1980 par = row->par()->next;
1985 while (row->par() != par)
1988 SetCounter(bview->buffer(), par);
1990 /* now check for the headline layouts. remember that they
1991 * have a dynamic left margin */
1993 && ( textclasslist.Style(bview->buffer()->params.textclass,
1994 par->layout).margintype == MARGIN_DYNAMIC
1995 || textclasslist.Style(bview->buffer()->params.textclass,
1996 par->layout).labeltype == LABEL_SENSITIVE)
1999 /* Rebreak the paragraph */
2000 RemoveParagraph(row);
2001 AppendParagraph(bview, row);
2004 /* think about the damned open footnotes! */
2005 while (par->Next() &&
2006 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2007 || par->Next()->IsDummy())){
2009 if (par->IsDummy()) {
2010 while (row->par() != par)
2012 RemoveParagraph(row);
2013 AppendParagraph(bview, row);
2019 par = par->LastPhysicalPar()->Next();
2025 /* insets an inset. */
2026 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2028 if (!cursor.par()->InsertInsetAllowed(inset))
2030 SetUndo(bview->buffer(), Undo::INSERT,
2031 cursor.par()->ParFromPos(cursor.pos())->previous,
2032 cursor.par()->ParFromPos(cursor.pos())->next);
2033 cursor.par()->InsertInset(cursor.pos(), inset);
2034 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2035 * The character will not be inserted a
2040 void LyXText::copyEnvironmentType()
2042 copylayouttype = cursor.par()->GetLayout();
2046 void LyXText::pasteEnvironmentType(BufferView * bview)
2048 SetLayout(bview, copylayouttype);
2052 void LyXText::CutSelection(BufferView * bview, bool doclear)
2054 // Stuff what we got on the clipboard. Even if there is no selection.
2056 // There is a problem with having the stuffing here in that the
2057 // larger the selection the slower LyX will get. This can be
2058 // solved by running the line below only when the selection has
2059 // finished. The solution used currently just works, to make it
2060 // faster we need to be more clever and probably also have more
2061 // calls to stuffClipboard. (Lgb)
2062 bview->stuffClipboard(selectionAsString(bview->buffer()));
2064 // This doesn't make sense, if there is no selection
2068 // OK, we have a selection. This is always between sel_start_cursor
2069 // and sel_end cursor
2070 LyXParagraph * tmppar;
2073 // Check whether there are half footnotes in the selection
2074 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2075 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2076 tmppar = sel_start_cursor.par();
2077 while (tmppar != sel_end_cursor.par()){
2078 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2079 WriteAlert(_("Impossible operation"),
2080 _("Don't know what to do with half floats."),
2084 tmppar = tmppar->Next();
2089 /* table stuff -- begin */
2090 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2091 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2092 WriteAlert(_("Impossible operation"),
2093 _("Don't know what to do with half tables."),
2097 sel_start_cursor.par()->table->Reinit();
2099 /* table stuff -- end */
2101 // make sure that the depth behind the selection are restored, too
2102 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2103 LyXParagraph * undoendpar = endpar;
2105 if (endpar && endpar->GetDepth()) {
2106 while (endpar && endpar->GetDepth()) {
2107 endpar = endpar->LastPhysicalPar()->Next();
2108 undoendpar = endpar;
2110 } else if (endpar) {
2111 endpar = endpar->Next(); // because of parindents etc.
2114 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2115 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2119 // there are two cases: cut only within one paragraph or
2120 // more than one paragraph
2121 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2122 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2123 // only within one paragraph
2124 endpar = sel_start_cursor.par();
2125 int pos = sel_end_cursor.pos();
2126 cap.cutSelection(sel_start_cursor.par(), &endpar,
2127 sel_start_cursor.pos(), pos,
2128 bview->buffer()->params.textclass, doclear);
2129 sel_end_cursor.pos(pos);
2131 endpar = sel_end_cursor.par();
2133 int pos = sel_end_cursor.pos();
2134 cap.cutSelection(sel_start_cursor.par(), &endpar,
2135 sel_start_cursor.pos(), pos,
2136 bview->buffer()->params.textclass, doclear);
2138 sel_end_cursor.par(endpar);
2139 sel_end_cursor.pos(pos);
2140 cursor.pos(sel_end_cursor.pos());
2142 endpar = endpar->Next();
2144 // sometimes necessary
2146 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2148 RedoParagraphs(bview, sel_start_cursor, endpar);
2151 cursor = sel_start_cursor;
2152 SetCursor(bview, cursor.par(), cursor.pos());
2153 sel_cursor = cursor;
2154 UpdateCounters(bview, cursor.row());
2158 void LyXText::CopySelection(BufferView * bview)
2160 // Stuff what we got on the clipboard. Even if there is no selection.
2162 // There is a problem with having the stuffing here in that the
2163 // larger the selection the slower LyX will get. This can be
2164 // solved by running the line below only when the selection has
2165 // finished. The solution used currently just works, to make it
2166 // faster we need to be more clever and probably also have more
2167 // calls to stuffClipboard. (Lgb)
2168 bview->stuffClipboard(selectionAsString(bview->buffer()));
2170 // this doesnt make sense, if there is no selection
2174 // ok we have a selection. This is always between sel_start_cursor
2175 // and sel_end cursor
2176 LyXParagraph * tmppar;
2179 /* check wether there are half footnotes in the selection */
2180 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2181 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2182 tmppar = sel_start_cursor.par();
2183 while (tmppar != sel_end_cursor.par()) {
2184 if (tmppar->footnoteflag !=
2185 sel_end_cursor.par()->footnoteflag) {
2186 WriteAlert(_("Impossible operation"),
2187 _("Don't know what to do"
2188 " with half floats."),
2192 tmppar = tmppar->Next();
2197 /* table stuff -- begin */
2198 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2199 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2200 WriteAlert(_("Impossible operation"),
2201 _("Don't know what to do with half tables."),
2206 /* table stuff -- end */
2209 // copy behind a space if there is one
2210 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2211 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2212 && (sel_start_cursor.par() != sel_end_cursor.par()
2213 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2214 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2218 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2219 sel_start_cursor.pos(), sel_end_cursor.pos(),
2220 bview->buffer()->params.textclass);
2224 void LyXText::PasteSelection(BufferView * bview)
2228 // this does not make sense, if there is nothing to paste
2229 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2232 SetUndo(bview->buffer(), Undo::INSERT,
2233 cursor.par()->ParFromPos(cursor.pos())->previous,
2234 cursor.par()->ParFromPos(cursor.pos())->next);
2236 LyXParagraph * endpar;
2237 LyXParagraph * actpar = cursor.par();
2239 int pos = cursor.pos();
2240 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2242 RedoParagraphs(bview, cursor, endpar);
2244 SetCursor(bview, cursor.par(), cursor.pos());
2247 sel_cursor = cursor;
2248 SetCursor(bview, actpar, pos);
2250 UpdateCounters(bview, cursor.row());
2254 // returns a pointer to the very first LyXParagraph
2255 LyXParagraph * LyXText::FirstParagraph() const
2257 return OwnerParagraph();
2261 // returns true if the specified string is at the specified position
2262 bool LyXText::IsStringInText(LyXParagraph * par,
2263 LyXParagraph::size_type pos,
2264 char const * str) const
2268 while (pos + i < par->Last() && str[i] &&
2269 str[i] == par->GetChar(pos + i)) {
2279 // sets the selection over the number of characters of string, no check!!
2280 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2282 sel_cursor = cursor;
2283 for (int i = 0; string[i]; ++i)
2289 // simple replacing. The font of the first selected character is used
2290 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2292 SetCursorParUndo(bview->buffer());
2295 if (!selection) { // create a dummy selection
2296 sel_end_cursor = cursor;
2297 sel_start_cursor = cursor;
2300 // Get font setting before we cut
2301 LyXParagraph::size_type pos = sel_end_cursor.pos();
2302 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2303 sel_start_cursor.pos());
2305 // Insert the new string
2306 for (int i = 0; str[i]; ++i) {
2307 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2311 // Cut the selection
2312 CutSelection(bview);
2318 // if the string can be found: return true and set the cursor to
2320 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2322 LyXParagraph * par = cursor.par();
2323 LyXParagraph::size_type pos = cursor.pos();
2324 while (par && !IsStringInText(par, pos, str)) {
2325 if (pos < par->Last() - 1)
2333 SetCursor(bview, par, pos);
2341 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2343 LyXParagraph * par = cursor.par();
2344 int pos = cursor.pos();
2350 // We skip empty paragraphs (Asger)
2352 par = par->Previous();
2354 pos = par->Last() - 1;
2355 } while (par && pos < 0);
2357 } while (par && !IsStringInText(par, pos, string));
2360 SetCursor(bview, par, pos);
2367 // needed to insert the selection
2368 void LyXText::InsertStringA(BufferView * bview, string const & str)
2370 LyXParagraph * par = cursor.par();
2371 LyXParagraph::size_type pos = cursor.pos();
2372 LyXParagraph::size_type a = 0;
2374 LyXParagraph * endpar = cursor.par()->Next();
2376 SetCursorParUndo(bview->buffer());
2379 textclasslist.Style(bview->buffer()->params.textclass,
2380 cursor.par()->GetLayout()).isEnvironment();
2381 // only to be sure, should not be neccessary
2384 // insert the string, don't insert doublespace
2385 string::size_type i = 0;
2386 while (i < str.length()) {
2387 if (str[i] != '\n') {
2389 && i + 1 < str.length() && str[i + 1] != ' '
2390 && pos && par->GetChar(pos - 1)!= ' ') {
2391 par->InsertChar(pos, ' ', current_font);
2394 } else if (par->table) {
2395 if (str[i] == '\t') {
2396 while((pos < par->size()) &&
2397 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2399 if (pos < par->size())
2401 else // no more fields to fill skip the rest
2403 } else if ((str[i] != 13) &&
2404 ((str[i] & 127) >= ' ')) {
2405 par->InsertChar(pos, str[i],
2410 } else if (str[i] == ' ') {
2411 InsetSpecialChar * new_inset =
2412 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2413 if (par->InsertInsetAllowed(new_inset)) {
2414 par->InsertInset(pos, new_inset,
2420 } else if (str[i] == '\t') {
2421 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2422 InsetSpecialChar * new_inset =
2423 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2424 if (par->InsertInsetAllowed(new_inset)) {
2425 par->InsertInset(pos, new_inset,
2432 } else if (str[i] != 13 &&
2433 // Ignore unprintables
2434 (str[i] & 127) >= ' ') {
2435 par->InsertChar(pos, str[i], current_font);
2441 if ((i + 1) >= str.length()) {
2442 if (pos < par->size())
2446 while((pos < par->size()) &&
2447 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2450 cell = NumberOfCell(par, pos);
2451 while((pos < par->size()) &&
2452 !(par->table->IsFirstCell(cell))) {
2454 while((pos < par->size()) &&
2455 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2458 cell = NumberOfCell(par, pos);
2460 if (pos >= par->size())
2461 // no more fields to fill skip the rest
2465 if (!par->size()) { // par is empty
2466 InsetSpecialChar * new_inset =
2467 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2468 if (par->InsertInsetAllowed(new_inset)) {
2469 par->InsertInset(pos,
2477 par->BreakParagraph(bview->buffer()->params, pos, flag);
2487 RedoParagraphs(bview, cursor, endpar);
2488 SetCursor(bview, cursor.par(), cursor.pos());
2489 sel_cursor = cursor;
2490 SetCursor(bview, par, pos);
2495 /* turns double-CR to single CR, others where converted into one blank and 13s
2496 * that are ignored .Double spaces are also converted into one. Spaces at
2497 * the beginning of a paragraph are forbidden. tabs are converted into one
2498 * space. then InsertStringA is called */
2499 void LyXText::InsertStringB(BufferView * bview, string const & s)
2502 LyXParagraph * par = cursor.par();
2503 string::size_type i = 1;
2504 while (i < str.length()) {
2505 if (str[i] == '\t' && !par->table)
2507 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2509 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2510 if (str[i + 1] != '\n') {
2511 if (str[i - 1] != ' ')
2516 while (i + 1 < str.length()
2517 && (str[i + 1] == ' '
2518 || str[i + 1] == '\t'
2519 || str[i + 1] == '\n'
2520 || str[i + 1] == 13)) {
2527 InsertStringA(bview, str);
2531 bool LyXText::GotoNextError(BufferView * bview) const
2533 LyXCursor res = cursor;
2535 if (res.pos() < res.par()->Last() - 1) {
2536 res.pos(res.pos() + 1);
2538 res.par(res.par()->Next());
2542 } while (res.par() &&
2543 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2544 && res.par()->GetInset(res.pos())->AutoDelete()));
2547 SetCursor(bview, res.par(), res.pos());
2554 bool LyXText::GotoNextNote(BufferView * bview) const
2556 LyXCursor res = cursor;
2558 if (res.pos() < res.par()->Last() - 1) {
2559 res.pos(res.pos() + 1);
2561 res.par(res.par()->Next());
2565 } while (res.par() &&
2566 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2567 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2570 SetCursor(bview, res.par(), res.pos());
2577 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2578 LyXParagraph::size_type pos)
2580 LyXCursor tmpcursor;
2583 /* table stuff -- begin*/
2586 CheckParagraphInTable(bview, par, pos);
2590 /* table stuff -- end*/
2593 LyXParagraph::size_type z;
2594 Row * row = GetRow(par, pos, y);
2596 // is there a break one row above
2597 if (row->previous() && row->previous()->par() == row->par()) {
2598 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2599 if ( z >= row->pos()) {
2600 // set the dimensions of the row above
2601 y -= row->previous()->height();
2603 refresh_row = row->previous();
2604 status = LyXText::NEED_MORE_REFRESH;
2606 BreakAgain(bview, row->previous());
2608 // set the cursor again. Otherwise
2609 // dangling pointers are possible
2610 SetCursor(bview, cursor.par(), cursor.pos());
2611 sel_cursor = cursor;
2616 int tmpheight = row->height();
2617 LyXParagraph::size_type tmplast = RowLast(row);
2621 BreakAgain(bview, row);
2622 if (row->height() == tmpheight && RowLast(row) == tmplast)
2623 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2625 status = LyXText::NEED_MORE_REFRESH;
2627 // check the special right address boxes
2628 if (textclasslist.Style(bview->buffer()->params.textclass,
2629 par->GetLayout()).margintype
2630 == MARGIN_RIGHT_ADDRESS_BOX) {
2637 RedoDrawingOfParagraph(bview, tmpcursor);
2643 // set the cursor again. Otherwise dangling pointers are possible
2644 // also set the selection
2648 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2649 sel_cursor = cursor;
2650 SetCursorIntern(bview, sel_start_cursor.par(),
2651 sel_start_cursor.pos());
2652 sel_start_cursor = cursor;
2653 SetCursorIntern(bview, sel_end_cursor.par(),
2654 sel_end_cursor.pos());
2655 sel_end_cursor = cursor;
2656 SetCursorIntern(bview, last_sel_cursor.par(),
2657 last_sel_cursor.pos());
2658 last_sel_cursor = cursor;
2661 SetCursorIntern(bview, cursor.par(), cursor.pos());
2665 // returns false if inset wasn't found
2666 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2668 // first check the current paragraph
2669 int pos = cursor.par()->GetPositionOfInset(inset);
2671 CheckParagraph(bview, cursor.par(), pos);
2675 // check every paragraph
2677 LyXParagraph * par = FirstParagraph();
2679 // make sure the paragraph is open
2680 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2681 pos = par->GetPositionOfInset(inset);
2683 CheckParagraph(bview, par, pos);
2694 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2695 LyXParagraph::size_type pos,
2696 bool setfont, bool boundary) const
2698 LyXCursor old_cursor = cursor;
2699 SetCursorIntern(bview, par, pos, setfont, boundary);
2700 DeleteEmptyParagraphMechanism(bview, old_cursor);
2704 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2705 LyXParagraph::size_type pos, bool boundary) const
2707 // correct the cursor position if impossible
2708 if (pos > par->Last()){
2709 LyXParagraph * tmppar = par->ParFromPos(pos);
2710 pos = par->PositionInParFromPos(pos);
2714 if (par->IsDummy() && par->previous &&
2715 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2716 while (par->previous &&
2717 ((par->previous->IsDummy() &&
2718 (par->previous->previous->footnoteflag ==
2719 LyXParagraph::CLOSED_FOOTNOTE)) ||
2720 (par->previous->footnoteflag ==
2721 LyXParagraph::CLOSED_FOOTNOTE))) {
2722 par = par->previous ;
2723 if (par->IsDummy() &&
2724 (par->previous->footnoteflag ==
2725 LyXParagraph::CLOSED_FOOTNOTE))
2726 pos += par->size() + 1;
2728 if (par->previous) {
2729 par = par->previous;
2731 pos += par->size() + 1;
2736 cur.boundary(boundary);
2738 /* get the cursor y position in text */
2740 Row * row = GetRow(par, pos, y);
2741 /* y is now the beginning of the cursor row */
2742 y += row->baseline();
2743 /* y is now the cursor baseline */
2746 /* now get the cursors x position */
2748 float fill_separator, fill_hfill, fill_label_hfill;
2749 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2751 LyXParagraph::size_type cursor_vpos = 0;
2752 LyXParagraph::size_type last = RowLastPrintable(row);
2754 if (pos > last + 1) // This shouldn't happen.
2756 else if (pos < row->pos())
2759 if (last < row->pos())
2760 cursor_vpos = row->pos();
2761 else if (pos > last && !boundary)
2762 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2763 ? row->pos() : last + 1;
2764 else if (pos > row->pos() &&
2765 (pos > last || boundary ||
2766 (row->par()->table && row->par()->IsNewline(pos))))
2767 /// Place cursor after char at (logical) position pos - 1
2768 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2769 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2771 /// Place cursor before char at (logical) position pos
2772 cursor_vpos = (bidi_level(pos) % 2 == 0)
2773 ? log2vis(pos) : log2vis(pos) + 1;
2776 /* table stuff -- begin*/
2777 if (row->par()->table) {
2778 int cell = NumberOfCell(row->par(), row->pos());
2780 x += row->par()->table->GetBeginningOfTextInCell(cell);
2781 for (LyXParagraph::size_type vpos = row->pos();
2782 vpos < cursor_vpos; ++vpos) {
2783 pos = vis2log(vpos);
2784 if (row->par()->IsNewline(pos)) {
2785 x = x_old + row->par()->table->WidthOfColumn(cell);
2788 x += row->par()->table->GetBeginningOfTextInCell(cell);
2790 x += SingleWidth(bview, row->par(), pos);
2794 /* table stuff -- end*/
2796 LyXParagraph::size_type main_body =
2797 BeginningOfMainBody(bview->buffer(), row->par());
2798 if ((main_body > 0) &&
2799 ((main_body-1 > last) ||
2800 !row->par()->IsLineSeparator(main_body-1)))
2803 for (LyXParagraph::size_type vpos = row->pos();
2804 vpos < cursor_vpos; ++vpos) {
2805 pos = vis2log(vpos);
2806 if (main_body > 0 && pos == main_body-1) {
2807 x += fill_label_hfill +
2808 lyxfont::width(textclasslist.Style(
2809 bview->buffer()->params.textclass,
2810 row->par()->GetLayout())
2812 GetFont(bview->buffer(), row->par(), -2));
2813 if (row->par()->IsLineSeparator(main_body-1))
2814 x -= SingleWidth(bview, row->par(),main_body-1);
2816 if (HfillExpansion(bview->buffer(), row, pos)) {
2817 x += SingleWidth(bview, row->par(), pos);
2818 if (pos >= main_body)
2821 x += fill_label_hfill;
2822 } else if (row->par()->IsSeparator(pos)) {
2823 x += SingleWidth(bview, row->par(), pos);
2824 if (pos >= main_body)
2825 x += fill_separator;
2827 x += SingleWidth(bview, row->par(), pos);
2839 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2840 LyXParagraph::size_type pos,
2841 bool setfont, bool boundary) const
2843 SetCursor(bview, cursor, par, pos, boundary);
2845 SetCurrentFont(bview);
2848 void LyXText::SetCurrentFont(BufferView * bview) const
2850 LyXParagraph::size_type pos = cursor.pos();
2851 if (cursor.boundary() && pos > 0)
2855 if (pos == cursor.par()->Last() ||
2856 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2858 else if (cursor.par()->IsSeparator(pos)) {
2859 if (pos > cursor.row()->pos() &&
2860 bidi_level(pos) % 2 ==
2861 bidi_level(pos - 1) % 2)
2863 else if (pos + 1 < cursor.par()->Last())
2869 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2870 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2872 if (cursor.pos() == cursor.par()->Last() &&
2873 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2874 !cursor.boundary()) {
2875 Language const * lang =
2876 cursor.par()->getParLanguage(bview->buffer()->params);
2877 current_font.setLanguage(lang);
2878 real_current_font.setLanguage(lang);
2883 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2885 LyXCursor old_cursor = cursor;
2887 /* get the row first */
2889 Row * row = GetRowNearY(y);
2890 cursor.par(row->par());
2893 int column = GetColumnNearX(bview, row, x, bound);
2894 cursor.pos(row->pos() + column);
2896 cursor.y(y + row->baseline());
2898 cursor.boundary(bound);
2899 SetCurrentFont(bview);
2900 DeleteEmptyParagraphMechanism(bview, old_cursor);
2904 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2905 int x, long y) const
2907 /* get the row first */
2909 Row * row = GetRowNearY(y);
2911 int column = GetColumnNearX(bview, row, x, bound);
2913 cur.par(row->par());
2914 cur.pos(row->pos() + column);
2916 cur.y(y + row->baseline());
2918 cur.boundary(bound);
2922 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2924 CursorLeftIntern(bview, internal);
2926 if (cursor.par()->table) {
2927 int cell = NumberOfCell(cursor.par(), cursor.pos());
2928 if (cursor.par()->table->IsContRow(cell)
2929 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2937 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2939 if (cursor.pos() > 0) {
2940 bool boundary = cursor.boundary();
2941 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2942 if (!internal && !boundary &&
2943 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2944 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2945 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2946 LyXParagraph * par = cursor.par()->Previous();
2947 SetCursor(bview, par, par->Last());
2952 void LyXText::CursorRight(BufferView * bview, bool internal) const
2954 CursorRightIntern(bview, internal);
2956 if (cursor.par()->table) {
2957 int cell = NumberOfCell(cursor.par(), cursor.pos());
2958 if (cursor.par()->table->IsContRow(cell) &&
2959 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2967 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
2969 if (!internal && cursor.boundary() &&
2970 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
2971 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2972 else if (cursor.pos() < cursor.par()->Last()) {
2973 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2975 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2976 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2977 } else if (cursor.par()->Next())
2978 SetCursor(bview, cursor.par()->Next(), 0);
2982 void LyXText::CursorUp(BufferView * bview) const
2984 SetCursorFromCoordinates(bview, cursor.x_fix(),
2985 cursor.y() - cursor.row()->baseline() - 1);
2987 if (cursor.par()->table) {
2988 int cell = NumberOfCell(cursor.par(), cursor.pos());
2989 if (cursor.par()->table->IsContRow(cell) &&
2990 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2998 void LyXText::CursorDown(BufferView * bview) const
3001 if (cursor.par()->table &&
3002 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3003 !cursor.par()->next)
3007 SetCursorFromCoordinates(bview, cursor.x_fix(),
3008 cursor.y() - cursor.row()->baseline()
3009 + cursor.row()->height() + 1);
3011 if (cursor.par()->table) {
3012 int cell = NumberOfCell(cursor.par(), cursor.pos());
3013 int cell_above = cursor.par()->table->GetCellAbove(cell);
3014 while(cursor.par()->table &&
3015 cursor.par()->table->IsContRow(cell) &&
3016 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3017 SetCursorFromCoordinates(bview, cursor.x_fix(),
3018 cursor.y() - cursor.row()->baseline()
3019 + cursor.row()->height() + 1);
3020 if (cursor.par()->table) {
3021 cell = NumberOfCell(cursor.par(), cursor.pos());
3022 cell_above = cursor.par()->table->GetCellAbove(cell);
3030 void LyXText::CursorUpParagraph(BufferView * bview) const
3032 if (cursor.pos() > 0) {
3033 SetCursor(bview, cursor.par(), 0);
3035 else if (cursor.par()->Previous()) {
3036 SetCursor(bview, cursor.par()->Previous(), 0);
3041 void LyXText::CursorDownParagraph(BufferView * bview) const
3043 if (cursor.par()->Next()) {
3044 SetCursor(bview, cursor.par()->Next(), 0);
3046 SetCursor(bview, cursor.par(), cursor.par()->Last());
3051 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3052 LyXCursor const & old_cursor) const
3054 // Would be wrong to delete anything if we have a selection.
3055 if (selection) return;
3057 // We allow all kinds of "mumbo-jumbo" when freespacing.
3058 if (textclasslist.Style(bview->buffer()->params.textclass,
3059 old_cursor.par()->GetLayout()).free_spacing)
3062 bool deleted = false;
3064 /* Ok I'll put some comments here about what is missing.
3065 I have fixed BackSpace (and thus Delete) to not delete
3066 double-spaces automagically. I have also changed Cut,
3067 Copy and Paste to hopefully do some sensible things.
3068 There are still some small problems that can lead to
3069 double spaces stored in the document file or space at
3070 the beginning of paragraphs. This happens if you have
3071 the cursor betwenn to spaces and then save. Or if you
3072 cut and paste and the selection have a space at the
3073 beginning and then save right after the paste. I am
3074 sure none of these are very hard to fix, but I will
3075 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3076 that I can get some feedback. (Lgb)
3079 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3080 // delete the LineSeparator.
3083 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3084 // delete the LineSeparator.
3087 // If the pos around the old_cursor were spaces, delete one of them.
3088 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3089 // Only if the cursor has really moved
3091 if (old_cursor.pos() > 0
3092 && old_cursor.pos() < old_cursor.par()->Last()
3093 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3094 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3095 old_cursor.par()->Erase(old_cursor.pos() - 1);
3096 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3098 if (old_cursor.par() == cursor.par() &&
3099 cursor.pos() > old_cursor.pos()) {
3100 SetCursorIntern(bview, cursor.par(),
3103 SetCursorIntern(bview, cursor.par(),
3109 // Do not delete empty paragraphs with keepempty set.
3110 if ((textclasslist.Style(bview->buffer()->params.textclass,
3111 old_cursor.par()->GetLayout())).keepempty)
3114 LyXCursor tmpcursor;
3116 if (old_cursor.par() != cursor.par()) {
3117 if ( (old_cursor.par()->Last() == 0
3118 || (old_cursor.par()->Last() == 1
3119 && old_cursor.par()->IsLineSeparator(0)))
3120 && old_cursor.par()->FirstPhysicalPar()
3121 == old_cursor.par()->LastPhysicalPar()) {
3122 // ok, we will delete anything
3124 // make sure that you do not delete any environments
3125 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3126 !(old_cursor.row()->previous()
3127 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3128 && !(old_cursor.row()->next()
3129 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3130 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3131 && ((old_cursor.row()->previous()
3132 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3133 || (old_cursor.row()->next()
3134 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3136 status = LyXText::NEED_MORE_REFRESH;
3139 if (old_cursor.row()->previous()) {
3140 refresh_row = old_cursor.row()->previous();
3141 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3143 cursor = old_cursor; // that undo can restore the right cursor position
3144 LyXParagraph * endpar = old_cursor.par()->next;
3145 if (endpar && endpar->GetDepth()) {
3146 while (endpar && endpar->GetDepth()) {
3147 endpar = endpar->LastPhysicalPar()->Next();
3150 SetUndo(bview->buffer(), Undo::DELETE,
3151 old_cursor.par()->previous,
3156 RemoveRow(old_cursor.row());
3157 if (OwnerParagraph() == old_cursor.par()) {
3158 OwnerParagraph(OwnerParagraph()->next);
3161 delete old_cursor.par();
3163 /* Breakagain the next par. Needed
3164 * because of the parindent that
3165 * can occur or dissappear. The
3166 * next row can change its height,
3167 * if there is another layout before */
3168 if (refresh_row->next()) {
3169 BreakAgain(bview, refresh_row->next());
3170 UpdateCounters(bview, refresh_row);
3172 SetHeightOfRow(bview, refresh_row);
3174 refresh_row = old_cursor.row()->next();
3175 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3178 cursor = old_cursor; // that undo can restore the right cursor position
3179 LyXParagraph * endpar = old_cursor.par()->next;
3180 if (endpar && endpar->GetDepth()) {
3181 while (endpar && endpar->GetDepth()) {
3182 endpar = endpar->LastPhysicalPar()->Next();
3185 SetUndo(bview->buffer(), Undo::DELETE,
3186 old_cursor.par()->previous,
3191 RemoveRow(old_cursor.row());
3193 if (OwnerParagraph() == old_cursor.par()) {
3194 OwnerParagraph(OwnerParagraph()->next);
3196 delete old_cursor.par();
3198 /* Breakagain the next par. Needed
3199 because of the parindent that can
3200 occur or dissappear.
3201 The next row can change its height,
3202 if there is another layout before
3205 BreakAgain(bview, refresh_row);
3206 UpdateCounters(bview, refresh_row->previous());
3212 SetCursorIntern(bview, cursor.par(), cursor.pos());
3214 if (sel_cursor.par() == old_cursor.par()
3215 && sel_cursor.pos() == sel_cursor.pos()) {
3216 // correct selection
3217 sel_cursor = cursor;
3222 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3223 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3225 SetCursorIntern(bview, cursor.par(), cursor.pos());
3226 sel_cursor = cursor;
3233 LyXParagraph * LyXText::GetParFromID(int id)
3235 LyXParagraph * result = FirstParagraph();
3236 while (result && result->id() != id)
3237 result = result->next;
3243 bool LyXText::TextUndo(BufferView * bview)
3247 // returns false if no undo possible
3248 Undo * undo = bview->buffer()->undostack.pop();
3252 bview->buffer()->redostack
3253 .push(CreateUndo(bview->buffer(), undo->kind,
3254 GetParFromID(undo->number_of_before_par),
3255 GetParFromID(undo->number_of_behind_par)));
3257 return TextHandleUndo(bview, undo);
3261 bool LyXText::TextRedo(BufferView * bview)
3265 // returns false if no redo possible
3266 Undo * undo = bview->buffer()->redostack.pop();
3270 bview->buffer()->undostack
3271 .push(CreateUndo(bview->buffer(), undo->kind,
3272 GetParFromID(undo->number_of_before_par),
3273 GetParFromID(undo->number_of_behind_par)));
3275 return TextHandleUndo(bview, undo);
3279 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3283 // returns false if no undo possible
3284 bool result = false;
3286 LyXParagraph * before =
3287 GetParFromID(undo->number_of_before_par);
3288 LyXParagraph * behind =
3289 GetParFromID(undo->number_of_behind_par);
3290 LyXParagraph * tmppar;
3291 LyXParagraph * tmppar2;
3292 LyXParagraph * endpar;
3293 LyXParagraph * tmppar5;
3295 // if there's no before take the beginning
3296 // of the document for redoing
3298 SetCursorIntern(bview, FirstParagraph(), 0);
3300 // replace the paragraphs with the undo informations
3302 LyXParagraph * tmppar3 = undo->par;
3303 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3304 LyXParagraph * tmppar4 = tmppar3;
3306 while (tmppar4->next)
3307 tmppar4 = tmppar4->next;
3308 } // get last undo par
3310 // now remove the old text if there is any
3311 if (before != behind || (!behind && !before)){
3313 tmppar5 = before->next;
3315 tmppar5 = OwnerParagraph();
3317 while (tmppar5 && tmppar5 != behind){
3319 tmppar5 = tmppar5->next;
3320 // a memory optimization for edit: Only layout information
3321 // is stored in the undo. So restore the text informations.
3322 if (undo->kind == Undo::EDIT) {
3323 tmppar2->setContentsFromPar(tmppar);
3324 tmppar->clearContents();
3325 tmppar2 = tmppar2->next;
3330 // put the new stuff in the list if there is one
3333 before->next = tmppar3;
3335 OwnerParagraph(tmppar3);
3336 tmppar3->previous = before;
3340 OwnerParagraph(behind);
3343 tmppar4->next = behind;
3345 behind->previous = tmppar4;
3349 // Set the cursor for redoing
3351 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3352 // check wether before points to a closed float and open it if necessary
3353 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3354 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3356 while (tmppar4->previous &&
3357 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3358 tmppar4 = tmppar4->previous;
3359 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3360 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3361 tmppar4 = tmppar4->next;
3366 // open a cosed footnote at the end if necessary
3367 if (behind && behind->previous &&
3368 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3369 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3370 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3371 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3372 behind = behind->next;
3376 // calculate the endpar for redoing the paragraphs.
3378 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3379 endpar = behind->LastPhysicalPar()->Next();
3381 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3385 tmppar = GetParFromID(undo->number_of_cursor_par);
3386 RedoParagraphs(bview, cursor, endpar);
3388 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3389 UpdateCounters(bview, cursor.row());
3399 void LyXText::FinishUndo()
3403 // makes sure the next operation will be stored
3404 undo_finished = true;
3408 void LyXText::FreezeUndo()
3412 // this is dangerous and for internal use only
3417 void LyXText::UnFreezeUndo()
3421 // this is dangerous and for internal use only
3422 undo_frozen = false;
3426 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3427 LyXParagraph const * before,
3428 LyXParagraph const * behind) const
3433 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3434 buf->redostack.clear();
3438 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3439 LyXParagraph const * before, LyXParagraph const * behind)
3443 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3447 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3448 LyXParagraph const * before,
3449 LyXParagraph const * behind) const
3454 int before_number = -1;
3455 int behind_number = -1;
3457 before_number = before->id();
3459 behind_number = behind->id();
3460 // Undo::EDIT and Undo::FINISH are
3461 // always finished. (no overlapping there)
3462 // overlapping only with insert and delete inside one paragraph:
3463 // Nobody wants all removed character
3464 // appear one by one when undoing.
3465 // EDIT is special since only layout information, not the
3466 // contents of a paragaph are stored.
3467 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3468 // check wether storing is needed
3469 if (!buf->undostack.empty() &&
3470 buf->undostack.top()->kind == kind &&
3471 buf->undostack.top()->number_of_before_par == before_number &&
3472 buf->undostack.top()->number_of_behind_par == behind_number ){
3477 // create a new Undo
3478 LyXParagraph * undopar;
3479 LyXParagraph * tmppar;
3480 LyXParagraph * tmppar2;
3482 LyXParagraph * start = 0;
3483 LyXParagraph * end = 0;
3486 start = before->next;
3488 start = FirstParagraph();
3490 end = behind->previous;
3492 end = FirstParagraph();
3498 && start != end->next
3499 && (before != behind || (!before && !behind))) {
3501 tmppar2 = tmppar->Clone();
3502 tmppar2->id(tmppar->id());
3504 // a memory optimization: Just store the layout information
3506 if (kind == Undo::EDIT){
3507 //tmppar2->text.clear();
3508 tmppar2->clearContents();
3513 while (tmppar != end && tmppar->next) {
3514 tmppar = tmppar->next;
3515 tmppar2->next = tmppar->Clone();
3516 tmppar2->next->id(tmppar->id());
3517 // a memory optimization: Just store the layout
3518 // information when only edit
3519 if (kind == Undo::EDIT){
3520 //tmppar2->next->text.clear();
3521 tmppar2->clearContents();
3523 tmppar2->next->previous = tmppar2;
3524 tmppar2 = tmppar2->next;
3528 undopar = 0; // nothing to replace (undo of delete maybe)
3530 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3531 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3533 Undo * undo = new Undo(kind,
3534 before_number, behind_number,
3535 cursor_par, cursor_pos,
3538 undo_finished = false;
3543 void LyXText::SetCursorParUndo(Buffer * buf)
3547 SetUndo(buf, Undo::FINISH,
3548 cursor.par()->ParFromPos(cursor.pos())->previous,
3549 cursor.par()->ParFromPos(cursor.pos())->next);
3554 void LyXText::RemoveTableRow(LyXCursor & cur) const
3560 // move to the previous row
3561 int cell_act = NumberOfCell(cur.par(), cur.pos());
3564 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3565 cur.pos(cur.pos() - 1);
3567 !cur.par()->table->IsFirstCell(cell_act)) {
3568 cur.pos(cur.pos() - 1);
3569 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3570 cur.pos(cur.pos() - 1);
3574 // now we have to pay attention if the actual table is the
3575 // main row of TableContRows and if yes to delete all of them
3580 // delete up to the next row
3581 while (cur.pos() < cur.par()->Last() &&
3583 || !cur.par()->table->IsFirstCell(cell_act))) {
3584 while (cur.pos() < cur.par()->Last() &&
3585 !cur.par()->IsNewline(cur.pos()))
3586 cur.par()->Erase(cur.pos());
3589 if (cur.pos() < cur.par()->Last())
3590 cur.par()->Erase(cur.pos());
3592 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3593 cur.pos(cur.pos() - 1);
3594 cur.par()->Erase(cur.pos()); // no newline at very end!
3596 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3597 !cur.par()->table->IsContRow(cell_org) &&
3598 cur.par()->table->IsContRow(cell));
3599 cur.par()->table->DeleteRow(cell_org);
3606 bool LyXText::IsEmptyTableCell() const
3608 LyXParagraph::size_type pos = cursor.pos() - 1;
3609 while (pos >= 0 && pos < cursor.par()->Last()
3610 && !cursor.par()->IsNewline(pos))
3612 return cursor.par()->IsNewline(pos + 1);
3617 void LyXText::toggleAppendix(BufferView * bview)
3619 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3620 bool start = !par->start_of_appendix;
3622 // ensure that we have only one start_of_appendix in this document
3623 LyXParagraph * tmp = FirstParagraph();
3624 for (; tmp; tmp = tmp->next)
3625 tmp->start_of_appendix = 0;
3626 par->start_of_appendix = start;
3628 // we can set the refreshing parameters now
3629 status = LyXText::NEED_MORE_REFRESH;
3631 refresh_row = 0; // not needed for full update
3632 UpdateCounters(bview, 0);
3633 SetCursor(bview, cursor.par(), cursor.pos());
3636 LyXParagraph * LyXText::OwnerParagraph() const
3639 return inset_owner->par;
3641 return bv_owner->buffer()->paragraph;
3645 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3648 inset_owner->par = p;
3650 bv_owner->buffer()->paragraph = p;