1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
52 LyXText::LyXText(BufferView * bv)
60 LyXText::LyXText(InsetText * inset)
77 status = LyXText::UNCHANGED;
78 // set cursor at the very top position
79 selection = true; /* these setting is necessary
80 because of the delete-empty-
81 paragraph mechanism in
84 LyXParagraph * par = OwnerParagraph();
85 current_font = GetFont(bv_owner->buffer(), par, 0);
87 InsertParagraph(bv_owner, par, lastrow);
90 SetCursor(bv_owner, firstrow->par(), 0);
92 current_font = LyXFont(LyXFont::ALL_SANE);
98 // no rebreak necessary
101 undo_finished = true;
104 // Default layouttype for copy environment type
108 // Dump all rowinformation:
109 Row * tmprow = firstrow;
110 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
112 lyxerr << tmprow->baseline() << '\t'
113 << tmprow->par << '\t'
114 << tmprow->pos() << '\t'
115 << tmprow->height << '\t'
116 << tmprow->ascent_of_text << '\t'
117 << tmprow->fill << '\n';
118 tmprow = tmprow->next();
125 void LyXText::init(BufferView * bview)
130 LyXParagraph * par = OwnerParagraph();
131 current_font = GetFont(bview->buffer(), par, 0);
133 InsertParagraph(bview, par, lastrow);
136 SetCursorIntern(bview, firstrow->par(), 0);
139 // Dump all rowinformation:
140 Row * tmprow = firstrow;
141 lyxerr << "Width = " << width << endl;
142 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
144 lyxerr << tmprow->baseline() << '\t'
145 << tmprow->par() << '\t'
146 << tmprow->pos() << '\t'
147 << tmprow->height() << '\t'
148 << tmprow->ascent_of_text() << '\t'
149 << tmprow->fill() << '\n';
150 tmprow = tmprow->next();
158 // Delete all rows, this does not touch the paragraphs!
159 Row * tmprow = firstrow;
161 tmprow = firstrow->next();
168 // Gets the fully instantiated font at a given position in a paragraph
169 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
170 // The difference is that this one is used for displaying, and thus we
171 // are allowed to make cosmetic improvements. For instance make footnotes
173 // If position is -1, we get the layout font of the paragraph.
174 // If position is -2, we get the font of the manual label of the paragraph.
175 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
176 LyXParagraph::size_type pos) const
178 LyXLayout const & layout =
179 textclasslist.Style(buf->params.textclass, par->GetLayout());
181 char par_depth = par->GetDepth();
182 // We specialize the 95% common case:
185 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
190 if (layout.labeltype == LABEL_MANUAL
191 && pos < BeginningOfMainBody(buf, par)) {
193 return par->GetFontSettings(buf->params, pos).
194 realize(layout.reslabelfont);
196 return par->GetFontSettings(buf->params, pos).
197 realize(layout.resfont);
200 // process layoutfont for pos == -1 and labelfont for pos < -1
202 return layout.resfont;
204 return layout.reslabelfont;
208 // The uncommon case need not be optimized as much
210 LyXFont layoutfont, tmpfont;
214 if (pos < BeginningOfMainBody(buf, par)) {
216 layoutfont = layout.labelfont;
219 layoutfont = layout.font;
221 tmpfont = par->GetFontSettings(buf->params, pos);
222 tmpfont.realize(layoutfont);
225 // process layoutfont for pos == -1 and labelfont for pos < -1
227 tmpfont = layout.font;
229 tmpfont = layout.labelfont;
232 // Resolve against environment font information
233 while (par && par_depth && !tmpfont.resolved()) {
234 par = par->DepthHook(par_depth - 1);
236 tmpfont.realize(textclasslist.
237 Style(buf->params.textclass,
238 par->GetLayout()).font);
239 par_depth = par->GetDepth();
243 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
246 // Cosmetic improvement: If this is an open footnote, make the font
248 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
249 && par->footnotekind == LyXParagraph::FOOTNOTE) {
257 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
258 LyXParagraph::size_type pos,
262 // Let the insets convert their font
263 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
264 if (par->GetInset(pos))
265 font = par->GetInset(pos)->ConvertFont(font);
268 LyXLayout const & layout =
269 textclasslist.Style(buf->params.textclass,
272 // Get concrete layout font to reduce against
275 if (pos < BeginningOfMainBody(buf, par))
276 layoutfont = layout.labelfont;
278 layoutfont = layout.font;
280 // Realize against environment font information
281 if (par->GetDepth()){
282 LyXParagraph * tp = par;
283 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
284 tp = tp->DepthHook(tp->GetDepth()-1);
286 layoutfont.realize(textclasslist.
287 Style(buf->params.textclass,
288 tp->GetLayout()).font);
292 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
295 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
296 && par->footnotekind == LyXParagraph::FOOTNOTE) {
297 layoutfont.decSize();
300 // Now, reduce font against full layout font
301 font.reduce(layoutfont);
303 par->SetFont(pos, font);
307 /* inserts a new row behind the specified row, increments
308 * the touched counters */
309 void LyXText::InsertRow(Row * row, LyXParagraph * par,
310 LyXParagraph::size_type pos) const
312 Row * tmprow = new Row;
315 tmprow->next(firstrow);
318 tmprow->previous(row);
319 tmprow->next(row->next());
324 tmprow->next()->previous(tmprow);
326 if (tmprow->previous())
327 tmprow->previous()->next(tmprow);
335 ++number_of_rows; // one more row
339 // removes the row and reset the touched counters
340 void LyXText::RemoveRow(Row * row) const
342 /* this must not happen before the currentrow for clear reasons.
343 so the trick is just to set the current row onto the previous
346 GetRow(row->par(), row->pos(), unused_y);
349 row->next()->previous(row->previous());
350 if (!row->previous()) {
351 firstrow = row->next();
353 row->previous()->next(row->next());
356 lastrow = row->previous();
358 height -= row->height(); // the text becomes smaller
361 --number_of_rows; // one row less
365 // remove all following rows of the paragraph of the specified row.
366 void LyXText::RemoveParagraph(Row * row) const
368 LyXParagraph * tmppar = row->par();
372 while (row && row->par() == tmppar) {
373 tmprow = row->next();
380 // insert the specified paragraph behind the specified row
381 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
384 InsertRow(row, par, 0); /* insert a new row, starting
387 SetCounter(bview->buffer(), par); // set the counters
389 // and now append the whole paragraph behind the new row
392 AppendParagraph(bview, firstrow);
394 row->next()->height(0);
395 AppendParagraph(bview, row->next());
401 void LyXText::ToggleFootnote(BufferView * bview)
403 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
405 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
407 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
409 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
410 CloseFootnote(bview);
417 void LyXText::OpenStuff(BufferView * bview)
419 if (cursor.pos() == 0 && cursor.par()->bibkey){
420 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
421 } else if (cursor.pos() < cursor.par()->Last()
422 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
423 && cursor.par()->GetInset(cursor.pos())->Editable()) {
424 bview->owner()->getMiniBuffer()
425 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
426 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
427 SetCursorParUndo(bview->buffer());
428 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
432 ToggleFootnote(bview);
440 void LyXText::CloseFootnote(BufferView * bview)
442 LyXParagraph * tmppar;
443 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
445 // if the cursor is not in an open footnote, or
446 // there is no open footnote in this paragraph, just return.
447 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
450 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
451 bview->owner()->getMiniBuffer()
452 ->Set(_("Nothing to do"));
456 // ok, move the cursor right before the footnote
457 // just a little faster than using CursorRight()
459 cursor.par()->ParFromPos(cursor.pos()) != par;) {
460 cursor.pos(cursor.pos() + 1);
463 // now the cursor is at the beginning of the physical par
464 SetCursor(bview, cursor.par(),
466 cursor.par()->ParFromPos(cursor.pos())->size());
468 /* we are in a footnote, so let us move at the beginning */
469 /* this is just faster than using just CursorLeft() */
471 tmppar = cursor.par();
472 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
473 // just a little bit faster than movin the cursor
474 tmppar = tmppar->Previous();
476 SetCursor(bview, tmppar, tmppar->Last());
479 // the cursor must be exactly before the footnote
480 par = cursor.par()->ParFromPos(cursor.pos());
482 status = LyXText::NEED_MORE_REFRESH;
483 refresh_row = cursor.row();
484 refresh_y = cursor.y() - cursor.row()->baseline();
486 tmppar = cursor.par();
487 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
488 Row * row = cursor.row();
490 tmppar->CloseFootnote(cursor.pos());
492 while (tmppar != endpar) {
493 RemoveRow(row->next());
495 tmppar = row->next()->par();
500 AppendParagraph(bview, cursor.row());
502 SetCursor(bview, cursor.par(), cursor.pos());
506 if (cursor.row()->next())
507 SetHeightOfRow(bview, cursor.row()->next());
512 /* used in setlayout */
513 // Asger is not sure we want to do this...
514 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
518 LyXLayout const & layout =
519 textclasslist.Style(buf->params.textclass, par->GetLayout());
521 LyXFont layoutfont, tmpfont;
522 for (LyXParagraph::size_type pos = 0;
523 pos < par->Last(); ++pos) {
524 if (pos < BeginningOfMainBody(buf, par))
525 layoutfont = layout.labelfont;
527 layoutfont = layout.font;
529 tmpfont = par->GetFontSettings(buf->params, pos);
530 tmpfont.reduce(layoutfont);
531 par->SetFont(pos, tmpfont);
536 LyXParagraph * LyXText::SetLayout(BufferView * bview,
537 LyXCursor & cur, LyXCursor & sstart_cur,
538 LyXCursor & send_cur,
539 LyXTextClass::size_type layout)
542 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
544 LyXParagraph * endpar = send_cur.par()->Next();
546 LyXParagraph * undoendpar = endpar;
548 if (endpar && endpar->GetDepth()) {
549 while (endpar && endpar->GetDepth()) {
551 endpar = endpar->LastPhysicalPar()->Next();
553 endpar = endpar->Next();
558 endpar = endpar->Next(); // because of parindents etc.
561 SetUndo(bview->buffer(), Undo::EDIT,
563 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
565 sstart_cur.par()->previous,
569 /* ok we have a selection. This is always between sstart_cur
570 * and sel_end cursor */
573 LyXLayout const & lyxlayout =
574 textclasslist.Style(bview->buffer()->params.textclass, layout);
576 while (cur.par() != send_cur.par()) {
578 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
580 cur.par()->SetLayout(bview->buffer()->params, layout);
581 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
583 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
585 LyXParagraph * fppar = cur.par();
587 fppar->added_space_top = lyxlayout.fill_top ?
588 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
589 fppar->added_space_bottom = lyxlayout.fill_bottom ?
590 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
591 if (lyxlayout.margintype == MARGIN_MANUAL)
592 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
593 if (lyxlayout.labeltype != LABEL_BIBLIO
595 delete fppar->bibkey;
601 cur.par(cur.par()->Next());
604 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
606 cur.par()->SetLayout(bview->buffer()->params, layout);
607 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
609 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
611 LyXParagraph * fppar = cur.par();
613 fppar->added_space_top = lyxlayout.fill_top ?
614 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
615 fppar->added_space_bottom = lyxlayout.fill_bottom ?
616 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
617 if (lyxlayout.margintype == MARGIN_MANUAL)
618 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
619 if (lyxlayout.labeltype != LABEL_BIBLIO
621 delete fppar->bibkey;
630 // set layout over selection and make a total rebreak of those paragraphs
631 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
633 LyXCursor tmpcursor = cursor; /* store the current cursor */
635 // if there is no selection just set the layout
636 // of the current paragraph */
638 sel_start_cursor = cursor; // dummy selection
639 sel_end_cursor = cursor;
642 endpar = SetLayout(bview, cursor, sel_start_cursor,
643 sel_end_cursor, layout);
644 RedoParagraphs(bview, sel_start_cursor, endpar);
646 // we have to reset the selection, because the
647 // geometry could have changed
648 SetCursor(bview, sel_start_cursor.par(),
649 sel_start_cursor.pos(), false);
651 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
653 UpdateCounters(bview, cursor.row());
656 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
660 // increment depth over selection and
661 // make a total rebreak of those paragraphs
662 void LyXText::IncDepth(BufferView * bview)
664 // If there is no selection, just use the current paragraph
666 sel_start_cursor = cursor; // dummy selection
667 sel_end_cursor = cursor;
670 // We end at the next paragraph with depth 0
671 LyXParagraph * endpar =
673 sel_end_cursor.par()->LastPhysicalPar()->Next();
675 sel_end_cursor.par()->Next();
677 LyXParagraph * undoendpar = endpar;
679 if (endpar && endpar->GetDepth()) {
680 while (endpar && endpar->GetDepth()) {
682 endpar = endpar->LastPhysicalPar()->Next();
684 endpar = endpar->Next();
690 endpar = endpar->Next(); // because of parindents etc.
693 SetUndo(bview->buffer(), Undo::EDIT,
696 .par()->ParFromPos(sel_start_cursor.pos())->previous,
698 sel_start_cursor.par()->previous,
702 LyXCursor tmpcursor = cursor; // store the current cursor
704 // ok we have a selection. This is always between sel_start_cursor
705 // and sel_end cursor
706 cursor = sel_start_cursor;
708 bool anything_changed = false;
711 // NOTE: you can't change the depth of a bibliography entry
714 cursor.par()->footnoteflag ==
715 sel_start_cursor.par()->footnoteflag &&
717 textclasslist.Style(bview->buffer()->params.textclass,
718 cursor.par()->GetLayout()
719 ).labeltype != LABEL_BIBLIO) {
720 LyXParagraph * prev =
722 cursor.par()->FirstPhysicalPar()->Previous();
724 cursor.par()->Previous();
727 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
728 || (prev->GetDepth() == cursor.par()->GetDepth()
729 && textclasslist.Style(bview->buffer()->params.textclass,
730 prev->GetLayout()).isEnvironment()))) {
732 cursor.par()->FirstPhysicalPar()->depth++;
734 cursor.par()->depth++;
736 anything_changed = true;
739 if (cursor.par() == sel_end_cursor.par())
741 cursor.par(cursor.par()->Next());
744 // if nothing changed set all depth to 0
745 if (!anything_changed) {
746 cursor = sel_start_cursor;
747 while (cursor.par() != sel_end_cursor.par()) {
749 cursor.par()->FirstPhysicalPar()->depth = 0;
751 cursor.par()->depth = 0;
753 cursor.par(cursor.par()->Next());
756 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
757 cursor.par()->FirstPhysicalPar()->depth = 0;
759 cursor.par()->depth = 0;
763 RedoParagraphs(bview, sel_start_cursor, endpar);
765 // we have to reset the selection, because the
766 // geometry could have changed
767 SetCursor(bview, sel_start_cursor.par(),
768 sel_start_cursor.pos());
770 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
771 UpdateCounters(bview, cursor.row());
774 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
778 // decrement depth over selection and
779 // make a total rebreak of those paragraphs
780 void LyXText::DecDepth(BufferView * bview)
782 // if there is no selection just set the layout
783 // of the current paragraph
785 sel_start_cursor = cursor; // dummy selection
786 sel_end_cursor = cursor;
789 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
791 LyXParagraph * endpar = sel_end_cursor.par()->Next();
793 LyXParagraph * undoendpar = endpar;
795 if (endpar && endpar->GetDepth()) {
796 while (endpar && endpar->GetDepth()) {
798 endpar = endpar->LastPhysicalPar()->Next();
800 endpar = endpar->Next();
806 endpar = endpar->Next(); // because of parindents etc.
809 SetUndo(bview->buffer(), Undo::EDIT,
812 .par()->ParFromPos(sel_start_cursor.pos())->previous,
814 sel_start_cursor.par()->previous,
818 LyXCursor tmpcursor = cursor; // store the current cursor
820 // ok we have a selection. This is always between sel_start_cursor
821 // and sel_end cursor
822 cursor = sel_start_cursor;
826 if (cursor.par()->footnoteflag ==
827 sel_start_cursor.par()->footnoteflag) {
828 if (cursor.par()->FirstPhysicalPar()->depth)
829 cursor.par()->FirstPhysicalPar()->depth--;
832 if (cursor.par()->depth)
833 cursor.par()->depth--;
835 if (cursor.par() == sel_end_cursor.par())
837 cursor.par(cursor.par()->Next());
840 RedoParagraphs(bview, sel_start_cursor, endpar);
842 // we have to reset the selection, because the
843 // geometry could have changed
844 SetCursor(bview, sel_start_cursor.par(),
845 sel_start_cursor.pos());
847 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
848 UpdateCounters(bview, cursor.row());
851 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
855 // set font over selection and make a total rebreak of those paragraphs
856 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
858 // if there is no selection just set the current_font
860 // Determine basis font
862 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
864 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
866 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
867 // Update current font
868 real_current_font.update(font,
869 bview->buffer()->params.language_info,
872 // Reduce to implicit settings
873 current_font = real_current_font;
874 current_font.reduce(layoutfont);
875 // And resolve it completely
876 real_current_font.realize(layoutfont);
880 LyXCursor tmpcursor = cursor; // store the current cursor
882 // ok we have a selection. This is always between sel_start_cursor
883 // and sel_end cursor
885 SetUndo(bview->buffer(), Undo::EDIT,
887 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
888 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
890 sel_start_cursor.par()->previous,
891 sel_end_cursor.par()->next
894 cursor = sel_start_cursor;
895 while (cursor.par() != sel_end_cursor.par() ||
898 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
900 cursor.pos() < sel_end_cursor.pos()))
902 if (cursor.pos() < cursor.par()->Last()
904 && cursor.par()->footnoteflag
905 == sel_start_cursor.par()->footnoteflag
908 // an open footnote should behave
910 LyXFont newfont = GetFont(bview->buffer(),
911 cursor.par(), cursor.pos());
913 bview->buffer()->params.language_info,
915 SetCharFont(bview->buffer(),
916 cursor.par(), cursor.pos(), newfont);
917 cursor.pos(cursor.pos() + 1);
920 cursor.par(cursor.par()->Next());
924 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
926 // we have to reset the selection, because the
927 // geometry could have changed
928 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
930 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
933 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
934 tmpcursor.boundary());
938 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
940 Row * tmprow = cur.row();
941 long y = cur.y() - tmprow->baseline();
943 SetHeightOfRow(bview, tmprow);
945 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
947 LyXParagraph * first_phys_par = tmprow->par();
949 // find the first row of the paragraph
950 if (first_phys_par != tmprow->par())
951 while (tmprow->previous()
952 && tmprow->previous()->par() != first_phys_par) {
953 tmprow = tmprow->previous();
954 y -= tmprow->height();
955 SetHeightOfRow(bview, tmprow);
957 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
958 tmprow = tmprow->previous();
959 y -= tmprow->height();
960 SetHeightOfRow(bview, tmprow);
963 // we can set the refreshing parameters now
964 status = LyXText::NEED_MORE_REFRESH;
966 refresh_row = tmprow;
967 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
971 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
973 Row * tmprow = cur.row();
975 long y = cur.y() - tmprow->baseline();
976 SetHeightOfRow(bview, tmprow);
978 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
980 LyXParagraph * first_phys_par = tmprow->par();
982 // find the first row of the paragraph
983 if (first_phys_par != tmprow->par())
984 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
985 tmprow = tmprow->previous();
986 y -= tmprow->height();
988 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
989 tmprow = tmprow->previous();
990 y -= tmprow->height();
993 // we can set the refreshing parameters now
994 if (status == LyXText::UNCHANGED || y < refresh_y) {
996 refresh_row = tmprow;
998 status = LyXText::NEED_MORE_REFRESH;
999 SetCursor(bview, cur.par(), cur.pos());
1003 /* deletes and inserts again all paragaphs between the cursor
1004 * and the specified par
1005 * This function is needed after SetLayout and SetFont etc. */
1006 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1007 LyXParagraph const * endpar) const
1010 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1012 Row * tmprow = cur.row();
1014 long y = cur.y() - tmprow->baseline();
1016 if (!tmprow->previous()){
1017 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1020 first_phys_par = tmprow->par()->FirstPhysicalPar();
1022 first_phys_par = tmprow->par();
1024 // find the first row of the paragraph
1025 if (first_phys_par != tmprow->par())
1026 while (tmprow->previous() &&
1027 (tmprow->previous()->par() != first_phys_par)) {
1028 tmprow = tmprow->previous();
1029 y -= tmprow->height();
1031 while (tmprow->previous()
1032 && tmprow->previous()->par() == first_phys_par) {
1033 tmprow = tmprow->previous();
1034 y -= tmprow->height();
1038 // we can set the refreshing parameters now
1039 status = LyXText::NEED_MORE_REFRESH;
1041 refresh_row = tmprow->previous(); /* the real refresh row will
1042 be deleted, so I store
1043 the previous here */
1046 tmppar = tmprow->next()->par();
1049 while (tmppar != endpar) {
1050 RemoveRow(tmprow->next());
1052 tmppar = tmprow->next()->par();
1057 // remove the first one
1058 tmprow2 = tmprow; /* this is because tmprow->previous()
1060 tmprow = tmprow->previous();
1063 tmppar = first_phys_par;
1067 InsertParagraph(bview, tmppar, tmprow);
1070 while (tmprow->next() && tmprow->next()->par() == tmppar)
1071 tmprow = tmprow->next();
1072 tmppar = tmppar->Next();
1074 } while (tmppar != endpar);
1076 // this is because of layout changes
1078 refresh_y -= refresh_row->height();
1079 SetHeightOfRow(bview, refresh_row);
1081 refresh_row = firstrow;
1083 SetHeightOfRow(bview, refresh_row);
1086 if (tmprow && tmprow->next())
1087 SetHeightOfRow(bview, tmprow->next());
1091 bool LyXText::FullRebreak(BufferView * bview)
1097 if (need_break_row) {
1098 BreakAgain(bview, need_break_row);
1106 /* important for the screen */
1109 /* the cursor set functions have a special mechanism. When they
1110 * realize, that you left an empty paragraph, they will delete it.
1111 * They also delete the corresponding row */
1113 // need the selection cursor:
1114 void LyXText::SetSelection()
1117 last_sel_cursor = sel_cursor;
1118 sel_start_cursor = sel_cursor;
1119 sel_end_cursor = sel_cursor;
1124 // first the toggling area
1125 if (cursor.y() < last_sel_cursor.y()
1126 || (cursor.y() == last_sel_cursor.y()
1127 && cursor.x() < last_sel_cursor.x())) {
1128 toggle_end_cursor = last_sel_cursor;
1129 toggle_cursor = cursor;
1131 toggle_end_cursor = cursor;
1132 toggle_cursor = last_sel_cursor;
1135 last_sel_cursor = cursor;
1137 // and now the whole selection
1139 if (sel_cursor.par() == cursor.par())
1140 if (sel_cursor.pos() < cursor.pos()) {
1141 sel_end_cursor = cursor;
1142 sel_start_cursor = sel_cursor;
1144 sel_end_cursor = sel_cursor;
1145 sel_start_cursor = cursor;
1147 else if (sel_cursor.y() < cursor.y() ||
1148 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1149 sel_end_cursor = cursor;
1150 sel_start_cursor = sel_cursor;
1153 sel_end_cursor = sel_cursor;
1154 sel_start_cursor = cursor;
1157 // a selection with no contents is not a selection
1158 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1159 sel_start_cursor.pos() == sel_end_cursor.pos())
1164 string LyXText::selectionAsString(Buffer const * buffer) const
1166 if (!selection) return string();
1169 // Special handling if the whole selection is within one paragraph
1170 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1171 result += sel_start_cursor.par()->String(buffer,
1172 sel_start_cursor.pos(),
1173 sel_end_cursor.pos());
1177 // The selection spans more than one paragraph
1179 // First paragraph in selection
1180 result += sel_start_cursor.par()->String(buffer,
1181 sel_start_cursor.pos(),
1182 sel_start_cursor.par()->Last())
1185 // The paragraphs in between (if any)
1186 LyXCursor tmpcur(sel_start_cursor);
1187 tmpcur.par(tmpcur.par()->Next());
1188 while (tmpcur.par() != sel_end_cursor.par()) {
1189 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1190 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1193 // Last paragraph in selection
1194 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1200 void LyXText::ClearSelection() const
1207 void LyXText::CursorHome(BufferView * bview) const
1209 SetCursor(bview, cursor.par(), cursor.row()->pos());
1213 void LyXText::CursorEnd(BufferView * bview) const
1215 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1216 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1218 if (cursor.par()->Last() &&
1219 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1220 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1221 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1223 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1226 if (cursor.par()->table) {
1227 int cell = NumberOfCell(cursor.par(), cursor.pos());
1228 if (cursor.par()->table->RowHasContRow(cell) &&
1229 cursor.par()->table->CellHasContRow(cell)<0) {
1230 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1231 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1233 if (cursor.par()->Last() &&
1234 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1235 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1236 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1238 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1246 void LyXText::CursorTop(BufferView * bview) const
1248 while (cursor.par()->Previous())
1249 cursor.par(cursor.par()->Previous());
1250 SetCursor(bview, cursor.par(), 0);
1254 void LyXText::CursorBottom(BufferView * bview) const
1256 while (cursor.par()->Next())
1257 cursor.par(cursor.par()->Next());
1258 SetCursor(bview, cursor.par(), cursor.par()->Last());
1262 /* returns a pointer to the row near the specified y-coordinate
1263 * (relative to the whole text). y is set to the real beginning
1265 Row * LyXText::GetRowNearY(long & y) const
1267 Row * tmprow = firstrow;
1270 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1271 tmpy += tmprow->height();
1272 tmprow = tmprow->next();
1275 y = tmpy; // return the real y
1280 void LyXText::ToggleFree(BufferView * bview,
1281 LyXFont const & font, bool toggleall)
1283 // If the mask is completely neutral, tell user
1284 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1285 // Could only happen with user style
1286 bview->owner()->getMiniBuffer()
1287 ->Set(_("No font change defined. Use Character under"
1288 " the Layout menu to define font change."));
1292 // Try implicit word selection
1293 // If there is a change in the language the implicit word selection
1295 LyXCursor resetCursor = cursor;
1296 bool implicitSelection = (font.language() == ignore_language)
1297 ? SelectWordWhenUnderCursor(bview) : false;
1300 SetFont(bview, font, toggleall);
1302 /* Implicit selections are cleared afterwards and cursor is set to the
1303 original position. */
1304 if (implicitSelection) {
1306 cursor = resetCursor;
1307 SetCursor(bview, cursor.par(), cursor.pos());
1308 sel_cursor = cursor;
1313 LyXParagraph::size_type
1314 LyXText::BeginningOfMainBody(Buffer const * buf,
1315 LyXParagraph const * par) const
1317 if (textclasslist.Style(buf->params.textclass,
1318 par->GetLayout()).labeltype != LABEL_MANUAL)
1321 return par->BeginningOfMainBody();
1326 /* if there is a selection, reset every environment you can find
1327 * in the selection, otherwise just the environment you are in */
1328 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1330 LyXParagraph * tmppar, * firsttmppar;
1334 /* is is only allowed, if the cursor is IN an open footnote.
1335 * Otherwise it is too dangerous */
1336 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1339 SetUndo(bview->buffer(), Undo::FINISH,
1340 cursor.par()->PreviousBeforeFootnote()->previous,
1341 cursor.par()->NextAfterFootnote()->next);
1343 /* ok, move to the beginning of the footnote. */
1344 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1345 cursor.par(cursor.par()->Previous());
1347 SetCursor(bview, cursor.par(), cursor.par()->Last());
1348 /* this is just faster than using CursorLeft(); */
1350 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1351 tmppar = firsttmppar;
1352 /* tmppar is now the paragraph right before the footnote */
1354 bool first_footnote_par_is_not_empty = tmppar->next->size();
1357 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1358 tmppar = tmppar->next; /* I use next instead of Next(),
1359 * because there cannot be any
1360 * footnotes in a footnote
1362 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1364 /* remember the captions and empty paragraphs */
1365 if ((textclasslist.Style(bview->buffer()->params.textclass,
1366 tmppar->GetLayout())
1367 .labeltype == LABEL_SENSITIVE)
1369 tmppar->SetLayout(bview->buffer()->params, 0);
1372 // now we will paste the ex-footnote, if the layouts allow it
1373 // first restore the layout of the paragraph right behind
1376 tmppar->next->MakeSameLayout(cursor.par());
1379 if ((!tmppar->GetLayout() && !tmppar->table)
1381 && (!tmppar->Next()->Last()
1382 || tmppar->Next()->HasSameLayout(tmppar)))) {
1383 if (tmppar->Next()->Last()
1384 && tmppar->Next()->IsLineSeparator(0))
1385 tmppar->Next()->Erase(0);
1386 tmppar->PasteParagraph(bview->buffer()->params);
1389 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1390 * by the pasting of the beginning */
1392 /* then the beginning */
1393 /* if there is no space between the text and the footnote, so we insert
1395 * (only if the previous par and the footnotepar are not empty!) */
1396 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1397 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1398 if (firsttmppar->size()
1399 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1400 && first_footnote_par_is_not_empty) {
1401 firsttmppar->next->InsertChar(0, ' ');
1403 firsttmppar->PasteParagraph(bview->buffer()->params);
1406 /* now redo the paragaphs */
1407 RedoParagraphs(bview, cursor, tmppar);
1409 SetCursor(bview, cursor.par(), cursor.pos());
1411 /* sometimes it can happen, that there is a counter change */
1412 Row * row = cursor.row();
1413 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1415 UpdateCounters(bview, row);
1423 /* the DTP switches for paragraphs. LyX will store them in the
1424 * first physicla paragraph. When a paragraph is broken, the top settings
1425 * rest, the bottom settings are given to the new one. So I can make shure,
1426 * they do not duplicate themself and you cannnot make dirty things with
1429 void LyXText::SetParagraph(BufferView * bview,
1430 bool line_top, bool line_bottom,
1431 bool pagebreak_top, bool pagebreak_bottom,
1432 VSpace const & space_top,
1433 VSpace const & space_bottom,
1435 string labelwidthstring,
1438 LyXCursor tmpcursor = cursor;
1440 sel_start_cursor = cursor;
1441 sel_end_cursor = cursor;
1444 // make sure that the depth behind the selection are restored, too
1446 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1448 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1450 LyXParagraph * undoendpar = endpar;
1452 if (endpar && endpar->GetDepth()) {
1453 while (endpar && endpar->GetDepth()) {
1455 endpar = endpar->LastPhysicalPar()->Next();
1457 endpar = endpar->Next();
1459 undoendpar = endpar;
1463 endpar = endpar->Next(); // because of parindents etc.
1466 SetUndo(bview->buffer(), Undo::EDIT,
1469 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1471 sel_start_cursor.par()->previous,
1476 LyXParagraph * tmppar = sel_end_cursor.par();
1478 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1479 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1481 while (tmppar != sel_start_cursor.par()->Previous()) {
1482 SetCursor(bview, tmppar, 0);
1484 status = LyXText::NEED_MORE_REFRESH;
1485 refresh_row = cursor.row();
1486 refresh_y = cursor.y() - cursor.row()->baseline();
1488 if (cursor.par()->footnoteflag ==
1489 sel_start_cursor.par()->footnoteflag) {
1491 cursor.par()->line_top = line_top;
1492 cursor.par()->line_bottom = line_bottom;
1493 cursor.par()->pagebreak_top = pagebreak_top;
1494 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1495 cursor.par()->added_space_top = space_top;
1496 cursor.par()->added_space_bottom = space_bottom;
1497 // does the layout allow the new alignment?
1498 if (align == LYX_ALIGN_LAYOUT)
1499 align = textclasslist
1500 .Style(bview->buffer()->params.textclass,
1501 cursor.par()->GetLayout()).align;
1502 if (align & textclasslist
1503 .Style(bview->buffer()->params.textclass,
1504 cursor.par()->GetLayout()).alignpossible) {
1505 if (align == textclasslist
1506 .Style(bview->buffer()->params.textclass,
1507 cursor.par()->GetLayout()).align)
1508 cursor.par()->align = LYX_ALIGN_LAYOUT;
1510 cursor.par()->align = align;
1512 cursor.par()->SetLabelWidthString(labelwidthstring);
1513 cursor.par()->noindent = noindent;
1517 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1519 tmppar = cursor.par()->Previous();
1523 RedoParagraphs(bview, sel_start_cursor, endpar);
1526 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1527 sel_cursor = cursor;
1528 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1530 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1532 bview->updateInset(inset_owner, true);
1536 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1538 char const * widthp,
1539 int alignment, bool hfill,
1540 bool start_minipage)
1542 LyXCursor tmpcursor = cursor;
1543 LyXParagraph * tmppar;
1545 sel_start_cursor = cursor;
1546 sel_end_cursor = cursor;
1549 // make sure that the depth behind the selection are restored, too
1551 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1553 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1555 LyXParagraph * undoendpar = endpar;
1557 if (endpar && endpar->GetDepth()) {
1558 while (endpar && endpar->GetDepth()) {
1560 endpar = endpar->LastPhysicalPar()->Next();
1562 endpar = endpar->Next();
1564 undoendpar = endpar;
1568 endpar = endpar->Next(); // because of parindents etc.
1571 SetUndo(bview->buffer(), Undo::EDIT,
1574 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1576 sel_start_cursor.par()->previous,
1580 tmppar = sel_end_cursor.par();
1582 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1583 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1585 while(tmppar != sel_start_cursor.par()->Previous()) {
1586 SetCursor(bview, tmppar, 0);
1588 status = LyXText::NEED_MORE_REFRESH;
1589 refresh_row = cursor.row();
1590 refresh_y = cursor.y() - cursor.row()->baseline();
1592 if (cursor.par()->footnoteflag ==
1593 sel_start_cursor.par()->footnoteflag) {
1595 if (type == LyXParagraph::PEXTRA_NONE) {
1596 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1597 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1598 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1601 cursor.par()->SetPExtraType(bview->buffer()->params,
1602 type, width, widthp);
1603 cursor.par()->pextra_hfill = hfill;
1604 cursor.par()->pextra_start_minipage = start_minipage;
1605 cursor.par()->pextra_alignment = alignment;
1609 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1611 tmppar = cursor.par()->Previous();
1614 RedoParagraphs(bview, sel_start_cursor, endpar);
1616 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1617 sel_cursor = cursor;
1618 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1620 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1624 char loweralphaCounter(int n)
1626 if (n < 1 || n > 26)
1633 char alphaCounter(int n)
1635 if (n < 1 || n > 26)
1642 char hebrewCounter(int n)
1644 static const char hebrew[22] = {
1645 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1646 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1647 '÷', 'ø', 'ù', 'ú'
1649 if (n < 1 || n > 22)
1657 char const * romanCounter(int n)
1659 static char const * roman[20] = {
1660 "i", "ii", "iii", "iv", "v",
1661 "vi", "vii", "viii", "ix", "x",
1662 "xi", "xii", "xiii", "xiv", "xv",
1663 "xvi", "xvii", "xviii", "xix", "xx"
1665 if (n < 1 || n > 20)
1672 // set the counter of a paragraph. This includes the labels
1673 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1676 // this is only relevant for the beginning of paragraph
1677 par = par->FirstPhysicalPar();
1679 LyXLayout const & layout =
1680 textclasslist.Style(buf->params.textclass,
1683 LyXTextClass const & textclass =
1684 textclasslist.TextClass(buf->params.textclass);
1686 /* copy the prev-counters to this one, unless this is the start of a
1687 footnote or of a bibliography or the very first paragraph */
1690 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1691 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1692 && par->footnotekind == LyXParagraph::FOOTNOTE)
1694 && !(textclasslist.Style(buf->params.textclass,
1695 par->Previous()->GetLayout()
1696 ).labeltype != LABEL_BIBLIO
1697 && layout.labeltype == LABEL_BIBLIO)) {
1698 for (int i = 0; i < 10; ++i) {
1699 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1702 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1704 par->appendix = par->Previous()->appendix;
1706 if (!par->appendix && par->start_of_appendix){
1707 par->appendix = true;
1708 for (int i = 0; i < 10; ++i) {
1709 par->setCounter(i, 0);
1713 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1714 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1716 par->enumdepth = par->Previous()->enumdepth;
1717 par->itemdepth = par->Previous()->itemdepth;
1720 for (int i = 0; i < 10; ++i) {
1721 par->setCounter(i, 0);
1723 par->appendix = par->start_of_appendix;
1729 // if this is an open marginnote and this is the first
1730 // entry in the marginnote and the enclosing
1731 // environment is an enum/item then correct for the
1732 // LaTeX behaviour (ARRae)
1733 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1734 && par->footnotekind == LyXParagraph::MARGIN
1736 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1737 && (par->PreviousBeforeFootnote()
1738 && textclasslist.Style(buf->params.textclass,
1739 par->PreviousBeforeFootnote()->GetLayout()
1740 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1741 // Any itemize or enumerate environment in a marginnote
1742 // that is embedded in an itemize or enumerate
1743 // paragraph is seen by LaTeX as being at a deeper
1744 // level within that enclosing itemization/enumeration
1745 // even if there is a "standard" layout at the start of
1751 /* Maybe we have to increment the enumeration depth.
1752 * BUT, enumeration in a footnote is considered in isolation from its
1753 * surrounding paragraph so don't increment if this is the
1754 * first line of the footnote
1755 * AND, bibliographies can't have their depth changed ie. they
1756 * are always of depth 0
1759 && par->Previous()->GetDepth() < par->GetDepth()
1760 && textclasslist.Style(buf->params.textclass,
1761 par->Previous()->GetLayout()
1762 ).labeltype == LABEL_COUNTER_ENUMI
1763 && par->enumdepth < 3
1765 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1766 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1767 && par->footnotekind == LyXParagraph::FOOTNOTE)
1769 && layout.labeltype != LABEL_BIBLIO) {
1773 /* Maybe we have to decrement the enumeration depth, see note above */
1775 && par->Previous()->GetDepth() > par->GetDepth()
1777 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1778 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1779 && par->footnotekind == LyXParagraph::FOOTNOTE)
1781 && layout.labeltype != LABEL_BIBLIO) {
1782 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1783 par->setCounter(6 + par->enumdepth,
1784 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1785 /* reset the counters.
1786 * A depth change is like a breaking layout
1788 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1789 par->setCounter(i, 0);
1792 if (!par->labelstring.empty()) {
1793 par->labelstring.erase();
1796 if (layout.margintype == MARGIN_MANUAL) {
1797 if (par->labelwidthstring.empty()) {
1798 par->SetLabelWidthString(layout.labelstring());
1801 par->SetLabelWidthString(string());
1804 /* is it a layout that has an automatic label ? */
1805 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1807 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1808 if (i >= 0 && i<= buf->params.secnumdepth) {
1809 par->incCounter(i); // increment the counter
1811 // Is there a label? Useful for Chapter layout
1812 if (!par->appendix){
1813 if (!layout.labelstring().empty())
1814 par->labelstring = layout.labelstring();
1816 par->labelstring.erase();
1818 if (!layout.labelstring_appendix().empty())
1819 par->labelstring = layout.labelstring_appendix();
1821 par->labelstring.erase();
1825 std::ostringstream s;
1829 if (!par->appendix) {
1830 switch (2 * LABEL_COUNTER_CHAPTER -
1831 textclass.maxcounter() + i) {
1832 case LABEL_COUNTER_CHAPTER:
1833 s << par->getCounter(i);
1835 case LABEL_COUNTER_SECTION:
1836 s << par->getCounter(i - 1) << '.'
1837 << par->getCounter(i);
1839 case LABEL_COUNTER_SUBSECTION:
1840 s << par->getCounter(i - 2) << '.'
1841 << par->getCounter(i - 1) << '.'
1842 << par->getCounter(i);
1844 case LABEL_COUNTER_SUBSUBSECTION:
1845 s << par->getCounter(i - 3) << '.'
1846 << par->getCounter(i - 2) << '.'
1847 << par->getCounter(i - 1) << '.'
1848 << par->getCounter(i);
1851 case LABEL_COUNTER_PARAGRAPH:
1852 s << par->getCounter(i - 4) << '.'
1853 << par->getCounter(i - 3) << '.'
1854 << par->getCounter(i - 2) << '.'
1855 << par->getCounter(i - 1) << '.'
1856 << par->getCounter(i);
1858 case LABEL_COUNTER_SUBPARAGRAPH:
1859 s << par->getCounter(i - 5) << '.'
1860 << par->getCounter(i - 4) << '.'
1861 << par->getCounter(i - 3) << '.'
1862 << par->getCounter(i - 2) << '.'
1863 << par->getCounter(i - 1) << '.'
1864 << par->getCounter(i);
1868 // Can this ever be reached? And in the
1869 // case it is, how can this be correct?
1871 s << par->getCounter(i) << '.';
1874 } else { // appendix
1875 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1876 case LABEL_COUNTER_CHAPTER:
1877 if (par->isRightToLeftPar(buf->params))
1878 s << hebrewCounter(par->getCounter(i));
1880 s << alphaCounter(par->getCounter(i));
1882 case LABEL_COUNTER_SECTION:
1883 if (par->isRightToLeftPar(buf->params))
1884 s << hebrewCounter(par->getCounter(i - 1));
1886 s << alphaCounter(par->getCounter(i - 1));
1889 << par->getCounter(i);
1892 case LABEL_COUNTER_SUBSECTION:
1893 if (par->isRightToLeftPar(buf->params))
1894 s << hebrewCounter(par->getCounter(i - 2));
1896 s << alphaCounter(par->getCounter(i - 2));
1899 << par->getCounter(i-1) << '.'
1900 << par->getCounter(i);
1903 case LABEL_COUNTER_SUBSUBSECTION:
1904 if (par->isRightToLeftPar(buf->params))
1905 s << hebrewCounter(par->getCounter(i-3));
1907 s << alphaCounter(par->getCounter(i-3));
1910 << par->getCounter(i-2) << '.'
1911 << par->getCounter(i-1) << '.'
1912 << par->getCounter(i);
1915 case LABEL_COUNTER_PARAGRAPH:
1916 if (par->isRightToLeftPar(buf->params))
1917 s << hebrewCounter(par->getCounter(i-4));
1919 s << alphaCounter(par->getCounter(i-4));
1922 << par->getCounter(i-3) << '.'
1923 << par->getCounter(i-2) << '.'
1924 << par->getCounter(i-1) << '.'
1925 << par->getCounter(i);
1928 case LABEL_COUNTER_SUBPARAGRAPH:
1929 if (par->isRightToLeftPar(buf->params))
1930 s << hebrewCounter(par->getCounter(i-5));
1932 s << alphaCounter(par->getCounter(i-5));
1935 << par->getCounter(i-4) << '.'
1936 << par->getCounter(i-3) << '.'
1937 << par->getCounter(i-2) << '.'
1938 << par->getCounter(i-1) << '.'
1939 << par->getCounter(i);
1943 // Can this ever be reached? And in the
1944 // case it is, how can this be correct?
1946 s << par->getCounter(i) << '.';
1952 par->labelstring += s.str().c_str();
1953 // We really want to remove the c_str as soon as
1957 char * tmps = s.str();
1958 par->labelstring += tmps;
1962 for (i++; i < 10; ++i) {
1963 // reset the following counters
1964 par->setCounter(i, 0);
1966 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1967 for (i++; i < 10; ++i) {
1968 // reset the following counters
1969 par->setCounter(i, 0);
1971 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1972 par->incCounter(i + par->enumdepth);
1973 int number = par->getCounter(i + par->enumdepth);
1976 std::ostringstream s;
1980 switch (par->enumdepth) {
1982 if (par->isRightToLeftPar(buf->params))
1984 << hebrewCounter(number)
1988 << loweralphaCounter(number)
1992 if (par->isRightToLeftPar(buf->params))
1993 s << '.' << romanCounter(number);
1995 s << romanCounter(number) << '.';
1998 if (par->isRightToLeftPar(buf->params))
2000 << alphaCounter(number);
2002 s << alphaCounter(number)
2006 if (par->isRightToLeftPar(buf->params))
2013 par->labelstring = s.str().c_str();
2014 // we really want to get rid of that c_str()
2017 char * tmps = s.str();
2018 par->labelstring = tmps;
2022 for (i += par->enumdepth + 1; i < 10; ++i)
2023 par->setCounter(i, 0); /* reset the following counters */
2026 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2027 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2029 int number = par->getCounter(i);
2031 par->bibkey = new InsetBibKey();
2032 par->bibkey->setCounter(number);
2033 par->labelstring = layout.labelstring();
2035 // In biblio should't be following counters but...
2037 string s = layout.labelstring();
2039 // the caption hack:
2040 if (layout.labeltype == LABEL_SENSITIVE) {
2041 bool isOK (par->InInset() && par->InInset()->owner() &&
2042 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2044 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2045 && (par->footnotekind == LyXParagraph::FIG
2046 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2047 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2048 ? ":øåéà " : "Figure:";
2049 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2050 && (par->footnotekind == LyXParagraph::TAB
2051 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2052 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2053 ? ":äìáè" : "Table:";
2054 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2055 && par->footnotekind == LyXParagraph::ALGORITHM) {
2056 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2057 ? ":Ãúéøåâìà " : "Algorithm:";
2061 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2063 = floatList.getType(tmp->type());
2064 // We should get the correct number here too.
2065 s = fl.name + " #:";
2067 /* par->SetLayout(0);
2068 s = layout->labelstring; */
2069 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2070 ? " :úåòîùî øñç" : "Senseless: ";
2073 par->labelstring = s;
2075 /* reset the enumeration counter. They are always resetted
2076 * when there is any other layout between */
2077 for (int i = 6 + par->enumdepth; i < 10; ++i)
2078 par->setCounter(i, 0);
2083 /* Updates all counters BEHIND the row. Changed paragraphs
2084 * with a dynamic left margin will be rebroken. */
2085 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2092 if (row->par()->next
2094 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2098 par = row->par()->LastPhysicalPar()->Next();
2100 par = row->par()->Next();
2103 par = row->par()->next;
2108 while (row->par() != par)
2111 SetCounter(bview->buffer(), par);
2113 /* now check for the headline layouts. remember that they
2114 * have a dynamic left margin */
2119 ( textclasslist.Style(bview->buffer()->params.textclass,
2120 par->layout).margintype == MARGIN_DYNAMIC
2121 || textclasslist.Style(bview->buffer()->params.textclass,
2122 par->layout).labeltype == LABEL_SENSITIVE)
2125 /* Rebreak the paragraph */
2126 RemoveParagraph(row);
2127 AppendParagraph(bview, row);
2130 /* think about the damned open footnotes! */
2131 while (par->Next() &&
2132 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2133 || par->Next()->IsDummy())){
2135 if (par->IsDummy()) {
2136 while (row->par() != par)
2138 RemoveParagraph(row);
2139 AppendParagraph(bview, row);
2145 par = par->LastPhysicalPar()->Next();
2154 /* insets an inset. */
2155 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2157 if (!cursor.par()->InsertInsetAllowed(inset))
2159 SetUndo(bview->buffer(), Undo::INSERT,
2161 cursor.par()->ParFromPos(cursor.pos())->previous,
2162 cursor.par()->ParFromPos(cursor.pos())->next
2164 cursor.par()->previous,
2168 cursor.par()->InsertInset(cursor.pos(), inset);
2169 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2170 * The character will not be inserted a
2175 void LyXText::copyEnvironmentType()
2177 copylayouttype = cursor.par()->GetLayout();
2181 void LyXText::pasteEnvironmentType(BufferView * bview)
2183 SetLayout(bview, copylayouttype);
2187 void LyXText::CutSelection(BufferView * bview, bool doclear)
2189 // Stuff what we got on the clipboard. Even if there is no selection.
2191 // There is a problem with having the stuffing here in that the
2192 // larger the selection the slower LyX will get. This can be
2193 // solved by running the line below only when the selection has
2194 // finished. The solution used currently just works, to make it
2195 // faster we need to be more clever and probably also have more
2196 // calls to stuffClipboard. (Lgb)
2197 bview->stuffClipboard(selectionAsString(bview->buffer()));
2199 // This doesn't make sense, if there is no selection
2203 // OK, we have a selection. This is always between sel_start_cursor
2204 // and sel_end cursor
2206 // Check whether there are half footnotes in the selection
2207 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2208 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2209 LyXParagraph * tmppar = sel_start_cursor.par();
2210 while (tmppar != sel_end_cursor.par()){
2211 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2212 WriteAlert(_("Impossible operation"),
2213 _("Don't know what to do with half floats."),
2217 tmppar = tmppar->Next();
2222 /* table stuff -- begin */
2223 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2224 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2225 WriteAlert(_("Impossible operation"),
2226 _("Don't know what to do with half tables."),
2230 sel_start_cursor.par()->table->Reinit();
2232 /* table stuff -- end */
2234 // make sure that the depth behind the selection are restored, too
2236 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2238 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2240 LyXParagraph * undoendpar = endpar;
2242 if (endpar && endpar->GetDepth()) {
2243 while (endpar && endpar->GetDepth()) {
2245 endpar = endpar->LastPhysicalPar()->Next();
2247 endpar = endpar->Next();
2249 undoendpar = endpar;
2251 } else if (endpar) {
2252 endpar = endpar->Next(); // because of parindents etc.
2255 SetUndo(bview->buffer(), Undo::DELETE,
2258 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2260 sel_start_cursor.par()->previous,
2266 // there are two cases: cut only within one paragraph or
2267 // more than one paragraph
2269 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2270 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2272 if (sel_start_cursor.par() == sel_end_cursor.par())
2275 // only within one paragraph
2276 endpar = sel_start_cursor.par();
2277 int pos = sel_end_cursor.pos();
2278 cap.cutSelection(sel_start_cursor.par(), &endpar,
2279 sel_start_cursor.pos(), pos,
2280 bview->buffer()->params.textclass, doclear);
2281 sel_end_cursor.pos(pos);
2283 endpar = sel_end_cursor.par();
2285 int pos = sel_end_cursor.pos();
2286 cap.cutSelection(sel_start_cursor.par(), &endpar,
2287 sel_start_cursor.pos(), pos,
2288 bview->buffer()->params.textclass, doclear);
2290 sel_end_cursor.par(endpar);
2291 sel_end_cursor.pos(pos);
2292 cursor.pos(sel_end_cursor.pos());
2294 endpar = endpar->Next();
2296 // sometimes necessary
2298 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2300 RedoParagraphs(bview, sel_start_cursor, endpar);
2303 cursor = sel_start_cursor;
2304 SetCursor(bview, cursor.par(), cursor.pos());
2305 sel_cursor = cursor;
2306 UpdateCounters(bview, cursor.row());
2310 void LyXText::CopySelection(BufferView * bview)
2312 // Stuff what we got on the clipboard. Even if there is no selection.
2314 // There is a problem with having the stuffing here in that the
2315 // larger the selection the slower LyX will get. This can be
2316 // solved by running the line below only when the selection has
2317 // finished. The solution used currently just works, to make it
2318 // faster we need to be more clever and probably also have more
2319 // calls to stuffClipboard. (Lgb)
2320 bview->stuffClipboard(selectionAsString(bview->buffer()));
2322 // this doesnt make sense, if there is no selection
2326 // ok we have a selection. This is always between sel_start_cursor
2327 // and sel_end cursor
2330 /* check wether there are half footnotes in the selection */
2331 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2332 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2333 LyXParagraph * tmppar = sel_start_cursor.par();
2334 while (tmppar != sel_end_cursor.par()) {
2335 if (tmppar->footnoteflag !=
2336 sel_end_cursor.par()->footnoteflag) {
2337 WriteAlert(_("Impossible operation"),
2338 _("Don't know what to do"
2339 " with half floats."),
2343 tmppar = tmppar->Next();
2348 /* table stuff -- begin */
2349 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2350 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2351 WriteAlert(_("Impossible operation"),
2352 _("Don't know what to do with half tables."),
2357 /* table stuff -- end */
2360 // copy behind a space if there is one
2361 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2362 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2363 && (sel_start_cursor.par() != sel_end_cursor.par()
2364 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2365 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2369 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2370 sel_start_cursor.pos(), sel_end_cursor.pos(),
2371 bview->buffer()->params.textclass);
2375 void LyXText::PasteSelection(BufferView * bview)
2379 // this does not make sense, if there is nothing to paste
2380 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2383 SetUndo(bview->buffer(), Undo::INSERT,
2385 cursor.par()->ParFromPos(cursor.pos())->previous,
2386 cursor.par()->ParFromPos(cursor.pos())->next
2388 cursor.par()->previous,
2393 LyXParagraph * endpar;
2394 LyXParagraph * actpar = cursor.par();
2396 int pos = cursor.pos();
2397 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2399 RedoParagraphs(bview, cursor, endpar);
2401 SetCursor(bview, cursor.par(), cursor.pos());
2404 sel_cursor = cursor;
2405 SetCursor(bview, actpar, pos);
2407 UpdateCounters(bview, cursor.row());
2411 // returns a pointer to the very first LyXParagraph
2412 LyXParagraph * LyXText::FirstParagraph() const
2414 return OwnerParagraph();
2418 // returns true if the specified string is at the specified position
2419 bool LyXText::IsStringInText(LyXParagraph * par,
2420 LyXParagraph::size_type pos,
2421 char const * str) const
2425 while (pos + i < par->Last() && str[i] &&
2426 str[i] == par->GetChar(pos + i)) {
2436 // sets the selection over the number of characters of string, no check!!
2437 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2439 sel_cursor = cursor;
2440 for (int i = 0; string[i]; ++i)
2446 // simple replacing. The font of the first selected character is used
2447 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2449 SetCursorParUndo(bview->buffer());
2452 if (!selection) { // create a dummy selection
2453 sel_end_cursor = cursor;
2454 sel_start_cursor = cursor;
2457 // Get font setting before we cut
2458 LyXParagraph::size_type pos = sel_end_cursor.pos();
2459 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2460 sel_start_cursor.pos());
2462 // Insert the new string
2463 for (int i = 0; str[i]; ++i) {
2464 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2468 // Cut the selection
2469 CutSelection(bview);
2475 // if the string can be found: return true and set the cursor to
2477 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2479 LyXParagraph * par = cursor.par();
2480 LyXParagraph::size_type pos = cursor.pos();
2481 while (par && !IsStringInText(par, pos, str)) {
2482 if (pos < par->Last() - 1)
2490 SetCursor(bview, par, pos);
2498 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2500 LyXParagraph * par = cursor.par();
2501 int pos = cursor.pos();
2507 // We skip empty paragraphs (Asger)
2509 par = par->Previous();
2511 pos = par->Last() - 1;
2512 } while (par && pos < 0);
2514 } while (par && !IsStringInText(par, pos, string));
2517 SetCursor(bview, par, pos);
2524 // needed to insert the selection
2525 void LyXText::InsertStringA(BufferView * bview, string const & str)
2527 LyXParagraph * par = cursor.par();
2528 LyXParagraph::size_type pos = cursor.pos();
2529 LyXParagraph::size_type a = 0;
2530 LyXParagraph * endpar = cursor.par()->Next();
2532 SetCursorParUndo(bview->buffer());
2535 textclasslist.Style(bview->buffer()->params.textclass,
2536 cursor.par()->GetLayout()).isEnvironment();
2537 // only to be sure, should not be neccessary
2540 // insert the string, don't insert doublespace
2541 string::size_type i = 0;
2542 while (i < str.length()) {
2543 if (str[i] != '\n') {
2545 && i + 1 < str.length() && str[i + 1] != ' '
2546 && pos && par->GetChar(pos - 1)!= ' ') {
2547 par->InsertChar(pos, ' ', current_font);
2550 } else if (par->table) {
2551 if (str[i] == '\t') {
2552 while((pos < par->size()) &&
2553 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2555 if (pos < par->size())
2557 else // no more fields to fill skip the rest
2559 } else if ((str[i] != 13) &&
2560 ((str[i] & 127) >= ' ')) {
2561 par->InsertChar(pos, str[i],
2566 } else if (str[i] == ' ') {
2567 InsetSpecialChar * new_inset =
2568 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2569 if (par->InsertInsetAllowed(new_inset)) {
2570 par->InsertInset(pos, new_inset,
2576 } else if (str[i] == '\t') {
2577 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2578 InsetSpecialChar * new_inset =
2579 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2580 if (par->InsertInsetAllowed(new_inset)) {
2581 par->InsertInset(pos, new_inset,
2588 } else if (str[i] != 13 &&
2589 // Ignore unprintables
2590 (str[i] & 127) >= ' ') {
2591 par->InsertChar(pos, str[i], current_font);
2597 if ((i + 1) >= str.length()) {
2598 if (pos < par->size())
2602 while((pos < par->size()) &&
2603 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2606 int cell = NumberOfCell(par, pos);
2607 while((pos < par->size()) &&
2608 !(par->table->IsFirstCell(cell))) {
2610 while((pos < par->size()) &&
2611 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2614 cell = NumberOfCell(par, pos);
2616 if (pos >= par->size())
2617 // no more fields to fill skip the rest
2621 if (!par->size()) { // par is empty
2622 InsetSpecialChar * new_inset =
2623 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2624 if (par->InsertInsetAllowed(new_inset)) {
2625 par->InsertInset(pos,
2633 par->BreakParagraph(bview->buffer()->params, pos, flag);
2643 RedoParagraphs(bview, cursor, endpar);
2644 SetCursor(bview, cursor.par(), cursor.pos());
2645 sel_cursor = cursor;
2646 SetCursor(bview, par, pos);
2651 /* turns double-CR to single CR, others where converted into one blank and 13s
2652 * that are ignored .Double spaces are also converted into one. Spaces at
2653 * the beginning of a paragraph are forbidden. tabs are converted into one
2654 * space. then InsertStringA is called */
2655 void LyXText::InsertStringB(BufferView * bview, string const & s)
2659 LyXParagraph * par = cursor.par();
2661 string::size_type i = 1;
2662 while (i < str.length()) {
2669 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2671 if (str[i] == '\n' && i + 1 < str.length()
2676 if (str[i + 1] != '\n') {
2677 if (str[i - 1] != ' ')
2682 while (i + 1 < str.length()
2683 && (str[i + 1] == ' '
2684 || str[i + 1] == '\t'
2685 || str[i + 1] == '\n'
2686 || str[i + 1] == 13)) {
2693 InsertStringA(bview, str);
2697 bool LyXText::GotoNextError(BufferView * bview) const
2699 LyXCursor res = cursor;
2701 if (res.pos() < res.par()->Last() - 1) {
2702 res.pos(res.pos() + 1);
2704 res.par(res.par()->Next());
2708 } while (res.par() &&
2709 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2710 && res.par()->GetInset(res.pos())->AutoDelete()));
2713 SetCursor(bview, res.par(), res.pos());
2720 bool LyXText::GotoNextNote(BufferView * bview) const
2722 LyXCursor res = cursor;
2724 if (res.pos() < res.par()->Last() - 1) {
2725 res.pos(res.pos() + 1);
2727 res.par(res.par()->Next());
2731 } while (res.par() &&
2732 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2733 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2736 SetCursor(bview, res.par(), res.pos());
2743 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2744 LyXParagraph::size_type pos)
2746 LyXCursor tmpcursor;
2749 /* table stuff -- begin*/
2752 CheckParagraphInTable(bview, par, pos);
2756 /* table stuff -- end*/
2759 LyXParagraph::size_type z;
2760 Row * row = GetRow(par, pos, y);
2762 // is there a break one row above
2763 if (row->previous() && row->previous()->par() == row->par()) {
2764 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2765 if ( z >= row->pos()) {
2766 // set the dimensions of the row above
2767 y -= row->previous()->height();
2769 refresh_row = row->previous();
2770 status = LyXText::NEED_MORE_REFRESH;
2772 BreakAgain(bview, row->previous());
2774 // set the cursor again. Otherwise
2775 // dangling pointers are possible
2776 SetCursor(bview, cursor.par(), cursor.pos());
2777 sel_cursor = cursor;
2782 int tmpheight = row->height();
2783 LyXParagraph::size_type tmplast = RowLast(row);
2787 BreakAgain(bview, row);
2788 if (row->height() == tmpheight && RowLast(row) == tmplast)
2789 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2791 status = LyXText::NEED_MORE_REFRESH;
2793 // check the special right address boxes
2794 if (textclasslist.Style(bview->buffer()->params.textclass,
2795 par->GetLayout()).margintype
2796 == MARGIN_RIGHT_ADDRESS_BOX) {
2803 RedoDrawingOfParagraph(bview, tmpcursor);
2809 // set the cursor again. Otherwise dangling pointers are possible
2810 // also set the selection
2814 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2815 sel_cursor = cursor;
2816 SetCursorIntern(bview, sel_start_cursor.par(),
2817 sel_start_cursor.pos());
2818 sel_start_cursor = cursor;
2819 SetCursorIntern(bview, sel_end_cursor.par(),
2820 sel_end_cursor.pos());
2821 sel_end_cursor = cursor;
2822 SetCursorIntern(bview, last_sel_cursor.par(),
2823 last_sel_cursor.pos());
2824 last_sel_cursor = cursor;
2827 SetCursorIntern(bview, cursor.par(), cursor.pos());
2831 // returns false if inset wasn't found
2832 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2834 // first check the current paragraph
2835 int pos = cursor.par()->GetPositionOfInset(inset);
2837 CheckParagraph(bview, cursor.par(), pos);
2841 // check every paragraph
2843 LyXParagraph * par = FirstParagraph();
2846 // make sure the paragraph is open
2847 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2849 pos = par->GetPositionOfInset(inset);
2851 CheckParagraph(bview, par, pos);
2864 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2865 LyXParagraph::size_type pos,
2866 bool setfont, bool boundary) const
2868 LyXCursor old_cursor = cursor;
2869 SetCursorIntern(bview, par, pos, setfont, boundary);
2870 DeleteEmptyParagraphMechanism(bview, old_cursor);
2874 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2875 LyXParagraph::size_type pos, bool boundary) const
2878 // correct the cursor position if impossible
2879 if (pos > par->Last()){
2880 LyXParagraph * tmppar = par->ParFromPos(pos);
2881 pos = par->PositionInParFromPos(pos);
2884 if (par->IsDummy() && par->previous &&
2885 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2886 while (par->previous &&
2887 ((par->previous->IsDummy() &&
2888 (par->previous->previous->footnoteflag ==
2889 LyXParagraph::CLOSED_FOOTNOTE)) ||
2890 (par->previous->footnoteflag ==
2891 LyXParagraph::CLOSED_FOOTNOTE))) {
2892 par = par->previous ;
2893 if (par->IsDummy() &&
2894 (par->previous->footnoteflag ==
2895 LyXParagraph::CLOSED_FOOTNOTE))
2896 pos += par->size() + 1;
2898 if (par->previous) {
2899 par = par->previous;
2901 pos += par->size() + 1;
2906 cur.boundary(boundary);
2908 /* get the cursor y position in text */
2910 Row * row = GetRow(par, pos, y);
2911 /* y is now the beginning of the cursor row */
2912 y += row->baseline();
2913 /* y is now the cursor baseline */
2916 /* now get the cursors x position */
2918 float fill_separator, fill_hfill, fill_label_hfill;
2919 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2921 LyXParagraph::size_type cursor_vpos = 0;
2922 LyXParagraph::size_type last = RowLastPrintable(row);
2924 if (pos > last + 1) // This shouldn't happen.
2926 else if (pos < row->pos())
2929 if (last < row->pos())
2930 cursor_vpos = row->pos();
2931 else if (pos > last && !boundary)
2932 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2933 ? row->pos() : last + 1;
2934 else if (pos > row->pos() &&
2935 (pos > last || boundary
2937 || (row->par()->table && row->par()->IsNewline(pos))
2940 /// Place cursor after char at (logical) position pos - 1
2941 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2942 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2944 /// Place cursor before char at (logical) position pos
2945 cursor_vpos = (bidi_level(pos) % 2 == 0)
2946 ? log2vis(pos) : log2vis(pos) + 1;
2949 /* table stuff -- begin*/
2950 if (row->par()->table) {
2951 int cell = NumberOfCell(row->par(), row->pos());
2953 x += row->par()->table->GetBeginningOfTextInCell(cell);
2954 for (LyXParagraph::size_type vpos = row->pos();
2955 vpos < cursor_vpos; ++vpos) {
2956 pos = vis2log(vpos);
2957 if (row->par()->IsNewline(pos)) {
2958 x = x_old + row->par()->table->WidthOfColumn(cell);
2961 x += row->par()->table->GetBeginningOfTextInCell(cell);
2963 x += SingleWidth(bview, row->par(), pos);
2967 /* table stuff -- end*/
2969 LyXParagraph::size_type main_body =
2970 BeginningOfMainBody(bview->buffer(), row->par());
2971 if ((main_body > 0) &&
2972 ((main_body-1 > last) ||
2973 !row->par()->IsLineSeparator(main_body-1)))
2976 for (LyXParagraph::size_type vpos = row->pos();
2977 vpos < cursor_vpos; ++vpos) {
2978 pos = vis2log(vpos);
2979 if (main_body > 0 && pos == main_body-1) {
2980 x += fill_label_hfill +
2981 lyxfont::width(textclasslist.Style(
2982 bview->buffer()->params.textclass,
2983 row->par()->GetLayout())
2985 GetFont(bview->buffer(), row->par(), -2));
2986 if (row->par()->IsLineSeparator(main_body-1))
2987 x -= SingleWidth(bview, row->par(),main_body-1);
2989 if (HfillExpansion(bview->buffer(), row, pos)) {
2990 x += SingleWidth(bview, row->par(), pos);
2991 if (pos >= main_body)
2994 x += fill_label_hfill;
2995 } else if (row->par()->IsSeparator(pos)) {
2996 x += SingleWidth(bview, row->par(), pos);
2997 if (pos >= main_body)
2998 x += fill_separator;
3000 x += SingleWidth(bview, row->par(), pos);
3012 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3013 LyXParagraph::size_type pos,
3014 bool setfont, bool boundary) const
3016 SetCursor(bview, cursor, par, pos, boundary);
3018 SetCurrentFont(bview);
3021 void LyXText::SetCurrentFont(BufferView * bview) const
3023 LyXParagraph::size_type pos = cursor.pos();
3024 if (cursor.boundary() && pos > 0)
3028 if (pos == cursor.par()->Last()
3030 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3034 else if (cursor.par()->IsSeparator(pos)) {
3035 if (pos > cursor.row()->pos() &&
3036 bidi_level(pos) % 2 ==
3037 bidi_level(pos - 1) % 2)
3039 else if (pos + 1 < cursor.par()->Last())
3045 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3046 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3048 if (cursor.pos() == cursor.par()->Last() &&
3049 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3050 !cursor.boundary()) {
3051 Language const * lang =
3052 cursor.par()->getParLanguage(bview->buffer()->params);
3053 current_font.setLanguage(lang);
3054 real_current_font.setLanguage(lang);
3059 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3061 LyXCursor old_cursor = cursor;
3063 /* get the row first */
3065 Row * row = GetRowNearY(y);
3066 cursor.par(row->par());
3069 int column = GetColumnNearX(bview, row, x, bound);
3070 cursor.pos(row->pos() + column);
3072 cursor.y(y + row->baseline());
3074 cursor.boundary(bound);
3075 SetCurrentFont(bview);
3076 DeleteEmptyParagraphMechanism(bview, old_cursor);
3080 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3081 int x, long y) const
3083 /* get the row first */
3085 Row * row = GetRowNearY(y);
3087 int column = GetColumnNearX(bview, row, x, bound);
3089 cur.par(row->par());
3090 cur.pos(row->pos() + column);
3092 cur.y(y + row->baseline());
3094 cur.boundary(bound);
3098 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3100 CursorLeftIntern(bview, internal);
3102 if (cursor.par()->table) {
3103 int cell = NumberOfCell(cursor.par(), cursor.pos());
3104 if (cursor.par()->table->IsContRow(cell)
3105 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3113 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3115 if (cursor.pos() > 0) {
3116 bool boundary = cursor.boundary();
3117 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3118 if (!internal && !boundary &&
3119 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3120 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3121 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3122 LyXParagraph * par = cursor.par()->Previous();
3123 SetCursor(bview, par, par->Last());
3128 void LyXText::CursorRight(BufferView * bview, bool internal) const
3130 CursorRightIntern(bview, internal);
3132 if (cursor.par()->table) {
3133 int cell = NumberOfCell(cursor.par(), cursor.pos());
3134 if (cursor.par()->table->IsContRow(cell) &&
3135 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3143 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3145 if (!internal && cursor.boundary() &&
3148 !cursor.par()->table ||
3150 !cursor.par()->IsNewline(cursor.pos())))
3151 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3152 else if (cursor.pos() < cursor.par()->Last()) {
3153 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3155 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3156 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3157 } else if (cursor.par()->Next())
3158 SetCursor(bview, cursor.par()->Next(), 0);
3162 void LyXText::CursorUp(BufferView * bview) const
3164 SetCursorFromCoordinates(bview, cursor.x_fix(),
3165 cursor.y() - cursor.row()->baseline() - 1);
3167 if (cursor.par()->table) {
3168 int cell = NumberOfCell(cursor.par(), cursor.pos());
3169 if (cursor.par()->table->IsContRow(cell) &&
3170 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3178 void LyXText::CursorDown(BufferView * bview) const
3181 if (cursor.par()->table &&
3182 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3183 !cursor.par()->next)
3187 SetCursorFromCoordinates(bview, cursor.x_fix(),
3188 cursor.y() - cursor.row()->baseline()
3189 + cursor.row()->height() + 1);
3191 if (cursor.par()->table) {
3192 int cell = NumberOfCell(cursor.par(), cursor.pos());
3193 int cell_above = cursor.par()->table->GetCellAbove(cell);
3194 while(cursor.par()->table &&
3195 cursor.par()->table->IsContRow(cell) &&
3196 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3197 SetCursorFromCoordinates(bview, cursor.x_fix(),
3198 cursor.y() - cursor.row()->baseline()
3199 + cursor.row()->height() + 1);
3200 if (cursor.par()->table) {
3201 cell = NumberOfCell(cursor.par(), cursor.pos());
3202 cell_above = cursor.par()->table->GetCellAbove(cell);
3210 void LyXText::CursorUpParagraph(BufferView * bview) const
3212 if (cursor.pos() > 0) {
3213 SetCursor(bview, cursor.par(), 0);
3215 else if (cursor.par()->Previous()) {
3216 SetCursor(bview, cursor.par()->Previous(), 0);
3221 void LyXText::CursorDownParagraph(BufferView * bview) const
3223 if (cursor.par()->Next()) {
3224 SetCursor(bview, cursor.par()->Next(), 0);
3226 SetCursor(bview, cursor.par(), cursor.par()->Last());
3231 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3232 LyXCursor const & old_cursor) const
3234 // Would be wrong to delete anything if we have a selection.
3235 if (selection) return;
3237 // We allow all kinds of "mumbo-jumbo" when freespacing.
3238 if (textclasslist.Style(bview->buffer()->params.textclass,
3239 old_cursor.par()->GetLayout()).free_spacing)
3242 bool deleted = false;
3244 /* Ok I'll put some comments here about what is missing.
3245 I have fixed BackSpace (and thus Delete) to not delete
3246 double-spaces automagically. I have also changed Cut,
3247 Copy and Paste to hopefully do some sensible things.
3248 There are still some small problems that can lead to
3249 double spaces stored in the document file or space at
3250 the beginning of paragraphs. This happens if you have
3251 the cursor betwenn to spaces and then save. Or if you
3252 cut and paste and the selection have a space at the
3253 beginning and then save right after the paste. I am
3254 sure none of these are very hard to fix, but I will
3255 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3256 that I can get some feedback. (Lgb)
3259 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3260 // delete the LineSeparator.
3263 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3264 // delete the LineSeparator.
3267 // If the pos around the old_cursor were spaces, delete one of them.
3268 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3269 // Only if the cursor has really moved
3271 if (old_cursor.pos() > 0
3272 && old_cursor.pos() < old_cursor.par()->Last()
3273 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3274 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3275 old_cursor.par()->Erase(old_cursor.pos() - 1);
3276 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3278 if (old_cursor.par() == cursor.par() &&
3279 cursor.pos() > old_cursor.pos()) {
3280 SetCursorIntern(bview, cursor.par(),
3283 SetCursorIntern(bview, cursor.par(),
3289 // Do not delete empty paragraphs with keepempty set.
3290 if ((textclasslist.Style(bview->buffer()->params.textclass,
3291 old_cursor.par()->GetLayout())).keepempty)
3294 LyXCursor tmpcursor;
3296 if (old_cursor.par() != cursor.par()) {
3297 if ( (old_cursor.par()->Last() == 0
3298 || (old_cursor.par()->Last() == 1
3299 && old_cursor.par()->IsLineSeparator(0)))
3301 && old_cursor.par()->FirstPhysicalPar()
3302 == old_cursor.par()->LastPhysicalPar()
3305 // ok, we will delete anything
3307 // make sure that you do not delete any environments
3310 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3311 !(old_cursor.row()->previous()
3312 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3313 && !(old_cursor.row()->next()
3314 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3315 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3316 && ((old_cursor.row()->previous()
3317 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3318 || (old_cursor.row()->next()
3319 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3322 status = LyXText::NEED_MORE_REFRESH;
3325 if (old_cursor.row()->previous()) {
3326 refresh_row = old_cursor.row()->previous();
3327 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3329 cursor = old_cursor; // that undo can restore the right cursor position
3330 LyXParagraph * endpar = old_cursor.par()->next;
3331 if (endpar && endpar->GetDepth()) {
3332 while (endpar && endpar->GetDepth()) {
3334 endpar = endpar->LastPhysicalPar()->Next();
3336 endpar = endpar->Next();
3340 SetUndo(bview->buffer(), Undo::DELETE,
3341 old_cursor.par()->previous,
3346 RemoveRow(old_cursor.row());
3347 if (OwnerParagraph() == old_cursor.par()) {
3348 OwnerParagraph(OwnerParagraph()->next);
3351 delete old_cursor.par();
3353 /* Breakagain the next par. Needed
3354 * because of the parindent that
3355 * can occur or dissappear. The
3356 * next row can change its height,
3357 * if there is another layout before */
3358 if (refresh_row->next()) {
3359 BreakAgain(bview, refresh_row->next());
3360 UpdateCounters(bview, refresh_row);
3362 SetHeightOfRow(bview, refresh_row);
3364 refresh_row = old_cursor.row()->next();
3365 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3368 cursor = old_cursor; // that undo can restore the right cursor position
3369 LyXParagraph * endpar = old_cursor.par()->next;
3370 if (endpar && endpar->GetDepth()) {
3371 while (endpar && endpar->GetDepth()) {
3373 endpar = endpar->LastPhysicalPar()->Next();
3375 endpar = endpar->Next();
3379 SetUndo(bview->buffer(), Undo::DELETE,
3380 old_cursor.par()->previous,
3385 RemoveRow(old_cursor.row());
3387 if (OwnerParagraph() == old_cursor.par()) {
3388 OwnerParagraph(OwnerParagraph()->next);
3390 delete old_cursor.par();
3392 /* Breakagain the next par. Needed
3393 because of the parindent that can
3394 occur or dissappear.
3395 The next row can change its height,
3396 if there is another layout before
3399 BreakAgain(bview, refresh_row);
3400 UpdateCounters(bview, refresh_row->previous());
3406 SetCursorIntern(bview, cursor.par(), cursor.pos());
3408 if (sel_cursor.par() == old_cursor.par()
3409 && sel_cursor.pos() == sel_cursor.pos()) {
3410 // correct selection
3411 sel_cursor = cursor;
3418 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3419 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3421 SetCursorIntern(bview, cursor.par(), cursor.pos());
3422 sel_cursor = cursor;
3429 LyXParagraph * LyXText::GetParFromID(int id)
3431 LyXParagraph * result = FirstParagraph();
3432 while (result && result->id() != id)
3433 result = result->next;
3439 bool LyXText::TextUndo(BufferView * bview)
3443 // returns false if no undo possible
3444 Undo * undo = bview->buffer()->undostack.pop();
3448 bview->buffer()->redostack
3449 .push(CreateUndo(bview->buffer(), undo->kind,
3450 GetParFromID(undo->number_of_before_par),
3451 GetParFromID(undo->number_of_behind_par)));
3453 return TextHandleUndo(bview, undo);
3457 bool LyXText::TextRedo(BufferView * bview)
3461 // returns false if no redo possible
3462 Undo * undo = bview->buffer()->redostack.pop();
3466 bview->buffer()->undostack
3467 .push(CreateUndo(bview->buffer(), undo->kind,
3468 GetParFromID(undo->number_of_before_par),
3469 GetParFromID(undo->number_of_behind_par)));
3471 return TextHandleUndo(bview, undo);
3475 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3479 // returns false if no undo possible
3480 bool result = false;
3482 LyXParagraph * before =
3483 GetParFromID(undo->number_of_before_par);
3484 LyXParagraph * behind =
3485 GetParFromID(undo->number_of_behind_par);
3486 LyXParagraph * tmppar;
3487 LyXParagraph * tmppar2;
3488 LyXParagraph * endpar;
3489 LyXParagraph * tmppar5;
3491 // if there's no before take the beginning
3492 // of the document for redoing
3494 SetCursorIntern(bview, FirstParagraph(), 0);
3496 // replace the paragraphs with the undo informations
3498 LyXParagraph * tmppar3 = undo->par;
3499 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3500 LyXParagraph * tmppar4 = tmppar3;
3502 while (tmppar4->next)
3503 tmppar4 = tmppar4->next;
3504 } // get last undo par
3506 // now remove the old text if there is any
3507 if (before != behind || (!behind && !before)){
3509 tmppar5 = before->next;
3511 tmppar5 = OwnerParagraph();
3513 while (tmppar5 && tmppar5 != behind){
3515 tmppar5 = tmppar5->next;
3516 // a memory optimization for edit: Only layout information
3517 // is stored in the undo. So restore the text informations.
3518 if (undo->kind == Undo::EDIT) {
3519 tmppar2->setContentsFromPar(tmppar);
3520 tmppar->clearContents();
3521 tmppar2 = tmppar2->next;
3526 // put the new stuff in the list if there is one
3529 before->next = tmppar3;
3531 OwnerParagraph(tmppar3);
3532 tmppar3->previous = before;
3535 OwnerParagraph(behind);
3538 tmppar4->next = behind;
3540 behind->previous = tmppar4;
3544 // Set the cursor for redoing
3547 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3549 SetCursorIntern(bview, before, 0);
3552 // check wether before points to a closed float and open it if necessary
3553 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3554 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3556 while (tmppar4->previous &&
3557 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3558 tmppar4 = tmppar4->previous;
3559 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3560 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3561 tmppar4 = tmppar4->next;
3568 // open a cosed footnote at the end if necessary
3569 if (behind && behind->previous &&
3570 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3571 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3572 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3573 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3574 behind = behind->next;
3579 // calculate the endpar for redoing the paragraphs.
3582 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3583 endpar = behind->LastPhysicalPar()->Next();
3585 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3587 endpar = behind->Next();
3592 tmppar = GetParFromID(undo->number_of_cursor_par);
3593 RedoParagraphs(bview, cursor, endpar);
3595 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3596 UpdateCounters(bview, cursor.row());
3606 void LyXText::FinishUndo()
3610 // makes sure the next operation will be stored
3611 undo_finished = true;
3615 void LyXText::FreezeUndo()
3619 // this is dangerous and for internal use only
3624 void LyXText::UnFreezeUndo()
3628 // this is dangerous and for internal use only
3629 undo_frozen = false;
3633 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3634 LyXParagraph const * before,
3635 LyXParagraph const * behind) const
3640 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3641 buf->redostack.clear();
3645 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3646 LyXParagraph const * before, LyXParagraph const * behind)
3650 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3654 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3655 LyXParagraph const * before,
3656 LyXParagraph const * behind) const
3661 int before_number = -1;
3662 int behind_number = -1;
3664 before_number = before->id();
3666 behind_number = behind->id();
3667 // Undo::EDIT and Undo::FINISH are
3668 // always finished. (no overlapping there)
3669 // overlapping only with insert and delete inside one paragraph:
3670 // Nobody wants all removed character
3671 // appear one by one when undoing.
3672 // EDIT is special since only layout information, not the
3673 // contents of a paragaph are stored.
3674 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3675 // check wether storing is needed
3676 if (!buf->undostack.empty() &&
3677 buf->undostack.top()->kind == kind &&
3678 buf->undostack.top()->number_of_before_par == before_number &&
3679 buf->undostack.top()->number_of_behind_par == behind_number ){
3684 // create a new Undo
3685 LyXParagraph * undopar;
3686 LyXParagraph * tmppar;
3687 LyXParagraph * tmppar2;
3689 LyXParagraph * start = 0;
3690 LyXParagraph * end = 0;
3693 start = before->next;
3695 start = FirstParagraph();
3697 end = behind->previous;
3699 end = FirstParagraph();
3705 && start != end->next
3706 && (before != behind || (!before && !behind))) {
3708 tmppar2 = tmppar->Clone();
3709 tmppar2->id(tmppar->id());
3711 // a memory optimization: Just store the layout information
3713 if (kind == Undo::EDIT){
3714 //tmppar2->text.clear();
3715 tmppar2->clearContents();
3720 while (tmppar != end && tmppar->next) {
3721 tmppar = tmppar->next;
3722 tmppar2->next = tmppar->Clone();
3723 tmppar2->next->id(tmppar->id());
3724 // a memory optimization: Just store the layout
3725 // information when only edit
3726 if (kind == Undo::EDIT){
3727 //tmppar2->next->text.clear();
3728 tmppar2->clearContents();
3730 tmppar2->next->previous = tmppar2;
3731 tmppar2 = tmppar2->next;
3735 undopar = 0; // nothing to replace (undo of delete maybe)
3738 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3739 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3741 int cursor_par = cursor.par()->id();
3742 int cursor_pos = cursor.pos();
3745 Undo * undo = new Undo(kind,
3746 before_number, behind_number,
3747 cursor_par, cursor_pos,
3750 undo_finished = false;
3755 void LyXText::SetCursorParUndo(Buffer * buf)
3759 SetUndo(buf, Undo::FINISH,
3761 cursor.par()->ParFromPos(cursor.pos())->previous,
3762 cursor.par()->ParFromPos(cursor.pos())->next
3764 cursor.par()->previous,
3772 void LyXText::RemoveTableRow(LyXCursor & cur) const
3778 // move to the previous row
3779 int cell_act = NumberOfCell(cur.par(), cur.pos());
3782 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3783 cur.pos(cur.pos() - 1);
3785 !cur.par()->table->IsFirstCell(cell_act)) {
3786 cur.pos(cur.pos() - 1);
3787 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3788 cur.pos(cur.pos() - 1);
3792 // now we have to pay attention if the actual table is the
3793 // main row of TableContRows and if yes to delete all of them
3798 // delete up to the next row
3799 while (cur.pos() < cur.par()->Last() &&
3801 || !cur.par()->table->IsFirstCell(cell_act))) {
3802 while (cur.pos() < cur.par()->Last() &&
3803 !cur.par()->IsNewline(cur.pos()))
3804 cur.par()->Erase(cur.pos());
3807 if (cur.pos() < cur.par()->Last())
3808 cur.par()->Erase(cur.pos());
3810 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3811 cur.pos(cur.pos() - 1);
3812 cur.par()->Erase(cur.pos()); // no newline at very end!
3814 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3815 !cur.par()->table->IsContRow(cell_org) &&
3816 cur.par()->table->IsContRow(cell));
3817 cur.par()->table->DeleteRow(cell_org);
3824 bool LyXText::IsEmptyTableCell() const
3826 LyXParagraph::size_type pos = cursor.pos() - 1;
3827 while (pos >= 0 && pos < cursor.par()->Last()
3828 && !cursor.par()->IsNewline(pos))
3830 return cursor.par()->IsNewline(pos + 1);
3835 void LyXText::toggleAppendix(BufferView * bview)
3838 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3840 LyXParagraph * par = cursor.par();
3842 bool start = !par->start_of_appendix;
3844 // ensure that we have only one start_of_appendix in this document
3845 LyXParagraph * tmp = FirstParagraph();
3846 for (; tmp; tmp = tmp->next)
3847 tmp->start_of_appendix = 0;
3848 par->start_of_appendix = start;
3850 // we can set the refreshing parameters now
3851 status = LyXText::NEED_MORE_REFRESH;
3853 refresh_row = 0; // not needed for full update
3854 UpdateCounters(bview, 0);
3855 SetCursor(bview, cursor.par(), cursor.pos());
3859 LyXParagraph * LyXText::OwnerParagraph() const
3862 return inset_owner->par;
3864 return bv_owner->buffer()->paragraph;
3868 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3871 inset_owner->par = p;
3873 bv_owner->buffer()->paragraph = p;