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"
47 //#define USE_OLD_CUT_AND_PASTE 1
53 LyXText::LyXText(BufferView * bv)
61 LyXText::LyXText(InsetText * inset)
78 status = LyXText::UNCHANGED;
79 // set cursor at the very top position
80 selection = true; /* these setting is necessary
81 because of the delete-empty-
82 paragraph mechanism in
85 LyXParagraph * par = OwnerParagraph();
86 current_font = GetFont(bv_owner->buffer(), par, 0);
88 InsertParagraph(bv_owner, par, lastrow);
91 SetCursor(bv_owner, firstrow->par(), 0);
93 current_font = LyXFont(LyXFont::ALL_SANE);
99 // no rebreak necessary
102 undo_finished = true;
105 // Default layouttype for copy environment type
109 // Dump all rowinformation:
110 Row * tmprow = firstrow;
111 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113 lyxerr << tmprow->baseline() << '\t'
114 << tmprow->par << '\t'
115 << tmprow->pos() << '\t'
116 << tmprow->height << '\t'
117 << tmprow->ascent_of_text << '\t'
118 << tmprow->fill << '\n';
119 tmprow = tmprow->next();
126 void LyXText::init(BufferView * bview)
131 LyXParagraph * par = OwnerParagraph();
132 current_font = GetFont(bview->buffer(), par, 0);
134 InsertParagraph(bview, par, lastrow);
137 SetCursorIntern(bview, firstrow->par(), 0);
140 // Dump all rowinformation:
141 Row * tmprow = firstrow;
142 lyxerr << "Width = " << width << endl;
143 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
145 lyxerr << tmprow->baseline() << '\t'
146 << tmprow->par() << '\t'
147 << tmprow->pos() << '\t'
148 << tmprow->height() << '\t'
149 << tmprow->ascent_of_text() << '\t'
150 << tmprow->fill() << '\n';
151 tmprow = tmprow->next();
159 // Delete all rows, this does not touch the paragraphs!
160 Row * tmprow = firstrow;
162 tmprow = firstrow->next();
169 // Gets the fully instantiated font at a given position in a paragraph
170 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
171 // The difference is that this one is used for displaying, and thus we
172 // are allowed to make cosmetic improvements. For instance make footnotes
174 // If position is -1, we get the layout font of the paragraph.
175 // If position is -2, we get the font of the manual label of the paragraph.
176 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
177 LyXParagraph::size_type pos) const
179 LyXLayout const & layout =
180 textclasslist.Style(buf->params.textclass, par->GetLayout());
182 char par_depth = par->GetDepth();
183 // We specialize the 95% common case:
186 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
191 if (layout.labeltype == LABEL_MANUAL
192 && pos < BeginningOfMainBody(buf, par)) {
194 return par->GetFontSettings(buf->params, pos).
195 realize(layout.reslabelfont);
197 return par->GetFontSettings(buf->params, pos).
198 realize(layout.resfont);
201 // process layoutfont for pos == -1 and labelfont for pos < -1
203 return layout.resfont;
205 return layout.reslabelfont;
209 // The uncommon case need not be optimized as much
211 LyXFont layoutfont, tmpfont;
215 if (pos < BeginningOfMainBody(buf, par)) {
217 layoutfont = layout.labelfont;
220 layoutfont = layout.font;
222 tmpfont = par->GetFontSettings(buf->params, pos);
223 tmpfont.realize(layoutfont);
226 // process layoutfont for pos == -1 and labelfont for pos < -1
228 tmpfont = layout.font;
230 tmpfont = layout.labelfont;
233 // Resolve against environment font information
234 while (par && par_depth && !tmpfont.resolved()) {
235 par = par->DepthHook(par_depth - 1);
237 tmpfont.realize(textclasslist.
238 Style(buf->params.textclass,
239 par->GetLayout()).font);
240 par_depth = par->GetDepth();
244 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
247 // Cosmetic improvement: If this is an open footnote, make the font
249 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
250 && par->footnotekind == LyXParagraph::FOOTNOTE) {
258 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
259 LyXParagraph::size_type pos,
263 // Let the insets convert their font
264 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
265 if (par->GetInset(pos))
266 font = par->GetInset(pos)->ConvertFont(font);
269 LyXLayout const & layout =
270 textclasslist.Style(buf->params.textclass,
273 // Get concrete layout font to reduce against
276 if (pos < BeginningOfMainBody(buf, par))
277 layoutfont = layout.labelfont;
279 layoutfont = layout.font;
281 // Realize against environment font information
282 if (par->GetDepth()){
283 LyXParagraph * tp = par;
284 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
285 tp = tp->DepthHook(tp->GetDepth()-1);
287 layoutfont.realize(textclasslist.
288 Style(buf->params.textclass,
289 tp->GetLayout()).font);
293 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
296 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
297 && par->footnotekind == LyXParagraph::FOOTNOTE) {
298 layoutfont.decSize();
301 // Now, reduce font against full layout font
302 font.reduce(layoutfont);
304 par->SetFont(pos, font);
308 /* inserts a new row behind the specified row, increments
309 * the touched counters */
310 void LyXText::InsertRow(Row * row, LyXParagraph * par,
311 LyXParagraph::size_type pos) const
313 Row * tmprow = new Row;
316 tmprow->next(firstrow);
319 tmprow->previous(row);
320 tmprow->next(row->next());
325 tmprow->next()->previous(tmprow);
327 if (tmprow->previous())
328 tmprow->previous()->next(tmprow);
336 ++number_of_rows; // one more row
340 // removes the row and reset the touched counters
341 void LyXText::RemoveRow(Row * row) const
343 /* this must not happen before the currentrow for clear reasons.
344 so the trick is just to set the current row onto the previous
347 GetRow(row->par(), row->pos(), unused_y);
350 row->next()->previous(row->previous());
351 if (!row->previous()) {
352 firstrow = row->next();
354 row->previous()->next(row->next());
357 lastrow = row->previous();
359 height -= row->height(); // the text becomes smaller
362 --number_of_rows; // one row less
366 // remove all following rows of the paragraph of the specified row.
367 void LyXText::RemoveParagraph(Row * row) const
369 LyXParagraph * tmppar = row->par();
373 while (row && row->par() == tmppar) {
374 tmprow = row->next();
381 // insert the specified paragraph behind the specified row
382 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
385 InsertRow(row, par, 0); /* insert a new row, starting
388 SetCounter(bview->buffer(), par); // set the counters
390 // and now append the whole paragraph behind the new row
393 AppendParagraph(bview, firstrow);
395 row->next()->height(0);
396 AppendParagraph(bview, row->next());
402 void LyXText::ToggleFootnote(BufferView * bview)
404 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
406 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
408 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
410 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
411 CloseFootnote(bview);
418 void LyXText::OpenStuff(BufferView * bview)
420 if (cursor.pos() == 0 && cursor.par()->bibkey){
421 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
422 } else if (cursor.pos() < cursor.par()->Last()
423 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
424 && cursor.par()->GetInset(cursor.pos())->Editable()) {
425 bview->owner()->getMiniBuffer()
426 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
427 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
428 SetCursorParUndo(bview->buffer());
429 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
433 ToggleFootnote(bview);
441 void LyXText::CloseFootnote(BufferView * bview)
443 LyXParagraph * tmppar;
444 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
446 // if the cursor is not in an open footnote, or
447 // there is no open footnote in this paragraph, just return.
448 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
451 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
452 bview->owner()->getMiniBuffer()
453 ->Set(_("Nothing to do"));
457 // ok, move the cursor right before the footnote
458 // just a little faster than using CursorRight()
460 cursor.par()->ParFromPos(cursor.pos()) != par;) {
461 cursor.pos(cursor.pos() + 1);
464 // now the cursor is at the beginning of the physical par
465 SetCursor(bview, cursor.par(),
467 cursor.par()->ParFromPos(cursor.pos())->size());
469 /* we are in a footnote, so let us move at the beginning */
470 /* this is just faster than using just CursorLeft() */
472 tmppar = cursor.par();
473 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
474 // just a little bit faster than movin the cursor
475 tmppar = tmppar->Previous();
477 SetCursor(bview, tmppar, tmppar->Last());
480 // the cursor must be exactly before the footnote
481 par = cursor.par()->ParFromPos(cursor.pos());
483 status = LyXText::NEED_MORE_REFRESH;
484 refresh_row = cursor.row();
485 refresh_y = cursor.y() - cursor.row()->baseline();
487 tmppar = cursor.par();
488 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
489 Row * row = cursor.row();
491 tmppar->CloseFootnote(cursor.pos());
493 while (tmppar != endpar) {
494 RemoveRow(row->next());
496 tmppar = row->next()->par();
501 AppendParagraph(bview, cursor.row());
503 SetCursor(bview, cursor.par(), cursor.pos());
507 if (cursor.row()->next())
508 SetHeightOfRow(bview, cursor.row()->next());
513 /* used in setlayout */
514 // Asger is not sure we want to do this...
515 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
519 LyXLayout const & layout =
520 textclasslist.Style(buf->params.textclass, par->GetLayout());
522 LyXFont layoutfont, tmpfont;
523 for (LyXParagraph::size_type pos = 0;
524 pos < par->Last(); ++pos) {
525 if (pos < BeginningOfMainBody(buf, par))
526 layoutfont = layout.labelfont;
528 layoutfont = layout.font;
530 tmpfont = par->GetFontSettings(buf->params, pos);
531 tmpfont.reduce(layoutfont);
532 par->SetFont(pos, tmpfont);
537 LyXParagraph * LyXText::SetLayout(BufferView * bview,
538 LyXCursor & cur, LyXCursor & sstart_cur,
539 LyXCursor & send_cur,
540 LyXTextClass::size_type layout)
543 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
545 LyXParagraph * endpar = send_cur.par()->Next();
547 LyXParagraph * undoendpar = endpar;
549 if (endpar && endpar->GetDepth()) {
550 while (endpar && endpar->GetDepth()) {
552 endpar = endpar->LastPhysicalPar()->Next();
554 endpar = endpar->Next();
559 endpar = endpar->Next(); // because of parindents etc.
562 SetUndo(bview->buffer(), Undo::EDIT,
563 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
566 /* ok we have a selection. This is always between sstart_cur
567 * and sel_end cursor */
570 LyXLayout const & lyxlayout =
571 textclasslist.Style(bview->buffer()->params.textclass, layout);
573 while (cur.par() != send_cur.par()) {
575 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
577 cur.par()->SetLayout(bview->buffer()->params, layout);
578 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
580 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
582 LyXParagraph * fppar = cur.par();
584 fppar->added_space_top = lyxlayout.fill_top ?
585 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
586 fppar->added_space_bottom = lyxlayout.fill_bottom ?
587 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
588 if (lyxlayout.margintype == MARGIN_MANUAL)
589 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
590 if (lyxlayout.labeltype != LABEL_BIBLIO
592 delete fppar->bibkey;
598 cur.par(cur.par()->Next());
601 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
603 cur.par()->SetLayout(bview->buffer()->params, layout);
604 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
606 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
608 LyXParagraph * fppar = cur.par();
610 fppar->added_space_top = lyxlayout.fill_top ?
611 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
612 fppar->added_space_bottom = lyxlayout.fill_bottom ?
613 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
614 if (lyxlayout.margintype == MARGIN_MANUAL)
615 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
616 if (lyxlayout.labeltype != LABEL_BIBLIO
618 delete fppar->bibkey;
627 // set layout over selection and make a total rebreak of those paragraphs
628 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
631 tmpcursor = cursor; /* store the current cursor */
633 #ifdef USE_OLD_SET_LAYOUT
634 // if there is no selection just set the layout
635 // of the current paragraph */
637 sel_start_cursor = cursor; // dummy selection
638 sel_end_cursor = cursor;
641 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
642 LyXParagraph * undoendpar = endpar;
644 if (endpar && endpar->GetDepth()) {
645 while (endpar && endpar->GetDepth()) {
646 endpar = endpar->LastPhysicalPar()->Next();
651 endpar = endpar->Next(); // because of parindents etc.
655 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
658 /* ok we have a selection. This is always between sel_start_cursor
659 * and sel_end cursor */
660 cursor = sel_start_cursor;
662 LyXLayout const & lyxlayout =
663 textclasslist.Style(bview->buffer()->params.textclass, layout);
665 while (cursor.par() != sel_end_cursor.par()) {
666 if (cursor.par()->footnoteflag ==
667 sel_start_cursor.par()->footnoteflag) {
668 cursor.par()->SetLayout(layout);
669 MakeFontEntriesLayoutSpecific(cursor.par());
670 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
671 fppar->added_space_top = lyxlayout.fill_top ?
672 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
673 fppar->added_space_bottom = lyxlayout.fill_bottom ?
674 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
675 if (lyxlayout.margintype == MARGIN_MANUAL)
676 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
677 if (lyxlayout.labeltype != LABEL_BIBLIO
679 delete fppar->bibkey;
683 cursor.par() = cursor.par()->Next();
685 if (cursor.par()->footnoteflag ==
686 sel_start_cursor.par()->footnoteflag) {
687 cursor.par()->SetLayout(layout);
688 MakeFontEntriesLayoutSpecific(cursor.par());
690 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
692 LyXParagraph* fppar = cursor.par();
694 fppar->added_space_top = lyxlayout.fill_top ?
695 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
696 fppar->added_space_bottom = lyxlayout.fill_bottom ?
697 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
698 if (lyxlayout.margintype == MARGIN_MANUAL)
699 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
700 if (lyxlayout.labeltype != LABEL_BIBLIO
702 delete fppar->bibkey;
707 // if there is no selection just set the layout
708 // of the current paragraph */
710 sel_start_cursor = cursor; // dummy selection
711 sel_end_cursor = cursor;
714 endpar = SetLayout(bview, cursor, sel_start_cursor,
715 sel_end_cursor, layout);
717 RedoParagraphs(bview, sel_start_cursor, endpar);
719 // we have to reset the selection, because the
720 // geometry could have changed */
721 SetCursor(bview, sel_start_cursor.par(),
722 sel_start_cursor.pos(), false);
724 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
726 UpdateCounters(bview, cursor.row());
729 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
733 // increment depth over selection and
734 // make a total rebreak of those paragraphs
735 void LyXText::IncDepth(BufferView * bview)
737 // If there is no selection, just use the current paragraph
739 sel_start_cursor = cursor; // dummy selection
740 sel_end_cursor = cursor;
743 // We end at the next paragraph with depth 0
744 LyXParagraph * endpar =
746 sel_end_cursor.par()->LastPhysicalPar()->Next();
748 sel_end_cursor.par()->Next();
750 LyXParagraph * undoendpar = endpar;
752 if (endpar && endpar->GetDepth()) {
753 while (endpar && endpar->GetDepth()) {
755 endpar = endpar->LastPhysicalPar()->Next();
757 endpar = endpar->Next();
763 endpar = endpar->Next(); // because of parindents etc.
766 SetUndo(bview->buffer(), Undo::EDIT,
768 .par()->ParFromPos(sel_start_cursor.pos())->previous,
771 LyXCursor tmpcursor = cursor; // store the current cursor
773 // ok we have a selection. This is always between sel_start_cursor
774 // and sel_end cursor
775 cursor = sel_start_cursor;
777 bool anything_changed = false;
780 // NOTE: you can't change the depth of a bibliography entry
783 cursor.par()->footnoteflag ==
784 sel_start_cursor.par()->footnoteflag &&
786 textclasslist.Style(bview->buffer()->params.textclass,
787 cursor.par()->GetLayout()
788 ).labeltype != LABEL_BIBLIO) {
789 LyXParagraph * prev =
791 cursor.par()->FirstPhysicalPar()->Previous();
793 cursor.par()->Previous();
796 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
797 || (prev->GetDepth() == cursor.par()->GetDepth()
798 && textclasslist.Style(bview->buffer()->params.textclass,
799 prev->GetLayout()).isEnvironment()))) {
801 cursor.par()->FirstPhysicalPar()->depth++;
803 cursor.par()->depth++;
805 anything_changed = true;
808 if (cursor.par() == sel_end_cursor.par())
810 cursor.par(cursor.par()->Next());
813 // if nothing changed set all depth to 0
814 if (!anything_changed) {
815 cursor = sel_start_cursor;
816 while (cursor.par() != sel_end_cursor.par()) {
818 cursor.par()->FirstPhysicalPar()->depth = 0;
820 cursor.par()->depth = 0;
822 cursor.par(cursor.par()->Next());
825 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
826 cursor.par()->FirstPhysicalPar()->depth = 0;
828 cursor.par()->depth = 0;
832 RedoParagraphs(bview, sel_start_cursor, endpar);
834 // we have to reset the selection, because the
835 // geometry could have changed
836 SetCursor(bview, sel_start_cursor.par(),
837 sel_start_cursor.pos());
839 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
840 UpdateCounters(bview, cursor.row());
843 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
847 // decrement depth over selection and
848 // make a total rebreak of those paragraphs
849 void LyXText::DecDepth(BufferView * bview)
851 // if there is no selection just set the layout
852 // of the current paragraph
854 sel_start_cursor = cursor; // dummy selection
855 sel_end_cursor = cursor;
858 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
860 LyXParagraph * endpar = sel_end_cursor.par()->Next();
862 LyXParagraph * undoendpar = endpar;
864 if (endpar && endpar->GetDepth()) {
865 while (endpar && endpar->GetDepth()) {
867 endpar = endpar->LastPhysicalPar()->Next();
869 endpar = endpar->Next();
875 endpar = endpar->Next(); // because of parindents etc.
878 SetUndo(bview->buffer(), Undo::EDIT,
880 .par()->ParFromPos(sel_start_cursor.pos())->previous,
883 LyXCursor tmpcursor = cursor; // store the current cursor
885 // ok we have a selection. This is always between sel_start_cursor
886 // and sel_end cursor
887 cursor = sel_start_cursor;
891 if (cursor.par()->footnoteflag ==
892 sel_start_cursor.par()->footnoteflag) {
893 if (cursor.par()->FirstPhysicalPar()->depth)
894 cursor.par()->FirstPhysicalPar()->depth--;
897 if (cursor.par()->depth)
898 cursor.par()->depth--;
900 if (cursor.par() == sel_end_cursor.par())
902 cursor.par(cursor.par()->Next());
905 RedoParagraphs(bview, sel_start_cursor, endpar);
907 // we have to reset the selection, because the
908 // geometry could have changed
909 SetCursor(bview, sel_start_cursor.par(),
910 sel_start_cursor.pos());
912 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
913 UpdateCounters(bview, cursor.row());
916 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
920 // set font over selection and make a total rebreak of those paragraphs
921 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
923 // if there is no selection just set the current_font
925 // Determine basis font
927 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
929 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
931 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
932 // Update current font
933 real_current_font.update(font,
934 bview->buffer()->params.language_info,
937 // Reduce to implicit settings
938 current_font = real_current_font;
939 current_font.reduce(layoutfont);
940 // And resolve it completely
941 real_current_font.realize(layoutfont);
945 LyXCursor tmpcursor = cursor; // store the current cursor
947 // ok we have a selection. This is always between sel_start_cursor
948 // and sel_end cursor
950 SetUndo(bview->buffer(), Undo::EDIT,
951 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
952 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
953 cursor = sel_start_cursor;
954 while (cursor.par() != sel_end_cursor.par() ||
957 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
959 cursor.pos() < sel_end_cursor.pos()))
961 if (cursor.pos() < cursor.par()->Last()
963 && cursor.par()->footnoteflag
964 == sel_start_cursor.par()->footnoteflag
967 // an open footnote should behave
969 LyXFont newfont = GetFont(bview->buffer(),
970 cursor.par(), cursor.pos());
972 bview->buffer()->params.language_info,
974 SetCharFont(bview->buffer(),
975 cursor.par(), cursor.pos(), newfont);
976 cursor.pos(cursor.pos() + 1);
979 cursor.par(cursor.par()->Next());
983 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
985 // we have to reset the selection, because the
986 // geometry could have changed
987 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
989 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
992 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
993 tmpcursor.boundary());
997 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
999 Row * tmprow = cur.row();
1000 long y = cur.y() - tmprow->baseline();
1002 SetHeightOfRow(bview, tmprow);
1004 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1006 LyXParagraph * first_phys_par = tmprow->par();
1008 // find the first row of the paragraph
1009 if (first_phys_par != tmprow->par())
1010 while (tmprow->previous()
1011 && tmprow->previous()->par() != first_phys_par) {
1012 tmprow = tmprow->previous();
1013 y -= tmprow->height();
1014 SetHeightOfRow(bview, tmprow);
1016 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1017 tmprow = tmprow->previous();
1018 y -= tmprow->height();
1019 SetHeightOfRow(bview, tmprow);
1022 // we can set the refreshing parameters now
1023 status = LyXText::NEED_MORE_REFRESH;
1025 refresh_row = tmprow;
1026 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
1030 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
1032 Row * tmprow = cur.row();
1034 long y = cur.y() - tmprow->baseline();
1035 SetHeightOfRow(bview, tmprow);
1037 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1039 LyXParagraph * first_phys_par = tmprow->par();
1041 // find the first row of the paragraph
1042 if (first_phys_par != tmprow->par())
1043 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
1044 tmprow = tmprow->previous();
1045 y -= tmprow->height();
1047 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1048 tmprow = tmprow->previous();
1049 y -= tmprow->height();
1052 // we can set the refreshing parameters now
1053 if (status == LyXText::UNCHANGED || y < refresh_y) {
1055 refresh_row = tmprow;
1057 status = LyXText::NEED_MORE_REFRESH;
1058 SetCursor(bview, cur.par(), cur.pos());
1062 /* deletes and inserts again all paragaphs between the cursor
1063 * and the specified par
1064 * This function is needed after SetLayout and SetFont etc. */
1065 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1066 LyXParagraph const * endpar) const
1069 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1071 Row * tmprow = cur.row();
1073 long y = cur.y() - tmprow->baseline();
1075 if (!tmprow->previous()){
1076 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1079 first_phys_par = tmprow->par()->FirstPhysicalPar();
1081 first_phys_par = tmprow->par();
1083 // find the first row of the paragraph
1084 if (first_phys_par != tmprow->par())
1085 while (tmprow->previous() &&
1086 (tmprow->previous()->par() != first_phys_par)) {
1087 tmprow = tmprow->previous();
1088 y -= tmprow->height();
1090 while (tmprow->previous()
1091 && tmprow->previous()->par() == first_phys_par) {
1092 tmprow = tmprow->previous();
1093 y -= tmprow->height();
1097 // we can set the refreshing parameters now
1098 status = LyXText::NEED_MORE_REFRESH;
1100 refresh_row = tmprow->previous(); /* the real refresh row will
1101 be deleted, so I store
1102 the previous here */
1105 tmppar = tmprow->next()->par();
1108 while (tmppar != endpar) {
1109 RemoveRow(tmprow->next());
1111 tmppar = tmprow->next()->par();
1116 // remove the first one
1117 tmprow2 = tmprow; /* this is because tmprow->previous()
1119 tmprow = tmprow->previous();
1122 tmppar = first_phys_par;
1126 InsertParagraph(bview, tmppar, tmprow);
1129 while (tmprow->next() && tmprow->next()->par() == tmppar)
1130 tmprow = tmprow->next();
1131 tmppar = tmppar->Next();
1133 } while (tmppar != endpar);
1135 // this is because of layout changes
1137 refresh_y -= refresh_row->height();
1138 SetHeightOfRow(bview, refresh_row);
1140 refresh_row = firstrow;
1142 SetHeightOfRow(bview, refresh_row);
1145 if (tmprow && tmprow->next())
1146 SetHeightOfRow(bview, tmprow->next());
1150 bool LyXText::FullRebreak(BufferView * bview)
1156 if (need_break_row) {
1157 BreakAgain(bview, need_break_row);
1165 /* important for the screen */
1168 /* the cursor set functions have a special mechanism. When they
1169 * realize, that you left an empty paragraph, they will delete it.
1170 * They also delete the corresponding row */
1172 // need the selection cursor:
1173 void LyXText::SetSelection()
1176 last_sel_cursor = sel_cursor;
1177 sel_start_cursor = sel_cursor;
1178 sel_end_cursor = sel_cursor;
1183 // first the toggling area
1184 if (cursor.y() < last_sel_cursor.y()
1185 || (cursor.y() == last_sel_cursor.y()
1186 && cursor.x() < last_sel_cursor.x())) {
1187 toggle_end_cursor = last_sel_cursor;
1188 toggle_cursor = cursor;
1190 toggle_end_cursor = cursor;
1191 toggle_cursor = last_sel_cursor;
1194 last_sel_cursor = cursor;
1196 // and now the whole selection
1198 if (sel_cursor.par() == cursor.par())
1199 if (sel_cursor.pos() < cursor.pos()) {
1200 sel_end_cursor = cursor;
1201 sel_start_cursor = sel_cursor;
1203 sel_end_cursor = sel_cursor;
1204 sel_start_cursor = cursor;
1206 else if (sel_cursor.y() < cursor.y() ||
1207 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1208 sel_end_cursor = cursor;
1209 sel_start_cursor = sel_cursor;
1212 sel_end_cursor = sel_cursor;
1213 sel_start_cursor = cursor;
1216 // a selection with no contents is not a selection
1217 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1218 sel_start_cursor.pos() == sel_end_cursor.pos())
1223 string LyXText::selectionAsString(Buffer const * buffer) const
1225 if (!selection) return string();
1228 // Special handling if the whole selection is within one paragraph
1229 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1230 result += sel_start_cursor.par()->String(buffer,
1231 sel_start_cursor.pos(),
1232 sel_end_cursor.pos());
1236 // The selection spans more than one paragraph
1238 // First paragraph in selection
1239 result += sel_start_cursor.par()->String(buffer,
1240 sel_start_cursor.pos(),
1241 sel_start_cursor.par()->Last())
1244 // The paragraphs in between (if any)
1245 LyXCursor tmpcur(sel_start_cursor);
1246 tmpcur.par(tmpcur.par()->Next());
1247 while (tmpcur.par() != sel_end_cursor.par()) {
1248 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1249 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1252 // Last paragraph in selection
1253 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1259 void LyXText::ClearSelection() const
1266 void LyXText::CursorHome(BufferView * bview) const
1268 SetCursor(bview, cursor.par(), cursor.row()->pos());
1272 void LyXText::CursorEnd(BufferView * bview) const
1274 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1275 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1277 if (cursor.par()->Last() &&
1278 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1279 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1280 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1282 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1285 if (cursor.par()->table) {
1286 int cell = NumberOfCell(cursor.par(), cursor.pos());
1287 if (cursor.par()->table->RowHasContRow(cell) &&
1288 cursor.par()->table->CellHasContRow(cell)<0) {
1289 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1290 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1292 if (cursor.par()->Last() &&
1293 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1294 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1295 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1297 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1305 void LyXText::CursorTop(BufferView * bview) const
1307 while (cursor.par()->Previous())
1308 cursor.par(cursor.par()->Previous());
1309 SetCursor(bview, cursor.par(), 0);
1313 void LyXText::CursorBottom(BufferView * bview) const
1315 while (cursor.par()->Next())
1316 cursor.par(cursor.par()->Next());
1317 SetCursor(bview, cursor.par(), cursor.par()->Last());
1321 /* returns a pointer to the row near the specified y-coordinate
1322 * (relative to the whole text). y is set to the real beginning
1324 Row * LyXText::GetRowNearY(long & y) const
1326 Row * tmprow = firstrow;
1329 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1330 tmpy += tmprow->height();
1331 tmprow = tmprow->next();
1334 y = tmpy; // return the real y
1339 void LyXText::ToggleFree(BufferView * bview,
1340 LyXFont const & font, bool toggleall)
1342 // If the mask is completely neutral, tell user
1343 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1344 // Could only happen with user style
1345 bview->owner()->getMiniBuffer()
1346 ->Set(_("No font change defined. Use Character under"
1347 " the Layout menu to define font change."));
1351 // Try implicit word selection
1352 // If there is a change in the language the implicit word selection
1354 LyXCursor resetCursor = cursor;
1355 bool implicitSelection = (font.language() == ignore_language)
1356 ? SelectWordWhenUnderCursor(bview) : false;
1359 SetFont(bview, font, toggleall);
1361 /* Implicit selections are cleared afterwards and cursor is set to the
1362 original position. */
1363 if (implicitSelection) {
1365 cursor = resetCursor;
1366 SetCursor(bview, cursor.par(), cursor.pos());
1367 sel_cursor = cursor;
1372 LyXParagraph::size_type
1373 LyXText::BeginningOfMainBody(Buffer const * buf,
1374 LyXParagraph const * par) const
1376 if (textclasslist.Style(buf->params.textclass,
1377 par->GetLayout()).labeltype != LABEL_MANUAL)
1380 return par->BeginningOfMainBody();
1385 /* if there is a selection, reset every environment you can find
1386 * in the selection, otherwise just the environment you are in */
1387 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1389 LyXParagraph * tmppar, * firsttmppar;
1393 /* is is only allowed, if the cursor is IN an open footnote.
1394 * Otherwise it is too dangerous */
1395 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1398 SetUndo(bview->buffer(), Undo::FINISH,
1399 cursor.par()->PreviousBeforeFootnote()->previous,
1400 cursor.par()->NextAfterFootnote()->next);
1402 /* ok, move to the beginning of the footnote. */
1403 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1404 cursor.par(cursor.par()->Previous());
1406 SetCursor(bview, cursor.par(), cursor.par()->Last());
1407 /* this is just faster than using CursorLeft(); */
1409 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1410 tmppar = firsttmppar;
1411 /* tmppar is now the paragraph right before the footnote */
1413 bool first_footnote_par_is_not_empty = tmppar->next->size();
1416 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1417 tmppar = tmppar->next; /* I use next instead of Next(),
1418 * because there cannot be any
1419 * footnotes in a footnote
1421 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1423 /* remember the captions and empty paragraphs */
1424 if ((textclasslist.Style(bview->buffer()->params.textclass,
1425 tmppar->GetLayout())
1426 .labeltype == LABEL_SENSITIVE)
1428 tmppar->SetLayout(bview->buffer()->params, 0);
1431 // now we will paste the ex-footnote, if the layouts allow it
1432 // first restore the layout of the paragraph right behind
1435 tmppar->next->MakeSameLayout(cursor.par());
1438 if ((!tmppar->GetLayout() && !tmppar->table)
1440 && (!tmppar->Next()->Last()
1441 || tmppar->Next()->HasSameLayout(tmppar)))) {
1442 if (tmppar->Next()->Last()
1443 && tmppar->Next()->IsLineSeparator(0))
1444 tmppar->Next()->Erase(0);
1445 tmppar->PasteParagraph(bview->buffer()->params);
1448 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1449 * by the pasting of the beginning */
1451 /* then the beginning */
1452 /* if there is no space between the text and the footnote, so we insert
1454 * (only if the previous par and the footnotepar are not empty!) */
1455 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1456 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1457 if (firsttmppar->size()
1458 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1459 && first_footnote_par_is_not_empty) {
1460 firsttmppar->next->InsertChar(0, ' ');
1462 firsttmppar->PasteParagraph(bview->buffer()->params);
1465 /* now redo the paragaphs */
1466 RedoParagraphs(bview, cursor, tmppar);
1468 SetCursor(bview, cursor.par(), cursor.pos());
1470 /* sometimes it can happen, that there is a counter change */
1471 Row * row = cursor.row();
1472 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1474 UpdateCounters(bview, row);
1482 /* the DTP switches for paragraphs. LyX will store them in the
1483 * first physicla paragraph. When a paragraph is broken, the top settings
1484 * rest, the bottom settings are given to the new one. So I can make shure,
1485 * they do not duplicate themself and you cannnot make dirty things with
1488 void LyXText::SetParagraph(BufferView * bview,
1489 bool line_top, bool line_bottom,
1490 bool pagebreak_top, bool pagebreak_bottom,
1491 VSpace const & space_top,
1492 VSpace const & space_bottom,
1494 string labelwidthstring,
1497 LyXCursor tmpcursor = cursor;
1499 sel_start_cursor = cursor;
1500 sel_end_cursor = cursor;
1503 // make sure that the depth behind the selection are restored, too
1505 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1507 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1509 LyXParagraph * undoendpar = endpar;
1511 if (endpar && endpar->GetDepth()) {
1512 while (endpar && endpar->GetDepth()) {
1514 endpar = endpar->LastPhysicalPar()->Next();
1516 endpar = endpar->Next();
1518 undoendpar = endpar;
1522 endpar = endpar->Next(); // because of parindents etc.
1525 SetUndo(bview->buffer(), Undo::EDIT,
1527 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1531 LyXParagraph * tmppar = sel_end_cursor.par();
1533 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1534 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1536 while (tmppar != sel_start_cursor.par()->Previous()) {
1537 SetCursor(bview, tmppar, 0);
1539 status = LyXText::NEED_MORE_REFRESH;
1540 refresh_row = cursor.row();
1541 refresh_y = cursor.y() - cursor.row()->baseline();
1543 if (cursor.par()->footnoteflag ==
1544 sel_start_cursor.par()->footnoteflag) {
1546 cursor.par()->line_top = line_top;
1547 cursor.par()->line_bottom = line_bottom;
1548 cursor.par()->pagebreak_top = pagebreak_top;
1549 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1550 cursor.par()->added_space_top = space_top;
1551 cursor.par()->added_space_bottom = space_bottom;
1552 // does the layout allow the new alignment?
1553 if (align == LYX_ALIGN_LAYOUT)
1554 align = textclasslist
1555 .Style(bview->buffer()->params.textclass,
1556 cursor.par()->GetLayout()).align;
1557 if (align & textclasslist
1558 .Style(bview->buffer()->params.textclass,
1559 cursor.par()->GetLayout()).alignpossible) {
1560 if (align == textclasslist
1561 .Style(bview->buffer()->params.textclass,
1562 cursor.par()->GetLayout()).align)
1563 cursor.par()->align = LYX_ALIGN_LAYOUT;
1565 cursor.par()->align = align;
1567 cursor.par()->SetLabelWidthString(labelwidthstring);
1568 cursor.par()->noindent = noindent;
1572 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1574 tmppar = cursor.par()->Previous();
1578 RedoParagraphs(bview, sel_start_cursor, endpar);
1581 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1582 sel_cursor = cursor;
1583 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1585 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1589 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1591 char const * widthp,
1592 int alignment, bool hfill,
1593 bool start_minipage)
1595 LyXCursor tmpcursor = cursor;
1596 LyXParagraph * tmppar;
1598 sel_start_cursor = cursor;
1599 sel_end_cursor = cursor;
1602 // make sure that the depth behind the selection are restored, too
1604 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1606 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1608 LyXParagraph * undoendpar = endpar;
1610 if (endpar && endpar->GetDepth()) {
1611 while (endpar && endpar->GetDepth()) {
1613 endpar = endpar->LastPhysicalPar()->Next();
1615 endpar = endpar->Next();
1617 undoendpar = endpar;
1621 endpar = endpar->Next(); // because of parindents etc.
1624 SetUndo(bview->buffer(), Undo::EDIT,
1626 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1629 tmppar = sel_end_cursor.par();
1631 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1632 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1634 while(tmppar != sel_start_cursor.par()->Previous()) {
1635 SetCursor(bview, tmppar, 0);
1637 status = LyXText::NEED_MORE_REFRESH;
1638 refresh_row = cursor.row();
1639 refresh_y = cursor.y() - cursor.row()->baseline();
1641 if (cursor.par()->footnoteflag ==
1642 sel_start_cursor.par()->footnoteflag) {
1644 if (type == LyXParagraph::PEXTRA_NONE) {
1645 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1646 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1647 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1650 cursor.par()->SetPExtraType(bview->buffer()->params,
1651 type, width, widthp);
1652 cursor.par()->pextra_hfill = hfill;
1653 cursor.par()->pextra_start_minipage = start_minipage;
1654 cursor.par()->pextra_alignment = alignment;
1658 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1660 tmppar = cursor.par()->Previous();
1663 RedoParagraphs(bview, sel_start_cursor, endpar);
1665 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1666 sel_cursor = cursor;
1667 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1669 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1673 char loweralphaCounter(int n)
1675 if (n < 1 || n > 26)
1682 char alphaCounter(int n)
1684 if (n < 1 || n > 26)
1691 char hebrewCounter(int n)
1693 static const char hebrew[22] = {
1694 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1695 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1696 '÷', 'ø', 'ù', 'ú'
1698 if (n < 1 || n > 22)
1706 char const * romanCounter(int n)
1708 static char const * roman[20] = {
1709 "i", "ii", "iii", "iv", "v",
1710 "vi", "vii", "viii", "ix", "x",
1711 "xi", "xii", "xiii", "xiv", "xv",
1712 "xvi", "xvii", "xviii", "xix", "xx"
1714 if (n < 1 || n > 20)
1721 // set the counter of a paragraph. This includes the labels
1722 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1725 // this is only relevant for the beginning of paragraph
1726 par = par->FirstPhysicalPar();
1728 LyXLayout const & layout =
1729 textclasslist.Style(buf->params.textclass,
1732 LyXTextClass const & textclass =
1733 textclasslist.TextClass(buf->params.textclass);
1735 /* copy the prev-counters to this one, unless this is the start of a
1736 footnote or of a bibliography or the very first paragraph */
1739 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1740 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1741 && par->footnotekind == LyXParagraph::FOOTNOTE)
1743 && !(textclasslist.Style(buf->params.textclass,
1744 par->Previous()->GetLayout()
1745 ).labeltype != LABEL_BIBLIO
1746 && layout.labeltype == LABEL_BIBLIO)) {
1747 for (int i = 0; i < 10; ++i) {
1748 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1751 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1753 par->appendix = par->Previous()->appendix;
1755 if (!par->appendix && par->start_of_appendix){
1756 par->appendix = true;
1757 for (int i = 0; i < 10; ++i) {
1758 par->setCounter(i, 0);
1762 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1763 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1765 par->enumdepth = par->Previous()->enumdepth;
1766 par->itemdepth = par->Previous()->itemdepth;
1769 for (int i = 0; i < 10; ++i) {
1770 par->setCounter(i, 0);
1772 par->appendix = par->start_of_appendix;
1778 // if this is an open marginnote and this is the first
1779 // entry in the marginnote and the enclosing
1780 // environment is an enum/item then correct for the
1781 // LaTeX behaviour (ARRae)
1782 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1783 && par->footnotekind == LyXParagraph::MARGIN
1785 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1786 && (par->PreviousBeforeFootnote()
1787 && textclasslist.Style(buf->params.textclass,
1788 par->PreviousBeforeFootnote()->GetLayout()
1789 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1790 // Any itemize or enumerate environment in a marginnote
1791 // that is embedded in an itemize or enumerate
1792 // paragraph is seen by LaTeX as being at a deeper
1793 // level within that enclosing itemization/enumeration
1794 // even if there is a "standard" layout at the start of
1800 /* Maybe we have to increment the enumeration depth.
1801 * BUT, enumeration in a footnote is considered in isolation from its
1802 * surrounding paragraph so don't increment if this is the
1803 * first line of the footnote
1804 * AND, bibliographies can't have their depth changed ie. they
1805 * are always of depth 0
1808 && par->Previous()->GetDepth() < par->GetDepth()
1809 && textclasslist.Style(buf->params.textclass,
1810 par->Previous()->GetLayout()
1811 ).labeltype == LABEL_COUNTER_ENUMI
1812 && par->enumdepth < 3
1814 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1815 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1816 && par->footnotekind == LyXParagraph::FOOTNOTE)
1818 && layout.labeltype != LABEL_BIBLIO) {
1822 /* Maybe we have to decrement the enumeration depth, see note above */
1824 && par->Previous()->GetDepth() > par->GetDepth()
1826 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1827 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1828 && par->footnotekind == LyXParagraph::FOOTNOTE)
1830 && layout.labeltype != LABEL_BIBLIO) {
1831 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1832 par->setCounter(6 + par->enumdepth,
1833 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1834 /* reset the counters.
1835 * A depth change is like a breaking layout
1837 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1838 par->setCounter(i, 0);
1841 if (!par->labelstring.empty()) {
1842 par->labelstring.erase();
1845 if (layout.margintype == MARGIN_MANUAL) {
1846 if (par->labelwidthstring.empty()) {
1847 par->SetLabelWidthString(layout.labelstring());
1850 par->SetLabelWidthString(string());
1853 /* is it a layout that has an automatic label ? */
1854 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1856 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1857 if (i >= 0 && i<= buf->params.secnumdepth) {
1858 par->incCounter(i); // increment the counter
1860 // Is there a label? Useful for Chapter layout
1861 if (!par->appendix){
1862 if (!layout.labelstring().empty())
1863 par->labelstring = layout.labelstring();
1865 par->labelstring.erase();
1867 if (!layout.labelstring_appendix().empty())
1868 par->labelstring = layout.labelstring_appendix();
1870 par->labelstring.erase();
1874 std::ostringstream s;
1878 if (!par->appendix) {
1879 switch (2 * LABEL_COUNTER_CHAPTER -
1880 textclass.maxcounter() + i) {
1881 case LABEL_COUNTER_CHAPTER:
1882 s << par->getCounter(i);
1884 case LABEL_COUNTER_SECTION:
1885 s << par->getCounter(i - 1) << '.'
1886 << par->getCounter(i);
1888 case LABEL_COUNTER_SUBSECTION:
1889 s << par->getCounter(i - 2) << '.'
1890 << par->getCounter(i - 1) << '.'
1891 << par->getCounter(i);
1893 case LABEL_COUNTER_SUBSUBSECTION:
1894 s << par->getCounter(i - 3) << '.'
1895 << par->getCounter(i - 2) << '.'
1896 << par->getCounter(i - 1) << '.'
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_PARAGRAPH:
1901 s << par->getCounter(i - 4) << '.'
1902 << par->getCounter(i - 3) << '.'
1903 << par->getCounter(i - 2) << '.'
1904 << par->getCounter(i - 1) << '.'
1905 << par->getCounter(i);
1907 case LABEL_COUNTER_SUBPARAGRAPH:
1908 s << par->getCounter(i - 5) << '.'
1909 << par->getCounter(i - 4) << '.'
1910 << par->getCounter(i - 3) << '.'
1911 << par->getCounter(i - 2) << '.'
1912 << par->getCounter(i - 1) << '.'
1913 << par->getCounter(i);
1917 // Can this ever be reached? And in the
1918 // case it is, how can this be correct?
1920 s << par->getCounter(i) << '.';
1923 } else { // appendix
1924 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1925 case LABEL_COUNTER_CHAPTER:
1926 if (par->isRightToLeftPar(buf->params))
1927 s << hebrewCounter(par->getCounter(i));
1929 s << alphaCounter(par->getCounter(i));
1931 case LABEL_COUNTER_SECTION:
1932 if (par->isRightToLeftPar(buf->params))
1933 s << hebrewCounter(par->getCounter(i - 1));
1935 s << alphaCounter(par->getCounter(i - 1));
1938 << par->getCounter(i);
1941 case LABEL_COUNTER_SUBSECTION:
1942 if (par->isRightToLeftPar(buf->params))
1943 s << hebrewCounter(par->getCounter(i - 2));
1945 s << alphaCounter(par->getCounter(i - 2));
1948 << par->getCounter(i-1) << '.'
1949 << par->getCounter(i);
1952 case LABEL_COUNTER_SUBSUBSECTION:
1953 if (par->isRightToLeftPar(buf->params))
1954 s << hebrewCounter(par->getCounter(i-3));
1956 s << alphaCounter(par->getCounter(i-3));
1959 << par->getCounter(i-2) << '.'
1960 << par->getCounter(i-1) << '.'
1961 << par->getCounter(i);
1964 case LABEL_COUNTER_PARAGRAPH:
1965 if (par->isRightToLeftPar(buf->params))
1966 s << hebrewCounter(par->getCounter(i-4));
1968 s << alphaCounter(par->getCounter(i-4));
1971 << par->getCounter(i-3) << '.'
1972 << par->getCounter(i-2) << '.'
1973 << par->getCounter(i-1) << '.'
1974 << par->getCounter(i);
1977 case LABEL_COUNTER_SUBPARAGRAPH:
1978 if (par->isRightToLeftPar(buf->params))
1979 s << hebrewCounter(par->getCounter(i-5));
1981 s << alphaCounter(par->getCounter(i-5));
1984 << par->getCounter(i-4) << '.'
1985 << par->getCounter(i-3) << '.'
1986 << par->getCounter(i-2) << '.'
1987 << par->getCounter(i-1) << '.'
1988 << par->getCounter(i);
1992 // Can this ever be reached? And in the
1993 // case it is, how can this be correct?
1995 s << par->getCounter(i) << '.';
2001 par->labelstring += s.str().c_str();
2002 // We really want to remove the c_str as soon as
2006 char * tmps = s.str();
2007 par->labelstring += tmps;
2011 for (i++; i < 10; ++i) {
2012 // reset the following counters
2013 par->setCounter(i, 0);
2015 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2016 for (i++; i < 10; ++i) {
2017 // reset the following counters
2018 par->setCounter(i, 0);
2020 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2021 par->incCounter(i + par->enumdepth);
2022 int number = par->getCounter(i + par->enumdepth);
2025 std::ostringstream s;
2029 switch (par->enumdepth) {
2031 if (par->isRightToLeftPar(buf->params))
2033 << hebrewCounter(number)
2037 << loweralphaCounter(number)
2041 if (par->isRightToLeftPar(buf->params))
2042 s << '.' << romanCounter(number);
2044 s << romanCounter(number) << '.';
2047 if (par->isRightToLeftPar(buf->params))
2049 << alphaCounter(number);
2051 s << alphaCounter(number)
2055 if (par->isRightToLeftPar(buf->params))
2062 par->labelstring = s.str().c_str();
2063 // we really want to get rid of that c_str()
2066 char * tmps = s.str();
2067 par->labelstring = tmps;
2071 for (i += par->enumdepth + 1; i < 10; ++i)
2072 par->setCounter(i, 0); /* reset the following counters */
2075 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2076 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2078 int number = par->getCounter(i);
2080 par->bibkey = new InsetBibKey();
2081 par->bibkey->setCounter(number);
2082 par->labelstring = layout.labelstring();
2084 // In biblio should't be following counters but...
2086 string s = layout.labelstring();
2088 // the caption hack:
2089 if (layout.labeltype == LABEL_SENSITIVE) {
2090 bool isOK (par->InInset() && par->InInset()->owner() &&
2091 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2093 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2094 && (par->footnotekind == LyXParagraph::FIG
2095 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2096 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2097 ? ":øåéà " : "Figure:";
2098 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2099 && (par->footnotekind == LyXParagraph::TAB
2100 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2101 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2102 ? ":äìáè" : "Table:";
2103 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2104 && par->footnotekind == LyXParagraph::ALGORITHM) {
2105 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2106 ? ":Ãúéøåâìà " : "Algorithm:";
2110 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2112 = floatList.getType(tmp->type());
2113 // We should get the correct number here too.
2114 s = fl.name + " #:";
2116 /* par->SetLayout(0);
2117 s = layout->labelstring; */
2118 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2119 ? " :úåòîùî øñç" : "Senseless: ";
2122 par->labelstring = s;
2124 /* reset the enumeration counter. They are always resetted
2125 * when there is any other layout between */
2126 for (int i = 6 + par->enumdepth; i < 10; ++i)
2127 par->setCounter(i, 0);
2132 /* Updates all counters BEHIND the row. Changed paragraphs
2133 * with a dynamic left margin will be rebroken. */
2134 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2141 if (row->par()->next
2143 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2147 par = row->par()->LastPhysicalPar()->Next();
2149 par = row->par()->Next();
2152 par = row->par()->next;
2157 while (row->par() != par)
2160 SetCounter(bview->buffer(), par);
2162 /* now check for the headline layouts. remember that they
2163 * have a dynamic left margin */
2168 ( textclasslist.Style(bview->buffer()->params.textclass,
2169 par->layout).margintype == MARGIN_DYNAMIC
2170 || textclasslist.Style(bview->buffer()->params.textclass,
2171 par->layout).labeltype == LABEL_SENSITIVE)
2174 /* Rebreak the paragraph */
2175 RemoveParagraph(row);
2176 AppendParagraph(bview, row);
2179 /* think about the damned open footnotes! */
2180 while (par->Next() &&
2181 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2182 || par->Next()->IsDummy())){
2184 if (par->IsDummy()) {
2185 while (row->par() != par)
2187 RemoveParagraph(row);
2188 AppendParagraph(bview, row);
2194 par = par->LastPhysicalPar()->Next();
2203 /* insets an inset. */
2204 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2206 if (!cursor.par()->InsertInsetAllowed(inset))
2208 SetUndo(bview->buffer(), Undo::INSERT,
2209 cursor.par()->ParFromPos(cursor.pos())->previous,
2210 cursor.par()->ParFromPos(cursor.pos())->next);
2211 cursor.par()->InsertInset(cursor.pos(), inset);
2212 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2213 * The character will not be inserted a
2218 void LyXText::copyEnvironmentType()
2220 copylayouttype = cursor.par()->GetLayout();
2224 void LyXText::pasteEnvironmentType(BufferView * bview)
2226 SetLayout(bview, copylayouttype);
2230 void LyXText::CutSelection(BufferView * bview, bool doclear)
2232 // Stuff what we got on the clipboard. Even if there is no selection.
2234 // There is a problem with having the stuffing here in that the
2235 // larger the selection the slower LyX will get. This can be
2236 // solved by running the line below only when the selection has
2237 // finished. The solution used currently just works, to make it
2238 // faster we need to be more clever and probably also have more
2239 // calls to stuffClipboard. (Lgb)
2240 bview->stuffClipboard(selectionAsString(bview->buffer()));
2242 // This doesn't make sense, if there is no selection
2246 // OK, we have a selection. This is always between sel_start_cursor
2247 // and sel_end cursor
2249 // Check whether there are half footnotes in the selection
2250 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2251 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2252 LyXParagraph * tmppar = sel_start_cursor.par();
2253 while (tmppar != sel_end_cursor.par()){
2254 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2255 WriteAlert(_("Impossible operation"),
2256 _("Don't know what to do with half floats."),
2260 tmppar = tmppar->Next();
2265 /* table stuff -- begin */
2266 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2267 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2268 WriteAlert(_("Impossible operation"),
2269 _("Don't know what to do with half tables."),
2273 sel_start_cursor.par()->table->Reinit();
2275 /* table stuff -- end */
2277 // make sure that the depth behind the selection are restored, too
2279 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2281 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2283 LyXParagraph * undoendpar = endpar;
2285 if (endpar && endpar->GetDepth()) {
2286 while (endpar && endpar->GetDepth()) {
2288 endpar = endpar->LastPhysicalPar()->Next();
2290 endpar = endpar->Next();
2292 undoendpar = endpar;
2294 } else if (endpar) {
2295 endpar = endpar->Next(); // because of parindents etc.
2298 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2299 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2304 // there are two cases: cut only within one paragraph or
2305 // more than one paragraph
2306 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2307 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2308 // only within one paragraph
2309 endpar = sel_start_cursor.par();
2310 int pos = sel_end_cursor.pos();
2311 cap.cutSelection(sel_start_cursor.par(), &endpar,
2312 sel_start_cursor.pos(), pos,
2313 bview->buffer()->params.textclass, doclear);
2314 sel_end_cursor.pos(pos);
2316 endpar = sel_end_cursor.par();
2318 int pos = sel_end_cursor.pos();
2319 cap.cutSelection(sel_start_cursor.par(), &endpar,
2320 sel_start_cursor.pos(), pos,
2321 bview->buffer()->params.textclass, doclear);
2323 sel_end_cursor.par(endpar);
2324 sel_end_cursor.pos(pos);
2325 cursor.pos(sel_end_cursor.pos());
2327 endpar = endpar->Next();
2329 // sometimes necessary
2331 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2333 RedoParagraphs(bview, sel_start_cursor, endpar);
2336 cursor = sel_start_cursor;
2337 SetCursor(bview, cursor.par(), cursor.pos());
2338 sel_cursor = cursor;
2339 UpdateCounters(bview, cursor.row());
2343 void LyXText::CopySelection(BufferView * bview)
2345 // Stuff what we got on the clipboard. Even if there is no selection.
2347 // There is a problem with having the stuffing here in that the
2348 // larger the selection the slower LyX will get. This can be
2349 // solved by running the line below only when the selection has
2350 // finished. The solution used currently just works, to make it
2351 // faster we need to be more clever and probably also have more
2352 // calls to stuffClipboard. (Lgb)
2353 bview->stuffClipboard(selectionAsString(bview->buffer()));
2355 // this doesnt make sense, if there is no selection
2359 // ok we have a selection. This is always between sel_start_cursor
2360 // and sel_end cursor
2363 /* check wether there are half footnotes in the selection */
2364 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2365 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2366 LyXParagraph * tmppar = sel_start_cursor.par();
2367 while (tmppar != sel_end_cursor.par()) {
2368 if (tmppar->footnoteflag !=
2369 sel_end_cursor.par()->footnoteflag) {
2370 WriteAlert(_("Impossible operation"),
2371 _("Don't know what to do"
2372 " with half floats."),
2376 tmppar = tmppar->Next();
2381 /* table stuff -- begin */
2382 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2383 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2384 WriteAlert(_("Impossible operation"),
2385 _("Don't know what to do with half tables."),
2390 /* table stuff -- end */
2393 // copy behind a space if there is one
2394 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2395 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2396 && (sel_start_cursor.par() != sel_end_cursor.par()
2397 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2398 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2402 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2403 sel_start_cursor.pos(), sel_end_cursor.pos(),
2404 bview->buffer()->params.textclass);
2408 void LyXText::PasteSelection(BufferView * bview)
2412 // this does not make sense, if there is nothing to paste
2413 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2416 SetUndo(bview->buffer(), Undo::INSERT,
2417 cursor.par()->ParFromPos(cursor.pos())->previous,
2418 cursor.par()->ParFromPos(cursor.pos())->next);
2420 LyXParagraph * endpar;
2421 LyXParagraph * actpar = cursor.par();
2423 int pos = cursor.pos();
2424 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2426 RedoParagraphs(bview, cursor, endpar);
2428 SetCursor(bview, cursor.par(), cursor.pos());
2431 sel_cursor = cursor;
2432 SetCursor(bview, actpar, pos);
2434 UpdateCounters(bview, cursor.row());
2438 // returns a pointer to the very first LyXParagraph
2439 LyXParagraph * LyXText::FirstParagraph() const
2441 return OwnerParagraph();
2445 // returns true if the specified string is at the specified position
2446 bool LyXText::IsStringInText(LyXParagraph * par,
2447 LyXParagraph::size_type pos,
2448 char const * str) const
2452 while (pos + i < par->Last() && str[i] &&
2453 str[i] == par->GetChar(pos + i)) {
2463 // sets the selection over the number of characters of string, no check!!
2464 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2466 sel_cursor = cursor;
2467 for (int i = 0; string[i]; ++i)
2473 // simple replacing. The font of the first selected character is used
2474 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2476 SetCursorParUndo(bview->buffer());
2479 if (!selection) { // create a dummy selection
2480 sel_end_cursor = cursor;
2481 sel_start_cursor = cursor;
2484 // Get font setting before we cut
2485 LyXParagraph::size_type pos = sel_end_cursor.pos();
2486 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2487 sel_start_cursor.pos());
2489 // Insert the new string
2490 for (int i = 0; str[i]; ++i) {
2491 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2495 // Cut the selection
2496 CutSelection(bview);
2502 // if the string can be found: return true and set the cursor to
2504 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2506 LyXParagraph * par = cursor.par();
2507 LyXParagraph::size_type pos = cursor.pos();
2508 while (par && !IsStringInText(par, pos, str)) {
2509 if (pos < par->Last() - 1)
2517 SetCursor(bview, par, pos);
2525 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2527 LyXParagraph * par = cursor.par();
2528 int pos = cursor.pos();
2534 // We skip empty paragraphs (Asger)
2536 par = par->Previous();
2538 pos = par->Last() - 1;
2539 } while (par && pos < 0);
2541 } while (par && !IsStringInText(par, pos, string));
2544 SetCursor(bview, par, pos);
2551 // needed to insert the selection
2552 void LyXText::InsertStringA(BufferView * bview, string const & str)
2554 LyXParagraph * par = cursor.par();
2555 LyXParagraph::size_type pos = cursor.pos();
2556 LyXParagraph::size_type a = 0;
2558 LyXParagraph * endpar = cursor.par()->Next();
2560 SetCursorParUndo(bview->buffer());
2563 textclasslist.Style(bview->buffer()->params.textclass,
2564 cursor.par()->GetLayout()).isEnvironment();
2565 // only to be sure, should not be neccessary
2568 // insert the string, don't insert doublespace
2569 string::size_type i = 0;
2570 while (i < str.length()) {
2571 if (str[i] != '\n') {
2573 && i + 1 < str.length() && str[i + 1] != ' '
2574 && pos && par->GetChar(pos - 1)!= ' ') {
2575 par->InsertChar(pos, ' ', current_font);
2578 } else if (par->table) {
2579 if (str[i] == '\t') {
2580 while((pos < par->size()) &&
2581 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2583 if (pos < par->size())
2585 else // no more fields to fill skip the rest
2587 } else if ((str[i] != 13) &&
2588 ((str[i] & 127) >= ' ')) {
2589 par->InsertChar(pos, str[i],
2594 } else if (str[i] == ' ') {
2595 InsetSpecialChar * new_inset =
2596 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2597 if (par->InsertInsetAllowed(new_inset)) {
2598 par->InsertInset(pos, new_inset,
2604 } else if (str[i] == '\t') {
2605 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2606 InsetSpecialChar * new_inset =
2607 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2608 if (par->InsertInsetAllowed(new_inset)) {
2609 par->InsertInset(pos, new_inset,
2616 } else if (str[i] != 13 &&
2617 // Ignore unprintables
2618 (str[i] & 127) >= ' ') {
2619 par->InsertChar(pos, str[i], current_font);
2625 if ((i + 1) >= str.length()) {
2626 if (pos < par->size())
2630 while((pos < par->size()) &&
2631 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2634 cell = NumberOfCell(par, pos);
2635 while((pos < par->size()) &&
2636 !(par->table->IsFirstCell(cell))) {
2638 while((pos < par->size()) &&
2639 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2642 cell = NumberOfCell(par, pos);
2644 if (pos >= par->size())
2645 // no more fields to fill skip the rest
2649 if (!par->size()) { // par is empty
2650 InsetSpecialChar * new_inset =
2651 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2652 if (par->InsertInsetAllowed(new_inset)) {
2653 par->InsertInset(pos,
2661 par->BreakParagraph(bview->buffer()->params, pos, flag);
2671 RedoParagraphs(bview, cursor, endpar);
2672 SetCursor(bview, cursor.par(), cursor.pos());
2673 sel_cursor = cursor;
2674 SetCursor(bview, par, pos);
2679 /* turns double-CR to single CR, others where converted into one blank and 13s
2680 * that are ignored .Double spaces are also converted into one. Spaces at
2681 * the beginning of a paragraph are forbidden. tabs are converted into one
2682 * space. then InsertStringA is called */
2683 void LyXText::InsertStringB(BufferView * bview, string const & s)
2686 LyXParagraph * par = cursor.par();
2687 string::size_type i = 1;
2688 while (i < str.length()) {
2689 if (str[i] == '\t' && !par->table)
2691 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2693 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2694 if (str[i + 1] != '\n') {
2695 if (str[i - 1] != ' ')
2700 while (i + 1 < str.length()
2701 && (str[i + 1] == ' '
2702 || str[i + 1] == '\t'
2703 || str[i + 1] == '\n'
2704 || str[i + 1] == 13)) {
2711 InsertStringA(bview, str);
2715 bool LyXText::GotoNextError(BufferView * bview) const
2717 LyXCursor res = cursor;
2719 if (res.pos() < res.par()->Last() - 1) {
2720 res.pos(res.pos() + 1);
2722 res.par(res.par()->Next());
2726 } while (res.par() &&
2727 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2728 && res.par()->GetInset(res.pos())->AutoDelete()));
2731 SetCursor(bview, res.par(), res.pos());
2738 bool LyXText::GotoNextNote(BufferView * bview) const
2740 LyXCursor res = cursor;
2742 if (res.pos() < res.par()->Last() - 1) {
2743 res.pos(res.pos() + 1);
2745 res.par(res.par()->Next());
2749 } while (res.par() &&
2750 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2751 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2754 SetCursor(bview, res.par(), res.pos());
2761 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2762 LyXParagraph::size_type pos)
2764 LyXCursor tmpcursor;
2767 /* table stuff -- begin*/
2770 CheckParagraphInTable(bview, par, pos);
2774 /* table stuff -- end*/
2777 LyXParagraph::size_type z;
2778 Row * row = GetRow(par, pos, y);
2780 // is there a break one row above
2781 if (row->previous() && row->previous()->par() == row->par()) {
2782 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2783 if ( z >= row->pos()) {
2784 // set the dimensions of the row above
2785 y -= row->previous()->height();
2787 refresh_row = row->previous();
2788 status = LyXText::NEED_MORE_REFRESH;
2790 BreakAgain(bview, row->previous());
2792 // set the cursor again. Otherwise
2793 // dangling pointers are possible
2794 SetCursor(bview, cursor.par(), cursor.pos());
2795 sel_cursor = cursor;
2800 int tmpheight = row->height();
2801 LyXParagraph::size_type tmplast = RowLast(row);
2805 BreakAgain(bview, row);
2806 if (row->height() == tmpheight && RowLast(row) == tmplast)
2807 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2809 status = LyXText::NEED_MORE_REFRESH;
2811 // check the special right address boxes
2812 if (textclasslist.Style(bview->buffer()->params.textclass,
2813 par->GetLayout()).margintype
2814 == MARGIN_RIGHT_ADDRESS_BOX) {
2821 RedoDrawingOfParagraph(bview, tmpcursor);
2827 // set the cursor again. Otherwise dangling pointers are possible
2828 // also set the selection
2832 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2833 sel_cursor = cursor;
2834 SetCursorIntern(bview, sel_start_cursor.par(),
2835 sel_start_cursor.pos());
2836 sel_start_cursor = cursor;
2837 SetCursorIntern(bview, sel_end_cursor.par(),
2838 sel_end_cursor.pos());
2839 sel_end_cursor = cursor;
2840 SetCursorIntern(bview, last_sel_cursor.par(),
2841 last_sel_cursor.pos());
2842 last_sel_cursor = cursor;
2845 SetCursorIntern(bview, cursor.par(), cursor.pos());
2849 // returns false if inset wasn't found
2850 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2852 // first check the current paragraph
2853 int pos = cursor.par()->GetPositionOfInset(inset);
2855 CheckParagraph(bview, cursor.par(), pos);
2859 // check every paragraph
2861 LyXParagraph * par = FirstParagraph();
2864 // make sure the paragraph is open
2865 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2867 pos = par->GetPositionOfInset(inset);
2869 CheckParagraph(bview, par, pos);
2882 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2883 LyXParagraph::size_type pos,
2884 bool setfont, bool boundary) const
2886 LyXCursor old_cursor = cursor;
2887 SetCursorIntern(bview, par, pos, setfont, boundary);
2888 DeleteEmptyParagraphMechanism(bview, old_cursor);
2892 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2893 LyXParagraph::size_type pos, bool boundary) const
2895 // correct the cursor position if impossible
2896 if (pos > par->Last()){
2897 LyXParagraph * tmppar = par->ParFromPos(pos);
2898 pos = par->PositionInParFromPos(pos);
2902 if (par->IsDummy() && par->previous &&
2903 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2904 while (par->previous &&
2905 ((par->previous->IsDummy() &&
2906 (par->previous->previous->footnoteflag ==
2907 LyXParagraph::CLOSED_FOOTNOTE)) ||
2908 (par->previous->footnoteflag ==
2909 LyXParagraph::CLOSED_FOOTNOTE))) {
2910 par = par->previous ;
2911 if (par->IsDummy() &&
2912 (par->previous->footnoteflag ==
2913 LyXParagraph::CLOSED_FOOTNOTE))
2914 pos += par->size() + 1;
2916 if (par->previous) {
2917 par = par->previous;
2919 pos += par->size() + 1;
2924 cur.boundary(boundary);
2926 /* get the cursor y position in text */
2928 Row * row = GetRow(par, pos, y);
2929 /* y is now the beginning of the cursor row */
2930 y += row->baseline();
2931 /* y is now the cursor baseline */
2934 /* now get the cursors x position */
2936 float fill_separator, fill_hfill, fill_label_hfill;
2937 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2939 LyXParagraph::size_type cursor_vpos = 0;
2940 LyXParagraph::size_type last = RowLastPrintable(row);
2942 if (pos > last + 1) // This shouldn't happen.
2944 else if (pos < row->pos())
2947 if (last < row->pos())
2948 cursor_vpos = row->pos();
2949 else if (pos > last && !boundary)
2950 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2951 ? row->pos() : last + 1;
2952 else if (pos > row->pos() &&
2953 (pos > last || boundary ||
2954 (row->par()->table && row->par()->IsNewline(pos))))
2955 /// Place cursor after char at (logical) position pos - 1
2956 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2957 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2959 /// Place cursor before char at (logical) position pos
2960 cursor_vpos = (bidi_level(pos) % 2 == 0)
2961 ? log2vis(pos) : log2vis(pos) + 1;
2964 /* table stuff -- begin*/
2965 if (row->par()->table) {
2966 int cell = NumberOfCell(row->par(), row->pos());
2968 x += row->par()->table->GetBeginningOfTextInCell(cell);
2969 for (LyXParagraph::size_type vpos = row->pos();
2970 vpos < cursor_vpos; ++vpos) {
2971 pos = vis2log(vpos);
2972 if (row->par()->IsNewline(pos)) {
2973 x = x_old + row->par()->table->WidthOfColumn(cell);
2976 x += row->par()->table->GetBeginningOfTextInCell(cell);
2978 x += SingleWidth(bview, row->par(), pos);
2982 /* table stuff -- end*/
2984 LyXParagraph::size_type main_body =
2985 BeginningOfMainBody(bview->buffer(), row->par());
2986 if ((main_body > 0) &&
2987 ((main_body-1 > last) ||
2988 !row->par()->IsLineSeparator(main_body-1)))
2991 for (LyXParagraph::size_type vpos = row->pos();
2992 vpos < cursor_vpos; ++vpos) {
2993 pos = vis2log(vpos);
2994 if (main_body > 0 && pos == main_body-1) {
2995 x += fill_label_hfill +
2996 lyxfont::width(textclasslist.Style(
2997 bview->buffer()->params.textclass,
2998 row->par()->GetLayout())
3000 GetFont(bview->buffer(), row->par(), -2));
3001 if (row->par()->IsLineSeparator(main_body-1))
3002 x -= SingleWidth(bview, row->par(),main_body-1);
3004 if (HfillExpansion(bview->buffer(), row, pos)) {
3005 x += SingleWidth(bview, row->par(), pos);
3006 if (pos >= main_body)
3009 x += fill_label_hfill;
3010 } else if (row->par()->IsSeparator(pos)) {
3011 x += SingleWidth(bview, row->par(), pos);
3012 if (pos >= main_body)
3013 x += fill_separator;
3015 x += SingleWidth(bview, row->par(), pos);
3027 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3028 LyXParagraph::size_type pos,
3029 bool setfont, bool boundary) const
3031 SetCursor(bview, cursor, par, pos, boundary);
3033 SetCurrentFont(bview);
3036 void LyXText::SetCurrentFont(BufferView * bview) const
3038 LyXParagraph::size_type pos = cursor.pos();
3039 if (cursor.boundary() && pos > 0)
3043 if (pos == cursor.par()->Last() ||
3044 (cursor.par()->table && cursor.par()->IsNewline(pos)))
3046 else if (cursor.par()->IsSeparator(pos)) {
3047 if (pos > cursor.row()->pos() &&
3048 bidi_level(pos) % 2 ==
3049 bidi_level(pos - 1) % 2)
3051 else if (pos + 1 < cursor.par()->Last())
3057 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3058 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3060 if (cursor.pos() == cursor.par()->Last() &&
3061 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3062 !cursor.boundary()) {
3063 Language const * lang =
3064 cursor.par()->getParLanguage(bview->buffer()->params);
3065 current_font.setLanguage(lang);
3066 real_current_font.setLanguage(lang);
3071 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3073 LyXCursor old_cursor = cursor;
3075 /* get the row first */
3077 Row * row = GetRowNearY(y);
3078 cursor.par(row->par());
3081 int column = GetColumnNearX(bview, row, x, bound);
3082 cursor.pos(row->pos() + column);
3084 cursor.y(y + row->baseline());
3086 cursor.boundary(bound);
3087 SetCurrentFont(bview);
3088 DeleteEmptyParagraphMechanism(bview, old_cursor);
3092 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3093 int x, long y) const
3095 /* get the row first */
3097 Row * row = GetRowNearY(y);
3099 int column = GetColumnNearX(bview, row, x, bound);
3101 cur.par(row->par());
3102 cur.pos(row->pos() + column);
3104 cur.y(y + row->baseline());
3106 cur.boundary(bound);
3110 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3112 CursorLeftIntern(bview, internal);
3114 if (cursor.par()->table) {
3115 int cell = NumberOfCell(cursor.par(), cursor.pos());
3116 if (cursor.par()->table->IsContRow(cell)
3117 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3125 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3127 if (cursor.pos() > 0) {
3128 bool boundary = cursor.boundary();
3129 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3130 if (!internal && !boundary &&
3131 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3132 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3133 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3134 LyXParagraph * par = cursor.par()->Previous();
3135 SetCursor(bview, par, par->Last());
3140 void LyXText::CursorRight(BufferView * bview, bool internal) const
3142 CursorRightIntern(bview, internal);
3144 if (cursor.par()->table) {
3145 int cell = NumberOfCell(cursor.par(), cursor.pos());
3146 if (cursor.par()->table->IsContRow(cell) &&
3147 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3155 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3157 if (!internal && cursor.boundary() &&
3158 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3159 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3160 else if (cursor.pos() < cursor.par()->Last()) {
3161 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3163 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3164 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3165 } else if (cursor.par()->Next())
3166 SetCursor(bview, cursor.par()->Next(), 0);
3170 void LyXText::CursorUp(BufferView * bview) const
3172 SetCursorFromCoordinates(bview, cursor.x_fix(),
3173 cursor.y() - cursor.row()->baseline() - 1);
3175 if (cursor.par()->table) {
3176 int cell = NumberOfCell(cursor.par(), cursor.pos());
3177 if (cursor.par()->table->IsContRow(cell) &&
3178 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3186 void LyXText::CursorDown(BufferView * bview) const
3189 if (cursor.par()->table &&
3190 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3191 !cursor.par()->next)
3195 SetCursorFromCoordinates(bview, cursor.x_fix(),
3196 cursor.y() - cursor.row()->baseline()
3197 + cursor.row()->height() + 1);
3199 if (cursor.par()->table) {
3200 int cell = NumberOfCell(cursor.par(), cursor.pos());
3201 int cell_above = cursor.par()->table->GetCellAbove(cell);
3202 while(cursor.par()->table &&
3203 cursor.par()->table->IsContRow(cell) &&
3204 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3205 SetCursorFromCoordinates(bview, cursor.x_fix(),
3206 cursor.y() - cursor.row()->baseline()
3207 + cursor.row()->height() + 1);
3208 if (cursor.par()->table) {
3209 cell = NumberOfCell(cursor.par(), cursor.pos());
3210 cell_above = cursor.par()->table->GetCellAbove(cell);
3218 void LyXText::CursorUpParagraph(BufferView * bview) const
3220 if (cursor.pos() > 0) {
3221 SetCursor(bview, cursor.par(), 0);
3223 else if (cursor.par()->Previous()) {
3224 SetCursor(bview, cursor.par()->Previous(), 0);
3229 void LyXText::CursorDownParagraph(BufferView * bview) const
3231 if (cursor.par()->Next()) {
3232 SetCursor(bview, cursor.par()->Next(), 0);
3234 SetCursor(bview, cursor.par(), cursor.par()->Last());
3239 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3240 LyXCursor const & old_cursor) const
3242 // Would be wrong to delete anything if we have a selection.
3243 if (selection) return;
3245 // We allow all kinds of "mumbo-jumbo" when freespacing.
3246 if (textclasslist.Style(bview->buffer()->params.textclass,
3247 old_cursor.par()->GetLayout()).free_spacing)
3250 bool deleted = false;
3252 /* Ok I'll put some comments here about what is missing.
3253 I have fixed BackSpace (and thus Delete) to not delete
3254 double-spaces automagically. I have also changed Cut,
3255 Copy and Paste to hopefully do some sensible things.
3256 There are still some small problems that can lead to
3257 double spaces stored in the document file or space at
3258 the beginning of paragraphs. This happens if you have
3259 the cursor betwenn to spaces and then save. Or if you
3260 cut and paste and the selection have a space at the
3261 beginning and then save right after the paste. I am
3262 sure none of these are very hard to fix, but I will
3263 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3264 that I can get some feedback. (Lgb)
3267 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3268 // delete the LineSeparator.
3271 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3272 // delete the LineSeparator.
3275 // If the pos around the old_cursor were spaces, delete one of them.
3276 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3277 // Only if the cursor has really moved
3279 if (old_cursor.pos() > 0
3280 && old_cursor.pos() < old_cursor.par()->Last()
3281 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3282 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3283 old_cursor.par()->Erase(old_cursor.pos() - 1);
3284 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3286 if (old_cursor.par() == cursor.par() &&
3287 cursor.pos() > old_cursor.pos()) {
3288 SetCursorIntern(bview, cursor.par(),
3291 SetCursorIntern(bview, cursor.par(),
3297 // Do not delete empty paragraphs with keepempty set.
3298 if ((textclasslist.Style(bview->buffer()->params.textclass,
3299 old_cursor.par()->GetLayout())).keepempty)
3302 LyXCursor tmpcursor;
3304 if (old_cursor.par() != cursor.par()) {
3305 if ( (old_cursor.par()->Last() == 0
3306 || (old_cursor.par()->Last() == 1
3307 && old_cursor.par()->IsLineSeparator(0)))
3309 && old_cursor.par()->FirstPhysicalPar()
3310 == old_cursor.par()->LastPhysicalPar()
3313 // ok, we will delete anything
3315 // make sure that you do not delete any environments
3318 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3319 !(old_cursor.row()->previous()
3320 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3321 && !(old_cursor.row()->next()
3322 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3323 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3324 && ((old_cursor.row()->previous()
3325 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3326 || (old_cursor.row()->next()
3327 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3330 status = LyXText::NEED_MORE_REFRESH;
3333 if (old_cursor.row()->previous()) {
3334 refresh_row = old_cursor.row()->previous();
3335 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3337 cursor = old_cursor; // that undo can restore the right cursor position
3338 LyXParagraph * endpar = old_cursor.par()->next;
3339 if (endpar && endpar->GetDepth()) {
3340 while (endpar && endpar->GetDepth()) {
3342 endpar = endpar->LastPhysicalPar()->Next();
3344 endpar = endpar->Next();
3348 SetUndo(bview->buffer(), Undo::DELETE,
3349 old_cursor.par()->previous,
3354 RemoveRow(old_cursor.row());
3355 if (OwnerParagraph() == old_cursor.par()) {
3356 OwnerParagraph(OwnerParagraph()->next);
3359 delete old_cursor.par();
3361 /* Breakagain the next par. Needed
3362 * because of the parindent that
3363 * can occur or dissappear. The
3364 * next row can change its height,
3365 * if there is another layout before */
3366 if (refresh_row->next()) {
3367 BreakAgain(bview, refresh_row->next());
3368 UpdateCounters(bview, refresh_row);
3370 SetHeightOfRow(bview, refresh_row);
3372 refresh_row = old_cursor.row()->next();
3373 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3376 cursor = old_cursor; // that undo can restore the right cursor position
3377 LyXParagraph * endpar = old_cursor.par()->next;
3378 if (endpar && endpar->GetDepth()) {
3379 while (endpar && endpar->GetDepth()) {
3381 endpar = endpar->LastPhysicalPar()->Next();
3383 endpar = endpar->Next();
3387 SetUndo(bview->buffer(), Undo::DELETE,
3388 old_cursor.par()->previous,
3393 RemoveRow(old_cursor.row());
3395 if (OwnerParagraph() == old_cursor.par()) {
3396 OwnerParagraph(OwnerParagraph()->next);
3398 delete old_cursor.par();
3400 /* Breakagain the next par. Needed
3401 because of the parindent that can
3402 occur or dissappear.
3403 The next row can change its height,
3404 if there is another layout before
3407 BreakAgain(bview, refresh_row);
3408 UpdateCounters(bview, refresh_row->previous());
3414 SetCursorIntern(bview, cursor.par(), cursor.pos());
3416 if (sel_cursor.par() == old_cursor.par()
3417 && sel_cursor.pos() == sel_cursor.pos()) {
3418 // correct selection
3419 sel_cursor = cursor;
3426 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3427 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3429 SetCursorIntern(bview, cursor.par(), cursor.pos());
3430 sel_cursor = cursor;
3437 LyXParagraph * LyXText::GetParFromID(int id)
3439 LyXParagraph * result = FirstParagraph();
3440 while (result && result->id() != id)
3441 result = result->next;
3447 bool LyXText::TextUndo(BufferView * bview)
3451 // returns false if no undo possible
3452 Undo * undo = bview->buffer()->undostack.pop();
3456 bview->buffer()->redostack
3457 .push(CreateUndo(bview->buffer(), undo->kind,
3458 GetParFromID(undo->number_of_before_par),
3459 GetParFromID(undo->number_of_behind_par)));
3461 return TextHandleUndo(bview, undo);
3465 bool LyXText::TextRedo(BufferView * bview)
3469 // returns false if no redo possible
3470 Undo * undo = bview->buffer()->redostack.pop();
3474 bview->buffer()->undostack
3475 .push(CreateUndo(bview->buffer(), undo->kind,
3476 GetParFromID(undo->number_of_before_par),
3477 GetParFromID(undo->number_of_behind_par)));
3479 return TextHandleUndo(bview, undo);
3483 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3487 // returns false if no undo possible
3488 bool result = false;
3490 LyXParagraph * before =
3491 GetParFromID(undo->number_of_before_par);
3492 LyXParagraph * behind =
3493 GetParFromID(undo->number_of_behind_par);
3494 LyXParagraph * tmppar;
3495 LyXParagraph * tmppar2;
3496 LyXParagraph * endpar;
3497 LyXParagraph * tmppar5;
3499 // if there's no before take the beginning
3500 // of the document for redoing
3502 SetCursorIntern(bview, FirstParagraph(), 0);
3504 // replace the paragraphs with the undo informations
3506 LyXParagraph * tmppar3 = undo->par;
3507 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3508 LyXParagraph * tmppar4 = tmppar3;
3510 while (tmppar4->next)
3511 tmppar4 = tmppar4->next;
3512 } // get last undo par
3514 // now remove the old text if there is any
3515 if (before != behind || (!behind && !before)){
3517 tmppar5 = before->next;
3519 tmppar5 = OwnerParagraph();
3521 while (tmppar5 && tmppar5 != behind){
3523 tmppar5 = tmppar5->next;
3524 // a memory optimization for edit: Only layout information
3525 // is stored in the undo. So restore the text informations.
3526 if (undo->kind == Undo::EDIT) {
3527 tmppar2->setContentsFromPar(tmppar);
3528 tmppar->clearContents();
3529 tmppar2 = tmppar2->next;
3534 // put the new stuff in the list if there is one
3537 before->next = tmppar3;
3539 OwnerParagraph(tmppar3);
3540 tmppar3->previous = before;
3543 OwnerParagraph(behind);
3546 tmppar4->next = behind;
3548 behind->previous = tmppar4;
3552 // Set the cursor for redoing
3555 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3557 SetCursorIntern(bview, before, 0);
3560 // check wether before points to a closed float and open it if necessary
3561 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3562 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3564 while (tmppar4->previous &&
3565 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3566 tmppar4 = tmppar4->previous;
3567 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3568 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3569 tmppar4 = tmppar4->next;
3576 // open a cosed footnote at the end if necessary
3577 if (behind && behind->previous &&
3578 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3579 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3580 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3581 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3582 behind = behind->next;
3587 // calculate the endpar for redoing the paragraphs.
3590 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3591 endpar = behind->LastPhysicalPar()->Next();
3593 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3595 endpar = behind->Next();
3600 tmppar = GetParFromID(undo->number_of_cursor_par);
3601 RedoParagraphs(bview, cursor, endpar);
3603 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3604 UpdateCounters(bview, cursor.row());
3614 void LyXText::FinishUndo()
3618 // makes sure the next operation will be stored
3619 undo_finished = true;
3623 void LyXText::FreezeUndo()
3627 // this is dangerous and for internal use only
3632 void LyXText::UnFreezeUndo()
3636 // this is dangerous and for internal use only
3637 undo_frozen = false;
3641 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3642 LyXParagraph const * before,
3643 LyXParagraph const * behind) const
3648 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3649 buf->redostack.clear();
3653 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3654 LyXParagraph const * before, LyXParagraph const * behind)
3658 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3662 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3663 LyXParagraph const * before,
3664 LyXParagraph const * behind) const
3669 int before_number = -1;
3670 int behind_number = -1;
3672 before_number = before->id();
3674 behind_number = behind->id();
3675 // Undo::EDIT and Undo::FINISH are
3676 // always finished. (no overlapping there)
3677 // overlapping only with insert and delete inside one paragraph:
3678 // Nobody wants all removed character
3679 // appear one by one when undoing.
3680 // EDIT is special since only layout information, not the
3681 // contents of a paragaph are stored.
3682 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3683 // check wether storing is needed
3684 if (!buf->undostack.empty() &&
3685 buf->undostack.top()->kind == kind &&
3686 buf->undostack.top()->number_of_before_par == before_number &&
3687 buf->undostack.top()->number_of_behind_par == behind_number ){
3692 // create a new Undo
3693 LyXParagraph * undopar;
3694 LyXParagraph * tmppar;
3695 LyXParagraph * tmppar2;
3697 LyXParagraph * start = 0;
3698 LyXParagraph * end = 0;
3701 start = before->next;
3703 start = FirstParagraph();
3705 end = behind->previous;
3707 end = FirstParagraph();
3713 && start != end->next
3714 && (before != behind || (!before && !behind))) {
3716 tmppar2 = tmppar->Clone();
3717 tmppar2->id(tmppar->id());
3719 // a memory optimization: Just store the layout information
3721 if (kind == Undo::EDIT){
3722 //tmppar2->text.clear();
3723 tmppar2->clearContents();
3728 while (tmppar != end && tmppar->next) {
3729 tmppar = tmppar->next;
3730 tmppar2->next = tmppar->Clone();
3731 tmppar2->next->id(tmppar->id());
3732 // a memory optimization: Just store the layout
3733 // information when only edit
3734 if (kind == Undo::EDIT){
3735 //tmppar2->next->text.clear();
3736 tmppar2->clearContents();
3738 tmppar2->next->previous = tmppar2;
3739 tmppar2 = tmppar2->next;
3743 undopar = 0; // nothing to replace (undo of delete maybe)
3745 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3746 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3748 Undo * undo = new Undo(kind,
3749 before_number, behind_number,
3750 cursor_par, cursor_pos,
3753 undo_finished = false;
3758 void LyXText::SetCursorParUndo(Buffer * buf)
3762 SetUndo(buf, Undo::FINISH,
3763 cursor.par()->ParFromPos(cursor.pos())->previous,
3764 cursor.par()->ParFromPos(cursor.pos())->next);
3769 void LyXText::RemoveTableRow(LyXCursor & cur) const
3775 // move to the previous row
3776 int cell_act = NumberOfCell(cur.par(), cur.pos());
3779 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3780 cur.pos(cur.pos() - 1);
3782 !cur.par()->table->IsFirstCell(cell_act)) {
3783 cur.pos(cur.pos() - 1);
3784 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3785 cur.pos(cur.pos() - 1);
3789 // now we have to pay attention if the actual table is the
3790 // main row of TableContRows and if yes to delete all of them
3795 // delete up to the next row
3796 while (cur.pos() < cur.par()->Last() &&
3798 || !cur.par()->table->IsFirstCell(cell_act))) {
3799 while (cur.pos() < cur.par()->Last() &&
3800 !cur.par()->IsNewline(cur.pos()))
3801 cur.par()->Erase(cur.pos());
3804 if (cur.pos() < cur.par()->Last())
3805 cur.par()->Erase(cur.pos());
3807 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3808 cur.pos(cur.pos() - 1);
3809 cur.par()->Erase(cur.pos()); // no newline at very end!
3811 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3812 !cur.par()->table->IsContRow(cell_org) &&
3813 cur.par()->table->IsContRow(cell));
3814 cur.par()->table->DeleteRow(cell_org);
3821 bool LyXText::IsEmptyTableCell() const
3823 LyXParagraph::size_type pos = cursor.pos() - 1;
3824 while (pos >= 0 && pos < cursor.par()->Last()
3825 && !cursor.par()->IsNewline(pos))
3827 return cursor.par()->IsNewline(pos + 1);
3832 void LyXText::toggleAppendix(BufferView * bview)
3835 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3837 LyXParagraph * par = cursor.par();
3839 bool start = !par->start_of_appendix;
3841 // ensure that we have only one start_of_appendix in this document
3842 LyXParagraph * tmp = FirstParagraph();
3843 for (; tmp; tmp = tmp->next)
3844 tmp->start_of_appendix = 0;
3845 par->start_of_appendix = start;
3847 // we can set the refreshing parameters now
3848 status = LyXText::NEED_MORE_REFRESH;
3850 refresh_row = 0; // not needed for full update
3851 UpdateCounters(bview, 0);
3852 SetCursor(bview, cursor.par(), cursor.pos());
3856 LyXParagraph * LyXText::OwnerParagraph() const
3859 return inset_owner->par;
3861 return bv_owner->buffer()->paragraph;
3865 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3868 inset_owner->par = p;
3870 bv_owner->buffer()->paragraph = p;