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"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
52 LyXText::LyXText(BufferView * bv)
60 LyXText::LyXText(InsetText * inset)
77 status = LyXText::UNCHANGED;
78 // set cursor at the very top position
79 selection = true; /* these setting is necessary
80 because of the delete-empty-
81 paragraph mechanism in
84 LyXParagraph * par = OwnerParagraph();
85 current_font = GetFont(bv_owner->buffer(), par, 0);
87 InsertParagraph(bv_owner, par, lastrow);
90 SetCursor(bv_owner, firstrow->par(), 0);
92 current_font = LyXFont(LyXFont::ALL_SANE);
98 // no rebreak necessary
101 undo_finished = true;
104 // Default layouttype for copy environment type
108 // Dump all rowinformation:
109 Row * tmprow = firstrow;
110 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
112 lyxerr << tmprow->baseline() << '\t'
113 << tmprow->par << '\t'
114 << tmprow->pos() << '\t'
115 << tmprow->height << '\t'
116 << tmprow->ascent_of_text << '\t'
117 << tmprow->fill << '\n';
118 tmprow = tmprow->next();
125 void LyXText::init(BufferView * bview)
130 LyXParagraph * par = OwnerParagraph();
131 current_font = GetFont(bview->buffer(), par, 0);
133 InsertParagraph(bview, par, lastrow);
136 SetCursorIntern(bview, firstrow->par(), 0);
139 // Dump all rowinformation:
140 Row * tmprow = firstrow;
141 lyxerr << "Width = " << width << endl;
142 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
144 lyxerr << tmprow->baseline() << '\t'
145 << tmprow->par() << '\t'
146 << tmprow->pos() << '\t'
147 << tmprow->height() << '\t'
148 << tmprow->ascent_of_text() << '\t'
149 << tmprow->fill() << '\n';
150 tmprow = tmprow->next();
158 // Delete all rows, this does not touch the paragraphs!
159 Row * tmprow = firstrow;
161 tmprow = firstrow->next();
168 // Gets the fully instantiated font at a given position in a paragraph
169 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
170 // The difference is that this one is used for displaying, and thus we
171 // are allowed to make cosmetic improvements. For instance make footnotes
173 // If position is -1, we get the layout font of the paragraph.
174 // If position is -2, we get the font of the manual label of the paragraph.
175 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
176 LyXParagraph::size_type pos) const
178 LyXLayout const & layout =
179 textclasslist.Style(buf->params.textclass, par->GetLayout());
181 char par_depth = par->GetDepth();
182 // We specialize the 95% common case:
185 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
190 if (layout.labeltype == LABEL_MANUAL
191 && pos < BeginningOfMainBody(buf, par)) {
193 return par->GetFontSettings(buf->params, pos).
194 realize(layout.reslabelfont);
196 return par->GetFontSettings(buf->params, pos).
197 realize(layout.resfont);
200 // process layoutfont for pos == -1 and labelfont for pos < -1
202 return layout.resfont;
204 return layout.reslabelfont;
208 // The uncommon case need not be optimized as much
210 LyXFont layoutfont, tmpfont;
214 if (pos < BeginningOfMainBody(buf, par)) {
216 layoutfont = layout.labelfont;
219 layoutfont = layout.font;
221 tmpfont = par->GetFontSettings(buf->params, pos);
222 tmpfont.realize(layoutfont);
225 // process layoutfont for pos == -1 and labelfont for pos < -1
227 tmpfont = layout.font;
229 tmpfont = layout.labelfont;
232 // Resolve against environment font information
233 while (par && par_depth && !tmpfont.resolved()) {
234 par = par->DepthHook(par_depth - 1);
236 tmpfont.realize(textclasslist.
237 Style(buf->params.textclass,
238 par->GetLayout()).font);
239 par_depth = par->GetDepth();
243 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
246 // Cosmetic improvement: If this is an open footnote, make the font
248 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
249 && par->footnotekind == LyXParagraph::FOOTNOTE) {
257 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
258 LyXParagraph::size_type pos,
262 // Let the insets convert their font
263 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
264 if (par->GetInset(pos))
265 font = par->GetInset(pos)->ConvertFont(font);
268 LyXLayout const & layout =
269 textclasslist.Style(buf->params.textclass,
272 // Get concrete layout font to reduce against
275 if (pos < BeginningOfMainBody(buf, par))
276 layoutfont = layout.labelfont;
278 layoutfont = layout.font;
280 // Realize against environment font information
281 if (par->GetDepth()){
282 LyXParagraph * tp = par;
283 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
284 tp = tp->DepthHook(tp->GetDepth()-1);
286 layoutfont.realize(textclasslist.
287 Style(buf->params.textclass,
288 tp->GetLayout()).font);
292 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
295 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
296 && par->footnotekind == LyXParagraph::FOOTNOTE) {
297 layoutfont.decSize();
300 // Now, reduce font against full layout font
301 font.reduce(layoutfont);
303 par->SetFont(pos, font);
307 /* inserts a new row behind the specified row, increments
308 * the touched counters */
309 void LyXText::InsertRow(Row * row, LyXParagraph * par,
310 LyXParagraph::size_type pos) const
312 Row * tmprow = new Row;
315 tmprow->next(firstrow);
318 tmprow->previous(row);
319 tmprow->next(row->next());
324 tmprow->next()->previous(tmprow);
326 if (tmprow->previous())
327 tmprow->previous()->next(tmprow);
335 ++number_of_rows; // one more row
339 // removes the row and reset the touched counters
340 void LyXText::RemoveRow(Row * row) const
342 /* this must not happen before the currentrow for clear reasons.
343 so the trick is just to set the current row onto the previous
346 GetRow(row->par(), row->pos(), unused_y);
349 row->next()->previous(row->previous());
350 if (!row->previous()) {
351 firstrow = row->next();
353 row->previous()->next(row->next());
356 lastrow = row->previous();
358 height -= row->height(); // the text becomes smaller
361 --number_of_rows; // one row less
365 // remove all following rows of the paragraph of the specified row.
366 void LyXText::RemoveParagraph(Row * row) const
368 LyXParagraph * tmppar = row->par();
372 while (row && row->par() == tmppar) {
373 tmprow = row->next();
380 // insert the specified paragraph behind the specified row
381 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
384 InsertRow(row, par, 0); /* insert a new row, starting
387 SetCounter(bview->buffer(), par); // set the counters
389 // and now append the whole paragraph behind the new row
392 AppendParagraph(bview, firstrow);
394 row->next()->height(0);
395 AppendParagraph(bview, row->next());
401 void LyXText::ToggleFootnote(BufferView * bview)
403 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
405 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
407 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
409 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
410 CloseFootnote(bview);
417 void LyXText::OpenStuff(BufferView * bview)
419 if (cursor.pos() == 0 && cursor.par()->bibkey){
420 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
421 } else if (cursor.pos() < cursor.par()->Last()
422 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
423 && cursor.par()->GetInset(cursor.pos())->Editable()) {
424 bview->owner()->getMiniBuffer()
425 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
426 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
427 SetCursorParUndo(bview->buffer());
428 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
432 ToggleFootnote(bview);
440 void LyXText::CloseFootnote(BufferView * bview)
442 LyXParagraph * tmppar;
443 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
445 // if the cursor is not in an open footnote, or
446 // there is no open footnote in this paragraph, just return.
447 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
450 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
451 bview->owner()->getMiniBuffer()
452 ->Set(_("Nothing to do"));
456 // ok, move the cursor right before the footnote
457 // just a little faster than using CursorRight()
459 cursor.par()->ParFromPos(cursor.pos()) != par;) {
460 cursor.pos(cursor.pos() + 1);
463 // now the cursor is at the beginning of the physical par
464 SetCursor(bview, cursor.par(),
466 cursor.par()->ParFromPos(cursor.pos())->size());
468 /* we are in a footnote, so let us move at the beginning */
469 /* this is just faster than using just CursorLeft() */
471 tmppar = cursor.par();
472 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
473 // just a little bit faster than movin the cursor
474 tmppar = tmppar->Previous();
476 SetCursor(bview, tmppar, tmppar->Last());
479 // the cursor must be exactly before the footnote
480 par = cursor.par()->ParFromPos(cursor.pos());
482 status = LyXText::NEED_MORE_REFRESH;
483 refresh_row = cursor.row();
484 refresh_y = cursor.y() - cursor.row()->baseline();
486 tmppar = cursor.par();
487 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
488 Row * row = cursor.row();
490 tmppar->CloseFootnote(cursor.pos());
492 while (tmppar != endpar) {
493 RemoveRow(row->next());
495 tmppar = row->next()->par();
500 AppendParagraph(bview, cursor.row());
502 SetCursor(bview, cursor.par(), cursor.pos());
506 if (cursor.row()->next())
507 SetHeightOfRow(bview, cursor.row()->next());
512 /* used in setlayout */
513 // Asger is not sure we want to do this...
514 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
518 LyXLayout const & layout =
519 textclasslist.Style(buf->params.textclass, par->GetLayout());
521 LyXFont layoutfont, tmpfont;
522 for (LyXParagraph::size_type pos = 0;
523 pos < par->Last(); ++pos) {
524 if (pos < BeginningOfMainBody(buf, par))
525 layoutfont = layout.labelfont;
527 layoutfont = layout.font;
529 tmpfont = par->GetFontSettings(buf->params, pos);
530 tmpfont.reduce(layoutfont);
531 par->SetFont(pos, tmpfont);
536 LyXParagraph * LyXText::SetLayout(BufferView * bview,
537 LyXCursor & cur, LyXCursor & sstart_cur,
538 LyXCursor & send_cur,
539 LyXTextClass::size_type layout)
542 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
544 LyXParagraph * endpar = send_cur.par()->Next();
546 LyXParagraph * undoendpar = endpar;
548 if (endpar && endpar->GetDepth()) {
549 while (endpar && endpar->GetDepth()) {
551 endpar = endpar->LastPhysicalPar()->Next();
553 endpar = endpar->Next();
558 endpar = endpar->Next(); // because of parindents etc.
561 SetUndo(bview->buffer(), Undo::EDIT,
562 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
565 /* ok we have a selection. This is always between sstart_cur
566 * and sel_end cursor */
569 LyXLayout const & lyxlayout =
570 textclasslist.Style(bview->buffer()->params.textclass, layout);
572 while (cur.par() != send_cur.par()) {
574 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
576 cur.par()->SetLayout(bview->buffer()->params, layout);
577 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
579 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
581 LyXParagraph * fppar = cur.par();
583 fppar->added_space_top = lyxlayout.fill_top ?
584 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
585 fppar->added_space_bottom = lyxlayout.fill_bottom ?
586 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
587 if (lyxlayout.margintype == MARGIN_MANUAL)
588 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
589 if (lyxlayout.labeltype != LABEL_BIBLIO
591 delete fppar->bibkey;
597 cur.par(cur.par()->Next());
600 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
602 cur.par()->SetLayout(bview->buffer()->params, layout);
603 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
605 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
607 LyXParagraph * fppar = cur.par();
609 fppar->added_space_top = lyxlayout.fill_top ?
610 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
611 fppar->added_space_bottom = lyxlayout.fill_bottom ?
612 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
613 if (lyxlayout.margintype == MARGIN_MANUAL)
614 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
615 if (lyxlayout.labeltype != LABEL_BIBLIO
617 delete fppar->bibkey;
626 // set layout over selection and make a total rebreak of those paragraphs
627 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
629 LyXCursor tmpcursor = cursor; /* store the current cursor */
631 // #ifdef USE_OLD_SET_LAYOUT
632 // // if there is no selection just set the layout
633 // // of the current paragraph */
635 // sel_start_cursor = cursor; // dummy selection
636 // sel_end_cursor = cursor;
639 // LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
640 // LyXParagraph * undoendpar = endpar;
642 // if (endpar && endpar->GetDepth()) {
643 // while (endpar && endpar->GetDepth()) {
644 // endpar = endpar->LastPhysicalPar()->Next();
645 // undoendpar = endpar;
648 // else if (endpar) {
649 // endpar = endpar->Next(); // because of parindents etc.
652 // SetUndo(Undo::EDIT,
653 // sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
656 // /* ok we have a selection. This is always between sel_start_cursor
657 // * and sel_end cursor */
658 // cursor = sel_start_cursor;
660 // LyXLayout const & lyxlayout =
661 // textclasslist.Style(bview->buffer()->params.textclass, layout);
663 // while (cursor.par() != sel_end_cursor.par()) {
664 // if (cursor.par()->footnoteflag ==
665 // sel_start_cursor.par()->footnoteflag) {
666 // cursor.par()->SetLayout(layout);
667 // MakeFontEntriesLayoutSpecific(cursor.par());
668 // LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
669 // fppar->added_space_top = lyxlayout.fill_top ?
670 // VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
671 // fppar->added_space_bottom = lyxlayout.fill_bottom ?
672 // VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
673 // if (lyxlayout.margintype == MARGIN_MANUAL)
674 // cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
675 // if (lyxlayout.labeltype != LABEL_BIBLIO
676 // && fppar->bibkey) {
677 // delete fppar->bibkey;
678 // fppar->bibkey = 0;
681 // cursor.par() = cursor.par()->Next();
683 // if (cursor.par()->footnoteflag ==
684 // sel_start_cursor.par()->footnoteflag) {
685 // cursor.par()->SetLayout(layout);
686 // MakeFontEntriesLayoutSpecific(cursor.par());
687 // #ifndef NEW_INSETS
688 // LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
690 // LyXParagraph* fppar = cursor.par();
692 // fppar->added_space_top = lyxlayout.fill_top ?
693 // VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
694 // fppar->added_space_bottom = lyxlayout.fill_bottom ?
695 // VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
696 // if (lyxlayout.margintype == MARGIN_MANUAL)
697 // cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
698 // if (lyxlayout.labeltype != LABEL_BIBLIO
699 // && fppar->bibkey) {
700 // delete fppar->bibkey;
701 // fppar->bibkey = 0;
705 // if there is no selection just set the layout
706 // of the current paragraph */
708 sel_start_cursor = cursor; // dummy selection
709 sel_end_cursor = cursor;
712 endpar = SetLayout(bview, cursor, sel_start_cursor,
713 sel_end_cursor, layout);
715 RedoParagraphs(bview, sel_start_cursor, endpar);
717 // we have to reset the selection, because the
718 // geometry could have changed
719 SetCursor(bview, sel_start_cursor.par(),
720 sel_start_cursor.pos(), false);
722 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
724 UpdateCounters(bview, cursor.row());
727 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
731 // increment depth over selection and
732 // make a total rebreak of those paragraphs
733 void LyXText::IncDepth(BufferView * bview)
735 // If there is no selection, just use the current paragraph
737 sel_start_cursor = cursor; // dummy selection
738 sel_end_cursor = cursor;
741 // We end at the next paragraph with depth 0
742 LyXParagraph * endpar =
744 sel_end_cursor.par()->LastPhysicalPar()->Next();
746 sel_end_cursor.par()->Next();
748 LyXParagraph * undoendpar = endpar;
750 if (endpar && endpar->GetDepth()) {
751 while (endpar && endpar->GetDepth()) {
753 endpar = endpar->LastPhysicalPar()->Next();
755 endpar = endpar->Next();
761 endpar = endpar->Next(); // because of parindents etc.
764 SetUndo(bview->buffer(), Undo::EDIT,
766 .par()->ParFromPos(sel_start_cursor.pos())->previous,
769 LyXCursor tmpcursor = cursor; // store the current cursor
771 // ok we have a selection. This is always between sel_start_cursor
772 // and sel_end cursor
773 cursor = sel_start_cursor;
775 bool anything_changed = false;
778 // NOTE: you can't change the depth of a bibliography entry
781 cursor.par()->footnoteflag ==
782 sel_start_cursor.par()->footnoteflag &&
784 textclasslist.Style(bview->buffer()->params.textclass,
785 cursor.par()->GetLayout()
786 ).labeltype != LABEL_BIBLIO) {
787 LyXParagraph * prev =
789 cursor.par()->FirstPhysicalPar()->Previous();
791 cursor.par()->Previous();
794 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
795 || (prev->GetDepth() == cursor.par()->GetDepth()
796 && textclasslist.Style(bview->buffer()->params.textclass,
797 prev->GetLayout()).isEnvironment()))) {
799 cursor.par()->FirstPhysicalPar()->depth++;
801 cursor.par()->depth++;
803 anything_changed = true;
806 if (cursor.par() == sel_end_cursor.par())
808 cursor.par(cursor.par()->Next());
811 // if nothing changed set all depth to 0
812 if (!anything_changed) {
813 cursor = sel_start_cursor;
814 while (cursor.par() != sel_end_cursor.par()) {
816 cursor.par()->FirstPhysicalPar()->depth = 0;
818 cursor.par()->depth = 0;
820 cursor.par(cursor.par()->Next());
823 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
824 cursor.par()->FirstPhysicalPar()->depth = 0;
826 cursor.par()->depth = 0;
830 RedoParagraphs(bview, sel_start_cursor, endpar);
832 // we have to reset the selection, because the
833 // geometry could have changed
834 SetCursor(bview, sel_start_cursor.par(),
835 sel_start_cursor.pos());
837 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
838 UpdateCounters(bview, cursor.row());
841 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
845 // decrement depth over selection and
846 // make a total rebreak of those paragraphs
847 void LyXText::DecDepth(BufferView * bview)
849 // if there is no selection just set the layout
850 // of the current paragraph
852 sel_start_cursor = cursor; // dummy selection
853 sel_end_cursor = cursor;
856 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
858 LyXParagraph * endpar = sel_end_cursor.par()->Next();
860 LyXParagraph * undoendpar = endpar;
862 if (endpar && endpar->GetDepth()) {
863 while (endpar && endpar->GetDepth()) {
865 endpar = endpar->LastPhysicalPar()->Next();
867 endpar = endpar->Next();
873 endpar = endpar->Next(); // because of parindents etc.
876 SetUndo(bview->buffer(), Undo::EDIT,
878 .par()->ParFromPos(sel_start_cursor.pos())->previous,
881 LyXCursor tmpcursor = cursor; // store the current cursor
883 // ok we have a selection. This is always between sel_start_cursor
884 // and sel_end cursor
885 cursor = sel_start_cursor;
889 if (cursor.par()->footnoteflag ==
890 sel_start_cursor.par()->footnoteflag) {
891 if (cursor.par()->FirstPhysicalPar()->depth)
892 cursor.par()->FirstPhysicalPar()->depth--;
895 if (cursor.par()->depth)
896 cursor.par()->depth--;
898 if (cursor.par() == sel_end_cursor.par())
900 cursor.par(cursor.par()->Next());
903 RedoParagraphs(bview, sel_start_cursor, endpar);
905 // we have to reset the selection, because the
906 // geometry could have changed
907 SetCursor(bview, sel_start_cursor.par(),
908 sel_start_cursor.pos());
910 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
911 UpdateCounters(bview, cursor.row());
914 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
918 // set font over selection and make a total rebreak of those paragraphs
919 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
921 // if there is no selection just set the current_font
923 // Determine basis font
925 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
927 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
929 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
930 // Update current font
931 real_current_font.update(font,
932 bview->buffer()->params.language_info,
935 // Reduce to implicit settings
936 current_font = real_current_font;
937 current_font.reduce(layoutfont);
938 // And resolve it completely
939 real_current_font.realize(layoutfont);
943 LyXCursor tmpcursor = cursor; // store the current cursor
945 // ok we have a selection. This is always between sel_start_cursor
946 // and sel_end cursor
948 SetUndo(bview->buffer(), Undo::EDIT,
949 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
950 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
951 cursor = sel_start_cursor;
952 while (cursor.par() != sel_end_cursor.par() ||
955 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
957 cursor.pos() < sel_end_cursor.pos()))
959 if (cursor.pos() < cursor.par()->Last()
961 && cursor.par()->footnoteflag
962 == sel_start_cursor.par()->footnoteflag
965 // an open footnote should behave
967 LyXFont newfont = GetFont(bview->buffer(),
968 cursor.par(), cursor.pos());
970 bview->buffer()->params.language_info,
972 SetCharFont(bview->buffer(),
973 cursor.par(), cursor.pos(), newfont);
974 cursor.pos(cursor.pos() + 1);
977 cursor.par(cursor.par()->Next());
981 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
983 // we have to reset the selection, because the
984 // geometry could have changed
985 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
987 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
990 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
991 tmpcursor.boundary());
995 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
997 Row * tmprow = cur.row();
998 long y = cur.y() - tmprow->baseline();
1000 SetHeightOfRow(bview, tmprow);
1002 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1004 LyXParagraph * first_phys_par = tmprow->par();
1006 // find the first row of the paragraph
1007 if (first_phys_par != tmprow->par())
1008 while (tmprow->previous()
1009 && tmprow->previous()->par() != first_phys_par) {
1010 tmprow = tmprow->previous();
1011 y -= tmprow->height();
1012 SetHeightOfRow(bview, tmprow);
1014 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1015 tmprow = tmprow->previous();
1016 y -= tmprow->height();
1017 SetHeightOfRow(bview, tmprow);
1020 // we can set the refreshing parameters now
1021 status = LyXText::NEED_MORE_REFRESH;
1023 refresh_row = tmprow;
1024 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
1028 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
1030 Row * tmprow = cur.row();
1032 long y = cur.y() - tmprow->baseline();
1033 SetHeightOfRow(bview, tmprow);
1035 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1037 LyXParagraph * first_phys_par = tmprow->par();
1039 // find the first row of the paragraph
1040 if (first_phys_par != tmprow->par())
1041 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
1042 tmprow = tmprow->previous();
1043 y -= tmprow->height();
1045 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1046 tmprow = tmprow->previous();
1047 y -= tmprow->height();
1050 // we can set the refreshing parameters now
1051 if (status == LyXText::UNCHANGED || y < refresh_y) {
1053 refresh_row = tmprow;
1055 status = LyXText::NEED_MORE_REFRESH;
1056 SetCursor(bview, cur.par(), cur.pos());
1060 /* deletes and inserts again all paragaphs between the cursor
1061 * and the specified par
1062 * This function is needed after SetLayout and SetFont etc. */
1063 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1064 LyXParagraph const * endpar) const
1067 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1069 Row * tmprow = cur.row();
1071 long y = cur.y() - tmprow->baseline();
1073 if (!tmprow->previous()){
1074 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1077 first_phys_par = tmprow->par()->FirstPhysicalPar();
1079 first_phys_par = tmprow->par();
1081 // find the first row of the paragraph
1082 if (first_phys_par != tmprow->par())
1083 while (tmprow->previous() &&
1084 (tmprow->previous()->par() != first_phys_par)) {
1085 tmprow = tmprow->previous();
1086 y -= tmprow->height();
1088 while (tmprow->previous()
1089 && tmprow->previous()->par() == first_phys_par) {
1090 tmprow = tmprow->previous();
1091 y -= tmprow->height();
1095 // we can set the refreshing parameters now
1096 status = LyXText::NEED_MORE_REFRESH;
1098 refresh_row = tmprow->previous(); /* the real refresh row will
1099 be deleted, so I store
1100 the previous here */
1103 tmppar = tmprow->next()->par();
1106 while (tmppar != endpar) {
1107 RemoveRow(tmprow->next());
1109 tmppar = tmprow->next()->par();
1114 // remove the first one
1115 tmprow2 = tmprow; /* this is because tmprow->previous()
1117 tmprow = tmprow->previous();
1120 tmppar = first_phys_par;
1124 InsertParagraph(bview, tmppar, tmprow);
1127 while (tmprow->next() && tmprow->next()->par() == tmppar)
1128 tmprow = tmprow->next();
1129 tmppar = tmppar->Next();
1131 } while (tmppar != endpar);
1133 // this is because of layout changes
1135 refresh_y -= refresh_row->height();
1136 SetHeightOfRow(bview, refresh_row);
1138 refresh_row = firstrow;
1140 SetHeightOfRow(bview, refresh_row);
1143 if (tmprow && tmprow->next())
1144 SetHeightOfRow(bview, tmprow->next());
1148 bool LyXText::FullRebreak(BufferView * bview)
1154 if (need_break_row) {
1155 BreakAgain(bview, need_break_row);
1163 /* important for the screen */
1166 /* the cursor set functions have a special mechanism. When they
1167 * realize, that you left an empty paragraph, they will delete it.
1168 * They also delete the corresponding row */
1170 // need the selection cursor:
1171 void LyXText::SetSelection()
1174 last_sel_cursor = sel_cursor;
1175 sel_start_cursor = sel_cursor;
1176 sel_end_cursor = sel_cursor;
1181 // first the toggling area
1182 if (cursor.y() < last_sel_cursor.y()
1183 || (cursor.y() == last_sel_cursor.y()
1184 && cursor.x() < last_sel_cursor.x())) {
1185 toggle_end_cursor = last_sel_cursor;
1186 toggle_cursor = cursor;
1188 toggle_end_cursor = cursor;
1189 toggle_cursor = last_sel_cursor;
1192 last_sel_cursor = cursor;
1194 // and now the whole selection
1196 if (sel_cursor.par() == cursor.par())
1197 if (sel_cursor.pos() < cursor.pos()) {
1198 sel_end_cursor = cursor;
1199 sel_start_cursor = sel_cursor;
1201 sel_end_cursor = sel_cursor;
1202 sel_start_cursor = cursor;
1204 else if (sel_cursor.y() < cursor.y() ||
1205 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1206 sel_end_cursor = cursor;
1207 sel_start_cursor = sel_cursor;
1210 sel_end_cursor = sel_cursor;
1211 sel_start_cursor = cursor;
1214 // a selection with no contents is not a selection
1215 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1216 sel_start_cursor.pos() == sel_end_cursor.pos())
1221 string LyXText::selectionAsString(Buffer const * buffer) const
1223 if (!selection) return string();
1226 // Special handling if the whole selection is within one paragraph
1227 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1228 result += sel_start_cursor.par()->String(buffer,
1229 sel_start_cursor.pos(),
1230 sel_end_cursor.pos());
1234 // The selection spans more than one paragraph
1236 // First paragraph in selection
1237 result += sel_start_cursor.par()->String(buffer,
1238 sel_start_cursor.pos(),
1239 sel_start_cursor.par()->Last())
1242 // The paragraphs in between (if any)
1243 LyXCursor tmpcur(sel_start_cursor);
1244 tmpcur.par(tmpcur.par()->Next());
1245 while (tmpcur.par() != sel_end_cursor.par()) {
1246 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1247 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1250 // Last paragraph in selection
1251 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1257 void LyXText::ClearSelection() const
1264 void LyXText::CursorHome(BufferView * bview) const
1266 SetCursor(bview, cursor.par(), cursor.row()->pos());
1270 void LyXText::CursorEnd(BufferView * bview) const
1272 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1273 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1275 if (cursor.par()->Last() &&
1276 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1277 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1278 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1280 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1283 if (cursor.par()->table) {
1284 int cell = NumberOfCell(cursor.par(), cursor.pos());
1285 if (cursor.par()->table->RowHasContRow(cell) &&
1286 cursor.par()->table->CellHasContRow(cell)<0) {
1287 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1288 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1290 if (cursor.par()->Last() &&
1291 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1292 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1293 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1295 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1303 void LyXText::CursorTop(BufferView * bview) const
1305 while (cursor.par()->Previous())
1306 cursor.par(cursor.par()->Previous());
1307 SetCursor(bview, cursor.par(), 0);
1311 void LyXText::CursorBottom(BufferView * bview) const
1313 while (cursor.par()->Next())
1314 cursor.par(cursor.par()->Next());
1315 SetCursor(bview, cursor.par(), cursor.par()->Last());
1319 /* returns a pointer to the row near the specified y-coordinate
1320 * (relative to the whole text). y is set to the real beginning
1322 Row * LyXText::GetRowNearY(long & y) const
1324 Row * tmprow = firstrow;
1327 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1328 tmpy += tmprow->height();
1329 tmprow = tmprow->next();
1332 y = tmpy; // return the real y
1337 void LyXText::ToggleFree(BufferView * bview,
1338 LyXFont const & font, bool toggleall)
1340 // If the mask is completely neutral, tell user
1341 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1342 // Could only happen with user style
1343 bview->owner()->getMiniBuffer()
1344 ->Set(_("No font change defined. Use Character under"
1345 " the Layout menu to define font change."));
1349 // Try implicit word selection
1350 // If there is a change in the language the implicit word selection
1352 LyXCursor resetCursor = cursor;
1353 bool implicitSelection = (font.language() == ignore_language)
1354 ? SelectWordWhenUnderCursor(bview) : false;
1357 SetFont(bview, font, toggleall);
1359 /* Implicit selections are cleared afterwards and cursor is set to the
1360 original position. */
1361 if (implicitSelection) {
1363 cursor = resetCursor;
1364 SetCursor(bview, cursor.par(), cursor.pos());
1365 sel_cursor = cursor;
1370 LyXParagraph::size_type
1371 LyXText::BeginningOfMainBody(Buffer const * buf,
1372 LyXParagraph const * par) const
1374 if (textclasslist.Style(buf->params.textclass,
1375 par->GetLayout()).labeltype != LABEL_MANUAL)
1378 return par->BeginningOfMainBody();
1383 /* if there is a selection, reset every environment you can find
1384 * in the selection, otherwise just the environment you are in */
1385 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1387 LyXParagraph * tmppar, * firsttmppar;
1391 /* is is only allowed, if the cursor is IN an open footnote.
1392 * Otherwise it is too dangerous */
1393 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1396 SetUndo(bview->buffer(), Undo::FINISH,
1397 cursor.par()->PreviousBeforeFootnote()->previous,
1398 cursor.par()->NextAfterFootnote()->next);
1400 /* ok, move to the beginning of the footnote. */
1401 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1402 cursor.par(cursor.par()->Previous());
1404 SetCursor(bview, cursor.par(), cursor.par()->Last());
1405 /* this is just faster than using CursorLeft(); */
1407 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1408 tmppar = firsttmppar;
1409 /* tmppar is now the paragraph right before the footnote */
1411 bool first_footnote_par_is_not_empty = tmppar->next->size();
1414 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1415 tmppar = tmppar->next; /* I use next instead of Next(),
1416 * because there cannot be any
1417 * footnotes in a footnote
1419 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1421 /* remember the captions and empty paragraphs */
1422 if ((textclasslist.Style(bview->buffer()->params.textclass,
1423 tmppar->GetLayout())
1424 .labeltype == LABEL_SENSITIVE)
1426 tmppar->SetLayout(bview->buffer()->params, 0);
1429 // now we will paste the ex-footnote, if the layouts allow it
1430 // first restore the layout of the paragraph right behind
1433 tmppar->next->MakeSameLayout(cursor.par());
1436 if ((!tmppar->GetLayout() && !tmppar->table)
1438 && (!tmppar->Next()->Last()
1439 || tmppar->Next()->HasSameLayout(tmppar)))) {
1440 if (tmppar->Next()->Last()
1441 && tmppar->Next()->IsLineSeparator(0))
1442 tmppar->Next()->Erase(0);
1443 tmppar->PasteParagraph(bview->buffer()->params);
1446 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1447 * by the pasting of the beginning */
1449 /* then the beginning */
1450 /* if there is no space between the text and the footnote, so we insert
1452 * (only if the previous par and the footnotepar are not empty!) */
1453 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1454 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1455 if (firsttmppar->size()
1456 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1457 && first_footnote_par_is_not_empty) {
1458 firsttmppar->next->InsertChar(0, ' ');
1460 firsttmppar->PasteParagraph(bview->buffer()->params);
1463 /* now redo the paragaphs */
1464 RedoParagraphs(bview, cursor, tmppar);
1466 SetCursor(bview, cursor.par(), cursor.pos());
1468 /* sometimes it can happen, that there is a counter change */
1469 Row * row = cursor.row();
1470 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1472 UpdateCounters(bview, row);
1480 /* the DTP switches for paragraphs. LyX will store them in the
1481 * first physicla paragraph. When a paragraph is broken, the top settings
1482 * rest, the bottom settings are given to the new one. So I can make shure,
1483 * they do not duplicate themself and you cannnot make dirty things with
1486 void LyXText::SetParagraph(BufferView * bview,
1487 bool line_top, bool line_bottom,
1488 bool pagebreak_top, bool pagebreak_bottom,
1489 VSpace const & space_top,
1490 VSpace const & space_bottom,
1492 string labelwidthstring,
1495 LyXCursor tmpcursor = cursor;
1497 sel_start_cursor = cursor;
1498 sel_end_cursor = cursor;
1501 // make sure that the depth behind the selection are restored, too
1503 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1505 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1507 LyXParagraph * undoendpar = endpar;
1509 if (endpar && endpar->GetDepth()) {
1510 while (endpar && endpar->GetDepth()) {
1512 endpar = endpar->LastPhysicalPar()->Next();
1514 endpar = endpar->Next();
1516 undoendpar = endpar;
1520 endpar = endpar->Next(); // because of parindents etc.
1523 SetUndo(bview->buffer(), Undo::EDIT,
1525 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1529 LyXParagraph * tmppar = sel_end_cursor.par();
1531 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1532 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1534 while (tmppar != sel_start_cursor.par()->Previous()) {
1535 SetCursor(bview, tmppar, 0);
1537 status = LyXText::NEED_MORE_REFRESH;
1538 refresh_row = cursor.row();
1539 refresh_y = cursor.y() - cursor.row()->baseline();
1541 if (cursor.par()->footnoteflag ==
1542 sel_start_cursor.par()->footnoteflag) {
1544 cursor.par()->line_top = line_top;
1545 cursor.par()->line_bottom = line_bottom;
1546 cursor.par()->pagebreak_top = pagebreak_top;
1547 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1548 cursor.par()->added_space_top = space_top;
1549 cursor.par()->added_space_bottom = space_bottom;
1550 // does the layout allow the new alignment?
1551 if (align == LYX_ALIGN_LAYOUT)
1552 align = textclasslist
1553 .Style(bview->buffer()->params.textclass,
1554 cursor.par()->GetLayout()).align;
1555 if (align & textclasslist
1556 .Style(bview->buffer()->params.textclass,
1557 cursor.par()->GetLayout()).alignpossible) {
1558 if (align == textclasslist
1559 .Style(bview->buffer()->params.textclass,
1560 cursor.par()->GetLayout()).align)
1561 cursor.par()->align = LYX_ALIGN_LAYOUT;
1563 cursor.par()->align = align;
1565 cursor.par()->SetLabelWidthString(labelwidthstring);
1566 cursor.par()->noindent = noindent;
1570 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1572 tmppar = cursor.par()->Previous();
1576 RedoParagraphs(bview, sel_start_cursor, endpar);
1579 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1580 sel_cursor = cursor;
1581 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1583 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1587 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1589 char const * widthp,
1590 int alignment, bool hfill,
1591 bool start_minipage)
1593 LyXCursor tmpcursor = cursor;
1594 LyXParagraph * tmppar;
1596 sel_start_cursor = cursor;
1597 sel_end_cursor = cursor;
1600 // make sure that the depth behind the selection are restored, too
1602 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1604 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1606 LyXParagraph * undoendpar = endpar;
1608 if (endpar && endpar->GetDepth()) {
1609 while (endpar && endpar->GetDepth()) {
1611 endpar = endpar->LastPhysicalPar()->Next();
1613 endpar = endpar->Next();
1615 undoendpar = endpar;
1619 endpar = endpar->Next(); // because of parindents etc.
1622 SetUndo(bview->buffer(), Undo::EDIT,
1624 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1627 tmppar = sel_end_cursor.par();
1629 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1630 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1632 while(tmppar != sel_start_cursor.par()->Previous()) {
1633 SetCursor(bview, tmppar, 0);
1635 status = LyXText::NEED_MORE_REFRESH;
1636 refresh_row = cursor.row();
1637 refresh_y = cursor.y() - cursor.row()->baseline();
1639 if (cursor.par()->footnoteflag ==
1640 sel_start_cursor.par()->footnoteflag) {
1642 if (type == LyXParagraph::PEXTRA_NONE) {
1643 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1644 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1645 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1648 cursor.par()->SetPExtraType(bview->buffer()->params,
1649 type, width, widthp);
1650 cursor.par()->pextra_hfill = hfill;
1651 cursor.par()->pextra_start_minipage = start_minipage;
1652 cursor.par()->pextra_alignment = alignment;
1656 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1658 tmppar = cursor.par()->Previous();
1661 RedoParagraphs(bview, sel_start_cursor, endpar);
1663 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1664 sel_cursor = cursor;
1665 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1667 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1671 char loweralphaCounter(int n)
1673 if (n < 1 || n > 26)
1680 char alphaCounter(int n)
1682 if (n < 1 || n > 26)
1689 char hebrewCounter(int n)
1691 static const char hebrew[22] = {
1692 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1693 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1696 if (n < 1 || n > 22)
1704 char const * romanCounter(int n)
1706 static char const * roman[20] = {
1707 "i", "ii", "iii", "iv", "v",
1708 "vi", "vii", "viii", "ix", "x",
1709 "xi", "xii", "xiii", "xiv", "xv",
1710 "xvi", "xvii", "xviii", "xix", "xx"
1712 if (n < 1 || n > 20)
1719 // set the counter of a paragraph. This includes the labels
1720 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1723 // this is only relevant for the beginning of paragraph
1724 par = par->FirstPhysicalPar();
1726 LyXLayout const & layout =
1727 textclasslist.Style(buf->params.textclass,
1730 LyXTextClass const & textclass =
1731 textclasslist.TextClass(buf->params.textclass);
1733 /* copy the prev-counters to this one, unless this is the start of a
1734 footnote or of a bibliography or the very first paragraph */
1737 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1738 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1739 && par->footnotekind == LyXParagraph::FOOTNOTE)
1741 && !(textclasslist.Style(buf->params.textclass,
1742 par->Previous()->GetLayout()
1743 ).labeltype != LABEL_BIBLIO
1744 && layout.labeltype == LABEL_BIBLIO)) {
1745 for (int i = 0; i < 10; ++i) {
1746 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1749 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1751 par->appendix = par->Previous()->appendix;
1753 if (!par->appendix && par->start_of_appendix){
1754 par->appendix = true;
1755 for (int i = 0; i < 10; ++i) {
1756 par->setCounter(i, 0);
1760 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1761 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1763 par->enumdepth = par->Previous()->enumdepth;
1764 par->itemdepth = par->Previous()->itemdepth;
1767 for (int i = 0; i < 10; ++i) {
1768 par->setCounter(i, 0);
1770 par->appendix = par->start_of_appendix;
1776 // if this is an open marginnote and this is the first
1777 // entry in the marginnote and the enclosing
1778 // environment is an enum/item then correct for the
1779 // LaTeX behaviour (ARRae)
1780 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1781 && par->footnotekind == LyXParagraph::MARGIN
1783 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1784 && (par->PreviousBeforeFootnote()
1785 && textclasslist.Style(buf->params.textclass,
1786 par->PreviousBeforeFootnote()->GetLayout()
1787 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1788 // Any itemize or enumerate environment in a marginnote
1789 // that is embedded in an itemize or enumerate
1790 // paragraph is seen by LaTeX as being at a deeper
1791 // level within that enclosing itemization/enumeration
1792 // even if there is a "standard" layout at the start of
1798 /* Maybe we have to increment the enumeration depth.
1799 * BUT, enumeration in a footnote is considered in isolation from its
1800 * surrounding paragraph so don't increment if this is the
1801 * first line of the footnote
1802 * AND, bibliographies can't have their depth changed ie. they
1803 * are always of depth 0
1806 && par->Previous()->GetDepth() < par->GetDepth()
1807 && textclasslist.Style(buf->params.textclass,
1808 par->Previous()->GetLayout()
1809 ).labeltype == LABEL_COUNTER_ENUMI
1810 && par->enumdepth < 3
1812 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1813 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1814 && par->footnotekind == LyXParagraph::FOOTNOTE)
1816 && layout.labeltype != LABEL_BIBLIO) {
1820 /* Maybe we have to decrement the enumeration depth, see note above */
1822 && par->Previous()->GetDepth() > par->GetDepth()
1824 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1825 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1826 && par->footnotekind == LyXParagraph::FOOTNOTE)
1828 && layout.labeltype != LABEL_BIBLIO) {
1829 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1830 par->setCounter(6 + par->enumdepth,
1831 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1832 /* reset the counters.
1833 * A depth change is like a breaking layout
1835 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1836 par->setCounter(i, 0);
1839 if (!par->labelstring.empty()) {
1840 par->labelstring.erase();
1843 if (layout.margintype == MARGIN_MANUAL) {
1844 if (par->labelwidthstring.empty()) {
1845 par->SetLabelWidthString(layout.labelstring());
1848 par->SetLabelWidthString(string());
1851 /* is it a layout that has an automatic label ? */
1852 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1854 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1855 if (i >= 0 && i<= buf->params.secnumdepth) {
1856 par->incCounter(i); // increment the counter
1858 // Is there a label? Useful for Chapter layout
1859 if (!par->appendix){
1860 if (!layout.labelstring().empty())
1861 par->labelstring = layout.labelstring();
1863 par->labelstring.erase();
1865 if (!layout.labelstring_appendix().empty())
1866 par->labelstring = layout.labelstring_appendix();
1868 par->labelstring.erase();
1872 std::ostringstream s;
1876 if (!par->appendix) {
1877 switch (2 * LABEL_COUNTER_CHAPTER -
1878 textclass.maxcounter() + i) {
1879 case LABEL_COUNTER_CHAPTER:
1880 s << par->getCounter(i);
1882 case LABEL_COUNTER_SECTION:
1883 s << par->getCounter(i - 1) << '.'
1884 << par->getCounter(i);
1886 case LABEL_COUNTER_SUBSECTION:
1887 s << par->getCounter(i - 2) << '.'
1888 << par->getCounter(i - 1) << '.'
1889 << par->getCounter(i);
1891 case LABEL_COUNTER_SUBSUBSECTION:
1892 s << par->getCounter(i - 3) << '.'
1893 << par->getCounter(i - 2) << '.'
1894 << par->getCounter(i - 1) << '.'
1895 << par->getCounter(i);
1898 case LABEL_COUNTER_PARAGRAPH:
1899 s << par->getCounter(i - 4) << '.'
1900 << par->getCounter(i - 3) << '.'
1901 << par->getCounter(i - 2) << '.'
1902 << par->getCounter(i - 1) << '.'
1903 << par->getCounter(i);
1905 case LABEL_COUNTER_SUBPARAGRAPH:
1906 s << par->getCounter(i - 5) << '.'
1907 << par->getCounter(i - 4) << '.'
1908 << par->getCounter(i - 3) << '.'
1909 << par->getCounter(i - 2) << '.'
1910 << par->getCounter(i - 1) << '.'
1911 << par->getCounter(i);
1915 // Can this ever be reached? And in the
1916 // case it is, how can this be correct?
1918 s << par->getCounter(i) << '.';
1921 } else { // appendix
1922 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1923 case LABEL_COUNTER_CHAPTER:
1924 if (par->isRightToLeftPar(buf->params))
1925 s << hebrewCounter(par->getCounter(i));
1927 s << alphaCounter(par->getCounter(i));
1929 case LABEL_COUNTER_SECTION:
1930 if (par->isRightToLeftPar(buf->params))
1931 s << hebrewCounter(par->getCounter(i - 1));
1933 s << alphaCounter(par->getCounter(i - 1));
1936 << par->getCounter(i);
1939 case LABEL_COUNTER_SUBSECTION:
1940 if (par->isRightToLeftPar(buf->params))
1941 s << hebrewCounter(par->getCounter(i - 2));
1943 s << alphaCounter(par->getCounter(i - 2));
1946 << par->getCounter(i-1) << '.'
1947 << par->getCounter(i);
1950 case LABEL_COUNTER_SUBSUBSECTION:
1951 if (par->isRightToLeftPar(buf->params))
1952 s << hebrewCounter(par->getCounter(i-3));
1954 s << alphaCounter(par->getCounter(i-3));
1957 << par->getCounter(i-2) << '.'
1958 << par->getCounter(i-1) << '.'
1959 << par->getCounter(i);
1962 case LABEL_COUNTER_PARAGRAPH:
1963 if (par->isRightToLeftPar(buf->params))
1964 s << hebrewCounter(par->getCounter(i-4));
1966 s << alphaCounter(par->getCounter(i-4));
1969 << par->getCounter(i-3) << '.'
1970 << par->getCounter(i-2) << '.'
1971 << par->getCounter(i-1) << '.'
1972 << par->getCounter(i);
1975 case LABEL_COUNTER_SUBPARAGRAPH:
1976 if (par->isRightToLeftPar(buf->params))
1977 s << hebrewCounter(par->getCounter(i-5));
1979 s << alphaCounter(par->getCounter(i-5));
1982 << par->getCounter(i-4) << '.'
1983 << par->getCounter(i-3) << '.'
1984 << par->getCounter(i-2) << '.'
1985 << par->getCounter(i-1) << '.'
1986 << par->getCounter(i);
1990 // Can this ever be reached? And in the
1991 // case it is, how can this be correct?
1993 s << par->getCounter(i) << '.';
1999 par->labelstring += s.str().c_str();
2000 // We really want to remove the c_str as soon as
2004 char * tmps = s.str();
2005 par->labelstring += tmps;
2009 for (i++; i < 10; ++i) {
2010 // reset the following counters
2011 par->setCounter(i, 0);
2013 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2014 for (i++; i < 10; ++i) {
2015 // reset the following counters
2016 par->setCounter(i, 0);
2018 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2019 par->incCounter(i + par->enumdepth);
2020 int number = par->getCounter(i + par->enumdepth);
2023 std::ostringstream s;
2027 switch (par->enumdepth) {
2029 if (par->isRightToLeftPar(buf->params))
2031 << hebrewCounter(number)
2035 << loweralphaCounter(number)
2039 if (par->isRightToLeftPar(buf->params))
2040 s << '.' << romanCounter(number);
2042 s << romanCounter(number) << '.';
2045 if (par->isRightToLeftPar(buf->params))
2047 << alphaCounter(number);
2049 s << alphaCounter(number)
2053 if (par->isRightToLeftPar(buf->params))
2060 par->labelstring = s.str().c_str();
2061 // we really want to get rid of that c_str()
2064 char * tmps = s.str();
2065 par->labelstring = tmps;
2069 for (i += par->enumdepth + 1; i < 10; ++i)
2070 par->setCounter(i, 0); /* reset the following counters */
2073 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2074 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2076 int number = par->getCounter(i);
2078 par->bibkey = new InsetBibKey();
2079 par->bibkey->setCounter(number);
2080 par->labelstring = layout.labelstring();
2082 // In biblio should't be following counters but...
2084 string s = layout.labelstring();
2086 // the caption hack:
2087 if (layout.labeltype == LABEL_SENSITIVE) {
2088 bool isOK (par->InInset() && par->InInset()->owner() &&
2089 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2091 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2092 && (par->footnotekind == LyXParagraph::FIG
2093 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2094 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2095 ? ":øåéà" : "Figure:";
2096 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2097 && (par->footnotekind == LyXParagraph::TAB
2098 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2099 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2100 ? ":äìáè" : "Table:";
2101 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2102 && par->footnotekind == LyXParagraph::ALGORITHM) {
2103 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2104 ? ":íúéøåâìà" : "Algorithm:";
2108 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2110 = floatList.getType(tmp->type());
2111 // We should get the correct number here too.
2112 s = fl.name + " #:";
2114 /* par->SetLayout(0);
2115 s = layout->labelstring; */
2116 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2117 ? " :úåòîùî øñç" : "Senseless: ";
2120 par->labelstring = s;
2122 /* reset the enumeration counter. They are always resetted
2123 * when there is any other layout between */
2124 for (int i = 6 + par->enumdepth; i < 10; ++i)
2125 par->setCounter(i, 0);
2130 /* Updates all counters BEHIND the row. Changed paragraphs
2131 * with a dynamic left margin will be rebroken. */
2132 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2139 if (row->par()->next
2141 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2145 par = row->par()->LastPhysicalPar()->Next();
2147 par = row->par()->Next();
2150 par = row->par()->next;
2155 while (row->par() != par)
2158 SetCounter(bview->buffer(), par);
2160 /* now check for the headline layouts. remember that they
2161 * have a dynamic left margin */
2166 ( textclasslist.Style(bview->buffer()->params.textclass,
2167 par->layout).margintype == MARGIN_DYNAMIC
2168 || textclasslist.Style(bview->buffer()->params.textclass,
2169 par->layout).labeltype == LABEL_SENSITIVE)
2172 /* Rebreak the paragraph */
2173 RemoveParagraph(row);
2174 AppendParagraph(bview, row);
2177 /* think about the damned open footnotes! */
2178 while (par->Next() &&
2179 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2180 || par->Next()->IsDummy())){
2182 if (par->IsDummy()) {
2183 while (row->par() != par)
2185 RemoveParagraph(row);
2186 AppendParagraph(bview, row);
2192 par = par->LastPhysicalPar()->Next();
2201 /* insets an inset. */
2202 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2204 if (!cursor.par()->InsertInsetAllowed(inset))
2206 SetUndo(bview->buffer(), Undo::INSERT,
2207 cursor.par()->ParFromPos(cursor.pos())->previous,
2208 cursor.par()->ParFromPos(cursor.pos())->next);
2209 cursor.par()->InsertInset(cursor.pos(), inset);
2210 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2211 * The character will not be inserted a
2216 void LyXText::copyEnvironmentType()
2218 copylayouttype = cursor.par()->GetLayout();
2222 void LyXText::pasteEnvironmentType(BufferView * bview)
2224 SetLayout(bview, copylayouttype);
2228 void LyXText::CutSelection(BufferView * bview, bool doclear)
2230 // Stuff what we got on the clipboard. Even if there is no selection.
2232 // There is a problem with having the stuffing here in that the
2233 // larger the selection the slower LyX will get. This can be
2234 // solved by running the line below only when the selection has
2235 // finished. The solution used currently just works, to make it
2236 // faster we need to be more clever and probably also have more
2237 // calls to stuffClipboard. (Lgb)
2238 bview->stuffClipboard(selectionAsString(bview->buffer()));
2240 // This doesn't make sense, if there is no selection
2244 // OK, we have a selection. This is always between sel_start_cursor
2245 // and sel_end cursor
2247 // Check whether there are half footnotes in the selection
2248 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2249 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2250 LyXParagraph * tmppar = sel_start_cursor.par();
2251 while (tmppar != sel_end_cursor.par()){
2252 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2253 WriteAlert(_("Impossible operation"),
2254 _("Don't know what to do with half floats."),
2258 tmppar = tmppar->Next();
2263 /* table stuff -- begin */
2264 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2265 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2266 WriteAlert(_("Impossible operation"),
2267 _("Don't know what to do with half tables."),
2271 sel_start_cursor.par()->table->Reinit();
2273 /* table stuff -- end */
2275 // make sure that the depth behind the selection are restored, too
2277 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2279 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2281 LyXParagraph * undoendpar = endpar;
2283 if (endpar && endpar->GetDepth()) {
2284 while (endpar && endpar->GetDepth()) {
2286 endpar = endpar->LastPhysicalPar()->Next();
2288 endpar = endpar->Next();
2290 undoendpar = endpar;
2292 } else if (endpar) {
2293 endpar = endpar->Next(); // because of parindents etc.
2296 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2297 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2302 // there are two cases: cut only within one paragraph or
2303 // more than one paragraph
2304 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2305 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2306 // only within one paragraph
2307 endpar = sel_start_cursor.par();
2308 int pos = sel_end_cursor.pos();
2309 cap.cutSelection(sel_start_cursor.par(), &endpar,
2310 sel_start_cursor.pos(), pos,
2311 bview->buffer()->params.textclass, doclear);
2312 sel_end_cursor.pos(pos);
2314 endpar = sel_end_cursor.par();
2316 int pos = sel_end_cursor.pos();
2317 cap.cutSelection(sel_start_cursor.par(), &endpar,
2318 sel_start_cursor.pos(), pos,
2319 bview->buffer()->params.textclass, doclear);
2321 sel_end_cursor.par(endpar);
2322 sel_end_cursor.pos(pos);
2323 cursor.pos(sel_end_cursor.pos());
2325 endpar = endpar->Next();
2327 // sometimes necessary
2329 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2331 RedoParagraphs(bview, sel_start_cursor, endpar);
2334 cursor = sel_start_cursor;
2335 SetCursor(bview, cursor.par(), cursor.pos());
2336 sel_cursor = cursor;
2337 UpdateCounters(bview, cursor.row());
2341 void LyXText::CopySelection(BufferView * bview)
2343 // Stuff what we got on the clipboard. Even if there is no selection.
2345 // There is a problem with having the stuffing here in that the
2346 // larger the selection the slower LyX will get. This can be
2347 // solved by running the line below only when the selection has
2348 // finished. The solution used currently just works, to make it
2349 // faster we need to be more clever and probably also have more
2350 // calls to stuffClipboard. (Lgb)
2351 bview->stuffClipboard(selectionAsString(bview->buffer()));
2353 // this doesnt make sense, if there is no selection
2357 // ok we have a selection. This is always between sel_start_cursor
2358 // and sel_end cursor
2361 /* check wether there are half footnotes in the selection */
2362 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2363 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2364 LyXParagraph * tmppar = sel_start_cursor.par();
2365 while (tmppar != sel_end_cursor.par()) {
2366 if (tmppar->footnoteflag !=
2367 sel_end_cursor.par()->footnoteflag) {
2368 WriteAlert(_("Impossible operation"),
2369 _("Don't know what to do"
2370 " with half floats."),
2374 tmppar = tmppar->Next();
2379 /* table stuff -- begin */
2380 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2381 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2382 WriteAlert(_("Impossible operation"),
2383 _("Don't know what to do with half tables."),
2388 /* table stuff -- end */
2391 // copy behind a space if there is one
2392 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2393 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2394 && (sel_start_cursor.par() != sel_end_cursor.par()
2395 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2396 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2400 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2401 sel_start_cursor.pos(), sel_end_cursor.pos(),
2402 bview->buffer()->params.textclass);
2406 void LyXText::PasteSelection(BufferView * bview)
2410 // this does not make sense, if there is nothing to paste
2411 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2414 SetUndo(bview->buffer(), Undo::INSERT,
2415 cursor.par()->ParFromPos(cursor.pos())->previous,
2416 cursor.par()->ParFromPos(cursor.pos())->next);
2418 LyXParagraph * endpar;
2419 LyXParagraph * actpar = cursor.par();
2421 int pos = cursor.pos();
2422 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2424 RedoParagraphs(bview, cursor, endpar);
2426 SetCursor(bview, cursor.par(), cursor.pos());
2429 sel_cursor = cursor;
2430 SetCursor(bview, actpar, pos);
2432 UpdateCounters(bview, cursor.row());
2436 // returns a pointer to the very first LyXParagraph
2437 LyXParagraph * LyXText::FirstParagraph() const
2439 return OwnerParagraph();
2443 // returns true if the specified string is at the specified position
2444 bool LyXText::IsStringInText(LyXParagraph * par,
2445 LyXParagraph::size_type pos,
2446 char const * str) const
2450 while (pos + i < par->Last() && str[i] &&
2451 str[i] == par->GetChar(pos + i)) {
2461 // sets the selection over the number of characters of string, no check!!
2462 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2464 sel_cursor = cursor;
2465 for (int i = 0; string[i]; ++i)
2471 // simple replacing. The font of the first selected character is used
2472 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2474 SetCursorParUndo(bview->buffer());
2477 if (!selection) { // create a dummy selection
2478 sel_end_cursor = cursor;
2479 sel_start_cursor = cursor;
2482 // Get font setting before we cut
2483 LyXParagraph::size_type pos = sel_end_cursor.pos();
2484 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2485 sel_start_cursor.pos());
2487 // Insert the new string
2488 for (int i = 0; str[i]; ++i) {
2489 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2493 // Cut the selection
2494 CutSelection(bview);
2500 // if the string can be found: return true and set the cursor to
2502 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2504 LyXParagraph * par = cursor.par();
2505 LyXParagraph::size_type pos = cursor.pos();
2506 while (par && !IsStringInText(par, pos, str)) {
2507 if (pos < par->Last() - 1)
2515 SetCursor(bview, par, pos);
2523 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2525 LyXParagraph * par = cursor.par();
2526 int pos = cursor.pos();
2532 // We skip empty paragraphs (Asger)
2534 par = par->Previous();
2536 pos = par->Last() - 1;
2537 } while (par && pos < 0);
2539 } while (par && !IsStringInText(par, pos, string));
2542 SetCursor(bview, par, pos);
2549 // needed to insert the selection
2550 void LyXText::InsertStringA(BufferView * bview, string const & str)
2552 LyXParagraph * par = cursor.par();
2553 LyXParagraph::size_type pos = cursor.pos();
2554 LyXParagraph::size_type a = 0;
2555 LyXParagraph * endpar = cursor.par()->Next();
2557 SetCursorParUndo(bview->buffer());
2560 textclasslist.Style(bview->buffer()->params.textclass,
2561 cursor.par()->GetLayout()).isEnvironment();
2562 // only to be sure, should not be neccessary
2565 // insert the string, don't insert doublespace
2566 string::size_type i = 0;
2567 while (i < str.length()) {
2568 if (str[i] != '\n') {
2570 && i + 1 < str.length() && str[i + 1] != ' '
2571 && pos && par->GetChar(pos - 1)!= ' ') {
2572 par->InsertChar(pos, ' ', current_font);
2575 } else if (par->table) {
2576 if (str[i] == '\t') {
2577 while((pos < par->size()) &&
2578 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2580 if (pos < par->size())
2582 else // no more fields to fill skip the rest
2584 } else if ((str[i] != 13) &&
2585 ((str[i] & 127) >= ' ')) {
2586 par->InsertChar(pos, str[i],
2591 } else if (str[i] == ' ') {
2592 InsetSpecialChar * new_inset =
2593 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2594 if (par->InsertInsetAllowed(new_inset)) {
2595 par->InsertInset(pos, new_inset,
2601 } else if (str[i] == '\t') {
2602 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2603 InsetSpecialChar * new_inset =
2604 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2605 if (par->InsertInsetAllowed(new_inset)) {
2606 par->InsertInset(pos, new_inset,
2613 } else if (str[i] != 13 &&
2614 // Ignore unprintables
2615 (str[i] & 127) >= ' ') {
2616 par->InsertChar(pos, str[i], current_font);
2622 if ((i + 1) >= str.length()) {
2623 if (pos < par->size())
2627 while((pos < par->size()) &&
2628 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2631 int cell = NumberOfCell(par, pos);
2632 while((pos < par->size()) &&
2633 !(par->table->IsFirstCell(cell))) {
2635 while((pos < par->size()) &&
2636 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2639 cell = NumberOfCell(par, pos);
2641 if (pos >= par->size())
2642 // no more fields to fill skip the rest
2646 if (!par->size()) { // par is empty
2647 InsetSpecialChar * new_inset =
2648 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2649 if (par->InsertInsetAllowed(new_inset)) {
2650 par->InsertInset(pos,
2658 par->BreakParagraph(bview->buffer()->params, pos, flag);
2668 RedoParagraphs(bview, cursor, endpar);
2669 SetCursor(bview, cursor.par(), cursor.pos());
2670 sel_cursor = cursor;
2671 SetCursor(bview, par, pos);
2676 /* turns double-CR to single CR, others where converted into one blank and 13s
2677 * that are ignored .Double spaces are also converted into one. Spaces at
2678 * the beginning of a paragraph are forbidden. tabs are converted into one
2679 * space. then InsertStringA is called */
2680 void LyXText::InsertStringB(BufferView * bview, string const & s)
2684 LyXParagraph * par = cursor.par();
2686 string::size_type i = 1;
2687 while (i < str.length()) {
2694 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2696 if (str[i] == '\n' && i + 1 < str.length()
2701 if (str[i + 1] != '\n') {
2702 if (str[i - 1] != ' ')
2707 while (i + 1 < str.length()
2708 && (str[i + 1] == ' '
2709 || str[i + 1] == '\t'
2710 || str[i + 1] == '\n'
2711 || str[i + 1] == 13)) {
2718 InsertStringA(bview, str);
2722 bool LyXText::GotoNextError(BufferView * bview) const
2724 LyXCursor res = cursor;
2726 if (res.pos() < res.par()->Last() - 1) {
2727 res.pos(res.pos() + 1);
2729 res.par(res.par()->Next());
2733 } while (res.par() &&
2734 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2735 && res.par()->GetInset(res.pos())->AutoDelete()));
2738 SetCursor(bview, res.par(), res.pos());
2745 bool LyXText::GotoNextNote(BufferView * bview) const
2747 LyXCursor res = cursor;
2749 if (res.pos() < res.par()->Last() - 1) {
2750 res.pos(res.pos() + 1);
2752 res.par(res.par()->Next());
2756 } while (res.par() &&
2757 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2758 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2761 SetCursor(bview, res.par(), res.pos());
2768 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2769 LyXParagraph::size_type pos)
2771 LyXCursor tmpcursor;
2774 /* table stuff -- begin*/
2777 CheckParagraphInTable(bview, par, pos);
2781 /* table stuff -- end*/
2784 LyXParagraph::size_type z;
2785 Row * row = GetRow(par, pos, y);
2787 // is there a break one row above
2788 if (row->previous() && row->previous()->par() == row->par()) {
2789 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2790 if ( z >= row->pos()) {
2791 // set the dimensions of the row above
2792 y -= row->previous()->height();
2794 refresh_row = row->previous();
2795 status = LyXText::NEED_MORE_REFRESH;
2797 BreakAgain(bview, row->previous());
2799 // set the cursor again. Otherwise
2800 // dangling pointers are possible
2801 SetCursor(bview, cursor.par(), cursor.pos());
2802 sel_cursor = cursor;
2807 int tmpheight = row->height();
2808 LyXParagraph::size_type tmplast = RowLast(row);
2812 BreakAgain(bview, row);
2813 if (row->height() == tmpheight && RowLast(row) == tmplast)
2814 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2816 status = LyXText::NEED_MORE_REFRESH;
2818 // check the special right address boxes
2819 if (textclasslist.Style(bview->buffer()->params.textclass,
2820 par->GetLayout()).margintype
2821 == MARGIN_RIGHT_ADDRESS_BOX) {
2828 RedoDrawingOfParagraph(bview, tmpcursor);
2834 // set the cursor again. Otherwise dangling pointers are possible
2835 // also set the selection
2839 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2840 sel_cursor = cursor;
2841 SetCursorIntern(bview, sel_start_cursor.par(),
2842 sel_start_cursor.pos());
2843 sel_start_cursor = cursor;
2844 SetCursorIntern(bview, sel_end_cursor.par(),
2845 sel_end_cursor.pos());
2846 sel_end_cursor = cursor;
2847 SetCursorIntern(bview, last_sel_cursor.par(),
2848 last_sel_cursor.pos());
2849 last_sel_cursor = cursor;
2852 SetCursorIntern(bview, cursor.par(), cursor.pos());
2856 // returns false if inset wasn't found
2857 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2859 // first check the current paragraph
2860 int pos = cursor.par()->GetPositionOfInset(inset);
2862 CheckParagraph(bview, cursor.par(), pos);
2866 // check every paragraph
2868 LyXParagraph * par = FirstParagraph();
2871 // make sure the paragraph is open
2872 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2874 pos = par->GetPositionOfInset(inset);
2876 CheckParagraph(bview, par, pos);
2889 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2890 LyXParagraph::size_type pos,
2891 bool setfont, bool boundary) const
2893 LyXCursor old_cursor = cursor;
2894 SetCursorIntern(bview, par, pos, setfont, boundary);
2895 DeleteEmptyParagraphMechanism(bview, old_cursor);
2899 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2900 LyXParagraph::size_type pos, bool boundary) const
2902 // correct the cursor position if impossible
2903 if (pos > par->Last()){
2904 LyXParagraph * tmppar = par->ParFromPos(pos);
2905 pos = par->PositionInParFromPos(pos);
2909 if (par->IsDummy() && par->previous &&
2910 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2911 while (par->previous &&
2912 ((par->previous->IsDummy() &&
2913 (par->previous->previous->footnoteflag ==
2914 LyXParagraph::CLOSED_FOOTNOTE)) ||
2915 (par->previous->footnoteflag ==
2916 LyXParagraph::CLOSED_FOOTNOTE))) {
2917 par = par->previous ;
2918 if (par->IsDummy() &&
2919 (par->previous->footnoteflag ==
2920 LyXParagraph::CLOSED_FOOTNOTE))
2921 pos += par->size() + 1;
2923 if (par->previous) {
2924 par = par->previous;
2926 pos += par->size() + 1;
2931 cur.boundary(boundary);
2933 /* get the cursor y position in text */
2935 Row * row = GetRow(par, pos, y);
2936 /* y is now the beginning of the cursor row */
2937 y += row->baseline();
2938 /* y is now the cursor baseline */
2941 /* now get the cursors x position */
2943 float fill_separator, fill_hfill, fill_label_hfill;
2944 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2946 LyXParagraph::size_type cursor_vpos = 0;
2947 LyXParagraph::size_type last = RowLastPrintable(row);
2949 if (pos > last + 1) // This shouldn't happen.
2951 else if (pos < row->pos())
2954 if (last < row->pos())
2955 cursor_vpos = row->pos();
2956 else if (pos > last && !boundary)
2957 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2958 ? row->pos() : last + 1;
2959 else if (pos > row->pos() &&
2960 (pos > last || boundary
2962 || (row->par()->table && row->par()->IsNewline(pos))
2965 /// Place cursor after char at (logical) position pos - 1
2966 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2967 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2969 /// Place cursor before char at (logical) position pos
2970 cursor_vpos = (bidi_level(pos) % 2 == 0)
2971 ? log2vis(pos) : log2vis(pos) + 1;
2974 /* table stuff -- begin*/
2975 if (row->par()->table) {
2976 int cell = NumberOfCell(row->par(), row->pos());
2978 x += row->par()->table->GetBeginningOfTextInCell(cell);
2979 for (LyXParagraph::size_type vpos = row->pos();
2980 vpos < cursor_vpos; ++vpos) {
2981 pos = vis2log(vpos);
2982 if (row->par()->IsNewline(pos)) {
2983 x = x_old + row->par()->table->WidthOfColumn(cell);
2986 x += row->par()->table->GetBeginningOfTextInCell(cell);
2988 x += SingleWidth(bview, row->par(), pos);
2992 /* table stuff -- end*/
2994 LyXParagraph::size_type main_body =
2995 BeginningOfMainBody(bview->buffer(), row->par());
2996 if ((main_body > 0) &&
2997 ((main_body-1 > last) ||
2998 !row->par()->IsLineSeparator(main_body-1)))
3001 for (LyXParagraph::size_type vpos = row->pos();
3002 vpos < cursor_vpos; ++vpos) {
3003 pos = vis2log(vpos);
3004 if (main_body > 0 && pos == main_body-1) {
3005 x += fill_label_hfill +
3006 lyxfont::width(textclasslist.Style(
3007 bview->buffer()->params.textclass,
3008 row->par()->GetLayout())
3010 GetFont(bview->buffer(), row->par(), -2));
3011 if (row->par()->IsLineSeparator(main_body-1))
3012 x -= SingleWidth(bview, row->par(),main_body-1);
3014 if (HfillExpansion(bview->buffer(), row, pos)) {
3015 x += SingleWidth(bview, row->par(), pos);
3016 if (pos >= main_body)
3019 x += fill_label_hfill;
3020 } else if (row->par()->IsSeparator(pos)) {
3021 x += SingleWidth(bview, row->par(), pos);
3022 if (pos >= main_body)
3023 x += fill_separator;
3025 x += SingleWidth(bview, row->par(), pos);
3037 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3038 LyXParagraph::size_type pos,
3039 bool setfont, bool boundary) const
3041 SetCursor(bview, cursor, par, pos, boundary);
3043 SetCurrentFont(bview);
3046 void LyXText::SetCurrentFont(BufferView * bview) const
3048 LyXParagraph::size_type pos = cursor.pos();
3049 if (cursor.boundary() && pos > 0)
3053 if (pos == cursor.par()->Last()
3055 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3059 else if (cursor.par()->IsSeparator(pos)) {
3060 if (pos > cursor.row()->pos() &&
3061 bidi_level(pos) % 2 ==
3062 bidi_level(pos - 1) % 2)
3064 else if (pos + 1 < cursor.par()->Last())
3070 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3071 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3073 if (cursor.pos() == cursor.par()->Last() &&
3074 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3075 !cursor.boundary()) {
3076 Language const * lang =
3077 cursor.par()->getParLanguage(bview->buffer()->params);
3078 current_font.setLanguage(lang);
3079 real_current_font.setLanguage(lang);
3084 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3086 LyXCursor old_cursor = cursor;
3088 /* get the row first */
3090 Row * row = GetRowNearY(y);
3091 cursor.par(row->par());
3094 int column = GetColumnNearX(bview, row, x, bound);
3095 cursor.pos(row->pos() + column);
3097 cursor.y(y + row->baseline());
3099 cursor.boundary(bound);
3100 SetCurrentFont(bview);
3101 DeleteEmptyParagraphMechanism(bview, old_cursor);
3105 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3106 int x, long y) const
3108 /* get the row first */
3110 Row * row = GetRowNearY(y);
3112 int column = GetColumnNearX(bview, row, x, bound);
3114 cur.par(row->par());
3115 cur.pos(row->pos() + column);
3117 cur.y(y + row->baseline());
3119 cur.boundary(bound);
3123 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3125 CursorLeftIntern(bview, internal);
3127 if (cursor.par()->table) {
3128 int cell = NumberOfCell(cursor.par(), cursor.pos());
3129 if (cursor.par()->table->IsContRow(cell)
3130 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3138 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3140 if (cursor.pos() > 0) {
3141 bool boundary = cursor.boundary();
3142 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3143 if (!internal && !boundary &&
3144 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3145 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3146 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3147 LyXParagraph * par = cursor.par()->Previous();
3148 SetCursor(bview, par, par->Last());
3153 void LyXText::CursorRight(BufferView * bview, bool internal) const
3155 CursorRightIntern(bview, internal);
3157 if (cursor.par()->table) {
3158 int cell = NumberOfCell(cursor.par(), cursor.pos());
3159 if (cursor.par()->table->IsContRow(cell) &&
3160 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3168 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3170 if (!internal && cursor.boundary() &&
3173 !cursor.par()->table ||
3175 !cursor.par()->IsNewline(cursor.pos())))
3176 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3177 else if (cursor.pos() < cursor.par()->Last()) {
3178 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3180 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3181 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3182 } else if (cursor.par()->Next())
3183 SetCursor(bview, cursor.par()->Next(), 0);
3187 void LyXText::CursorUp(BufferView * bview) const
3189 SetCursorFromCoordinates(bview, cursor.x_fix(),
3190 cursor.y() - cursor.row()->baseline() - 1);
3192 if (cursor.par()->table) {
3193 int cell = NumberOfCell(cursor.par(), cursor.pos());
3194 if (cursor.par()->table->IsContRow(cell) &&
3195 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3203 void LyXText::CursorDown(BufferView * bview) const
3206 if (cursor.par()->table &&
3207 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3208 !cursor.par()->next)
3212 SetCursorFromCoordinates(bview, cursor.x_fix(),
3213 cursor.y() - cursor.row()->baseline()
3214 + cursor.row()->height() + 1);
3216 if (cursor.par()->table) {
3217 int cell = NumberOfCell(cursor.par(), cursor.pos());
3218 int cell_above = cursor.par()->table->GetCellAbove(cell);
3219 while(cursor.par()->table &&
3220 cursor.par()->table->IsContRow(cell) &&
3221 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3222 SetCursorFromCoordinates(bview, cursor.x_fix(),
3223 cursor.y() - cursor.row()->baseline()
3224 + cursor.row()->height() + 1);
3225 if (cursor.par()->table) {
3226 cell = NumberOfCell(cursor.par(), cursor.pos());
3227 cell_above = cursor.par()->table->GetCellAbove(cell);
3235 void LyXText::CursorUpParagraph(BufferView * bview) const
3237 if (cursor.pos() > 0) {
3238 SetCursor(bview, cursor.par(), 0);
3240 else if (cursor.par()->Previous()) {
3241 SetCursor(bview, cursor.par()->Previous(), 0);
3246 void LyXText::CursorDownParagraph(BufferView * bview) const
3248 if (cursor.par()->Next()) {
3249 SetCursor(bview, cursor.par()->Next(), 0);
3251 SetCursor(bview, cursor.par(), cursor.par()->Last());
3256 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3257 LyXCursor const & old_cursor) const
3259 // Would be wrong to delete anything if we have a selection.
3260 if (selection) return;
3262 // We allow all kinds of "mumbo-jumbo" when freespacing.
3263 if (textclasslist.Style(bview->buffer()->params.textclass,
3264 old_cursor.par()->GetLayout()).free_spacing)
3267 bool deleted = false;
3269 /* Ok I'll put some comments here about what is missing.
3270 I have fixed BackSpace (and thus Delete) to not delete
3271 double-spaces automagically. I have also changed Cut,
3272 Copy and Paste to hopefully do some sensible things.
3273 There are still some small problems that can lead to
3274 double spaces stored in the document file or space at
3275 the beginning of paragraphs. This happens if you have
3276 the cursor betwenn to spaces and then save. Or if you
3277 cut and paste and the selection have a space at the
3278 beginning and then save right after the paste. I am
3279 sure none of these are very hard to fix, but I will
3280 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3281 that I can get some feedback. (Lgb)
3284 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3285 // delete the LineSeparator.
3288 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3289 // delete the LineSeparator.
3292 // If the pos around the old_cursor were spaces, delete one of them.
3293 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3294 // Only if the cursor has really moved
3296 if (old_cursor.pos() > 0
3297 && old_cursor.pos() < old_cursor.par()->Last()
3298 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3299 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3300 old_cursor.par()->Erase(old_cursor.pos() - 1);
3301 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3303 if (old_cursor.par() == cursor.par() &&
3304 cursor.pos() > old_cursor.pos()) {
3305 SetCursorIntern(bview, cursor.par(),
3308 SetCursorIntern(bview, cursor.par(),
3314 // Do not delete empty paragraphs with keepempty set.
3315 if ((textclasslist.Style(bview->buffer()->params.textclass,
3316 old_cursor.par()->GetLayout())).keepempty)
3319 LyXCursor tmpcursor;
3321 if (old_cursor.par() != cursor.par()) {
3322 if ( (old_cursor.par()->Last() == 0
3323 || (old_cursor.par()->Last() == 1
3324 && old_cursor.par()->IsLineSeparator(0)))
3326 && old_cursor.par()->FirstPhysicalPar()
3327 == old_cursor.par()->LastPhysicalPar()
3330 // ok, we will delete anything
3332 // make sure that you do not delete any environments
3335 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3336 !(old_cursor.row()->previous()
3337 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3338 && !(old_cursor.row()->next()
3339 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3340 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3341 && ((old_cursor.row()->previous()
3342 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3343 || (old_cursor.row()->next()
3344 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3347 status = LyXText::NEED_MORE_REFRESH;
3350 if (old_cursor.row()->previous()) {
3351 refresh_row = old_cursor.row()->previous();
3352 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3354 cursor = old_cursor; // that undo can restore the right cursor position
3355 LyXParagraph * endpar = old_cursor.par()->next;
3356 if (endpar && endpar->GetDepth()) {
3357 while (endpar && endpar->GetDepth()) {
3359 endpar = endpar->LastPhysicalPar()->Next();
3361 endpar = endpar->Next();
3365 SetUndo(bview->buffer(), Undo::DELETE,
3366 old_cursor.par()->previous,
3371 RemoveRow(old_cursor.row());
3372 if (OwnerParagraph() == old_cursor.par()) {
3373 OwnerParagraph(OwnerParagraph()->next);
3376 delete old_cursor.par();
3378 /* Breakagain the next par. Needed
3379 * because of the parindent that
3380 * can occur or dissappear. The
3381 * next row can change its height,
3382 * if there is another layout before */
3383 if (refresh_row->next()) {
3384 BreakAgain(bview, refresh_row->next());
3385 UpdateCounters(bview, refresh_row);
3387 SetHeightOfRow(bview, refresh_row);
3389 refresh_row = old_cursor.row()->next();
3390 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3393 cursor = old_cursor; // that undo can restore the right cursor position
3394 LyXParagraph * endpar = old_cursor.par()->next;
3395 if (endpar && endpar->GetDepth()) {
3396 while (endpar && endpar->GetDepth()) {
3398 endpar = endpar->LastPhysicalPar()->Next();
3400 endpar = endpar->Next();
3404 SetUndo(bview->buffer(), Undo::DELETE,
3405 old_cursor.par()->previous,
3410 RemoveRow(old_cursor.row());
3412 if (OwnerParagraph() == old_cursor.par()) {
3413 OwnerParagraph(OwnerParagraph()->next);
3415 delete old_cursor.par();
3417 /* Breakagain the next par. Needed
3418 because of the parindent that can
3419 occur or dissappear.
3420 The next row can change its height,
3421 if there is another layout before
3424 BreakAgain(bview, refresh_row);
3425 UpdateCounters(bview, refresh_row->previous());
3431 SetCursorIntern(bview, cursor.par(), cursor.pos());
3433 if (sel_cursor.par() == old_cursor.par()
3434 && sel_cursor.pos() == sel_cursor.pos()) {
3435 // correct selection
3436 sel_cursor = cursor;
3443 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3444 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3446 SetCursorIntern(bview, cursor.par(), cursor.pos());
3447 sel_cursor = cursor;
3454 LyXParagraph * LyXText::GetParFromID(int id)
3456 LyXParagraph * result = FirstParagraph();
3457 while (result && result->id() != id)
3458 result = result->next;
3464 bool LyXText::TextUndo(BufferView * bview)
3468 // returns false if no undo possible
3469 Undo * undo = bview->buffer()->undostack.pop();
3473 bview->buffer()->redostack
3474 .push(CreateUndo(bview->buffer(), undo->kind,
3475 GetParFromID(undo->number_of_before_par),
3476 GetParFromID(undo->number_of_behind_par)));
3478 return TextHandleUndo(bview, undo);
3482 bool LyXText::TextRedo(BufferView * bview)
3486 // returns false if no redo possible
3487 Undo * undo = bview->buffer()->redostack.pop();
3491 bview->buffer()->undostack
3492 .push(CreateUndo(bview->buffer(), undo->kind,
3493 GetParFromID(undo->number_of_before_par),
3494 GetParFromID(undo->number_of_behind_par)));
3496 return TextHandleUndo(bview, undo);
3500 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3504 // returns false if no undo possible
3505 bool result = false;
3507 LyXParagraph * before =
3508 GetParFromID(undo->number_of_before_par);
3509 LyXParagraph * behind =
3510 GetParFromID(undo->number_of_behind_par);
3511 LyXParagraph * tmppar;
3512 LyXParagraph * tmppar2;
3513 LyXParagraph * endpar;
3514 LyXParagraph * tmppar5;
3516 // if there's no before take the beginning
3517 // of the document for redoing
3519 SetCursorIntern(bview, FirstParagraph(), 0);
3521 // replace the paragraphs with the undo informations
3523 LyXParagraph * tmppar3 = undo->par;
3524 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3525 LyXParagraph * tmppar4 = tmppar3;
3527 while (tmppar4->next)
3528 tmppar4 = tmppar4->next;
3529 } // get last undo par
3531 // now remove the old text if there is any
3532 if (before != behind || (!behind && !before)){
3534 tmppar5 = before->next;
3536 tmppar5 = OwnerParagraph();
3538 while (tmppar5 && tmppar5 != behind){
3540 tmppar5 = tmppar5->next;
3541 // a memory optimization for edit: Only layout information
3542 // is stored in the undo. So restore the text informations.
3543 if (undo->kind == Undo::EDIT) {
3544 tmppar2->setContentsFromPar(tmppar);
3545 tmppar->clearContents();
3546 tmppar2 = tmppar2->next;
3551 // put the new stuff in the list if there is one
3554 before->next = tmppar3;
3556 OwnerParagraph(tmppar3);
3557 tmppar3->previous = before;
3560 OwnerParagraph(behind);
3563 tmppar4->next = behind;
3565 behind->previous = tmppar4;
3569 // Set the cursor for redoing
3572 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3574 SetCursorIntern(bview, before, 0);
3577 // check wether before points to a closed float and open it if necessary
3578 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3579 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3581 while (tmppar4->previous &&
3582 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3583 tmppar4 = tmppar4->previous;
3584 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3585 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3586 tmppar4 = tmppar4->next;
3593 // open a cosed footnote at the end if necessary
3594 if (behind && behind->previous &&
3595 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3596 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3597 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3598 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3599 behind = behind->next;
3604 // calculate the endpar for redoing the paragraphs.
3607 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3608 endpar = behind->LastPhysicalPar()->Next();
3610 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3612 endpar = behind->Next();
3617 tmppar = GetParFromID(undo->number_of_cursor_par);
3618 RedoParagraphs(bview, cursor, endpar);
3620 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3621 UpdateCounters(bview, cursor.row());
3631 void LyXText::FinishUndo()
3635 // makes sure the next operation will be stored
3636 undo_finished = true;
3640 void LyXText::FreezeUndo()
3644 // this is dangerous and for internal use only
3649 void LyXText::UnFreezeUndo()
3653 // this is dangerous and for internal use only
3654 undo_frozen = false;
3658 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3659 LyXParagraph const * before,
3660 LyXParagraph const * behind) const
3665 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3666 buf->redostack.clear();
3670 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3671 LyXParagraph const * before, LyXParagraph const * behind)
3675 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3679 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3680 LyXParagraph const * before,
3681 LyXParagraph const * behind) const
3686 int before_number = -1;
3687 int behind_number = -1;
3689 before_number = before->id();
3691 behind_number = behind->id();
3692 // Undo::EDIT and Undo::FINISH are
3693 // always finished. (no overlapping there)
3694 // overlapping only with insert and delete inside one paragraph:
3695 // Nobody wants all removed character
3696 // appear one by one when undoing.
3697 // EDIT is special since only layout information, not the
3698 // contents of a paragaph are stored.
3699 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3700 // check wether storing is needed
3701 if (!buf->undostack.empty() &&
3702 buf->undostack.top()->kind == kind &&
3703 buf->undostack.top()->number_of_before_par == before_number &&
3704 buf->undostack.top()->number_of_behind_par == behind_number ){
3709 // create a new Undo
3710 LyXParagraph * undopar;
3711 LyXParagraph * tmppar;
3712 LyXParagraph * tmppar2;
3714 LyXParagraph * start = 0;
3715 LyXParagraph * end = 0;
3718 start = before->next;
3720 start = FirstParagraph();
3722 end = behind->previous;
3724 end = FirstParagraph();
3730 && start != end->next
3731 && (before != behind || (!before && !behind))) {
3733 tmppar2 = tmppar->Clone();
3734 tmppar2->id(tmppar->id());
3736 // a memory optimization: Just store the layout information
3738 if (kind == Undo::EDIT){
3739 //tmppar2->text.clear();
3740 tmppar2->clearContents();
3745 while (tmppar != end && tmppar->next) {
3746 tmppar = tmppar->next;
3747 tmppar2->next = tmppar->Clone();
3748 tmppar2->next->id(tmppar->id());
3749 // a memory optimization: Just store the layout
3750 // information when only edit
3751 if (kind == Undo::EDIT){
3752 //tmppar2->next->text.clear();
3753 tmppar2->clearContents();
3755 tmppar2->next->previous = tmppar2;
3756 tmppar2 = tmppar2->next;
3760 undopar = 0; // nothing to replace (undo of delete maybe)
3762 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3763 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3765 Undo * undo = new Undo(kind,
3766 before_number, behind_number,
3767 cursor_par, cursor_pos,
3770 undo_finished = false;
3775 void LyXText::SetCursorParUndo(Buffer * buf)
3779 SetUndo(buf, Undo::FINISH,
3780 cursor.par()->ParFromPos(cursor.pos())->previous,
3781 cursor.par()->ParFromPos(cursor.pos())->next);
3786 void LyXText::RemoveTableRow(LyXCursor & cur) const
3792 // move to the previous row
3793 int cell_act = NumberOfCell(cur.par(), cur.pos());
3796 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3797 cur.pos(cur.pos() - 1);
3799 !cur.par()->table->IsFirstCell(cell_act)) {
3800 cur.pos(cur.pos() - 1);
3801 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3802 cur.pos(cur.pos() - 1);
3806 // now we have to pay attention if the actual table is the
3807 // main row of TableContRows and if yes to delete all of them
3812 // delete up to the next row
3813 while (cur.pos() < cur.par()->Last() &&
3815 || !cur.par()->table->IsFirstCell(cell_act))) {
3816 while (cur.pos() < cur.par()->Last() &&
3817 !cur.par()->IsNewline(cur.pos()))
3818 cur.par()->Erase(cur.pos());
3821 if (cur.pos() < cur.par()->Last())
3822 cur.par()->Erase(cur.pos());
3824 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3825 cur.pos(cur.pos() - 1);
3826 cur.par()->Erase(cur.pos()); // no newline at very end!
3828 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3829 !cur.par()->table->IsContRow(cell_org) &&
3830 cur.par()->table->IsContRow(cell));
3831 cur.par()->table->DeleteRow(cell_org);
3838 bool LyXText::IsEmptyTableCell() const
3840 LyXParagraph::size_type pos = cursor.pos() - 1;
3841 while (pos >= 0 && pos < cursor.par()->Last()
3842 && !cursor.par()->IsNewline(pos))
3844 return cursor.par()->IsNewline(pos + 1);
3849 void LyXText::toggleAppendix(BufferView * bview)
3852 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3854 LyXParagraph * par = cursor.par();
3856 bool start = !par->start_of_appendix;
3858 // ensure that we have only one start_of_appendix in this document
3859 LyXParagraph * tmp = FirstParagraph();
3860 for (; tmp; tmp = tmp->next)
3861 tmp->start_of_appendix = 0;
3862 par->start_of_appendix = start;
3864 // we can set the refreshing parameters now
3865 status = LyXText::NEED_MORE_REFRESH;
3867 refresh_row = 0; // not needed for full update
3868 UpdateCounters(bview, 0);
3869 SetCursor(bview, cursor.par(), cursor.pos());
3873 LyXParagraph * LyXText::OwnerParagraph() const
3876 return inset_owner->par;
3878 return bv_owner->buffer()->paragraph;
3882 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3885 inset_owner->par = p;
3887 bv_owner->buffer()->paragraph = p;