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 InsetCommandParams p( "bibitem" );
2032 par->bibkey = new InsetBibKey(p);
2034 par->bibkey->setCounter(number);
2035 par->labelstring = layout.labelstring();
2037 // In biblio should't be following counters but...
2039 string s = layout.labelstring();
2041 // the caption hack:
2042 if (layout.labeltype == LABEL_SENSITIVE) {
2043 bool isOK (par->InInset() && par->InInset()->owner() &&
2044 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2046 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2047 && (par->footnotekind == LyXParagraph::FIG
2048 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2049 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2050 ? ":øåéà " : "Figure:";
2051 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2052 && (par->footnotekind == LyXParagraph::TAB
2053 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2054 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2055 ? ":äìáè" : "Table:";
2056 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2057 && par->footnotekind == LyXParagraph::ALGORITHM) {
2058 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2059 ? ":Ãúéøåâìà " : "Algorithm:";
2063 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2065 = floatList.getType(tmp->type());
2066 // We should get the correct number here too.
2067 s = fl.name + " #:";
2069 /* par->SetLayout(0);
2070 s = layout->labelstring; */
2071 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2072 ? " :úåòîùî øñç" : "Senseless: ";
2075 par->labelstring = s;
2077 /* reset the enumeration counter. They are always resetted
2078 * when there is any other layout between */
2079 for (int i = 6 + par->enumdepth; i < 10; ++i)
2080 par->setCounter(i, 0);
2085 /* Updates all counters BEHIND the row. Changed paragraphs
2086 * with a dynamic left margin will be rebroken. */
2087 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2094 if (row->par()->next
2096 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2100 par = row->par()->LastPhysicalPar()->Next();
2102 par = row->par()->Next();
2105 par = row->par()->next;
2110 while (row->par() != par)
2113 SetCounter(bview->buffer(), par);
2115 /* now check for the headline layouts. remember that they
2116 * have a dynamic left margin */
2121 ( textclasslist.Style(bview->buffer()->params.textclass,
2122 par->layout).margintype == MARGIN_DYNAMIC
2123 || textclasslist.Style(bview->buffer()->params.textclass,
2124 par->layout).labeltype == LABEL_SENSITIVE)
2127 /* Rebreak the paragraph */
2128 RemoveParagraph(row);
2129 AppendParagraph(bview, row);
2132 /* think about the damned open footnotes! */
2133 while (par->Next() &&
2134 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2135 || par->Next()->IsDummy())){
2137 if (par->IsDummy()) {
2138 while (row->par() != par)
2140 RemoveParagraph(row);
2141 AppendParagraph(bview, row);
2147 par = par->LastPhysicalPar()->Next();
2156 /* insets an inset. */
2157 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2159 if (!cursor.par()->InsertInsetAllowed(inset))
2161 SetUndo(bview->buffer(), Undo::INSERT,
2163 cursor.par()->ParFromPos(cursor.pos())->previous,
2164 cursor.par()->ParFromPos(cursor.pos())->next
2166 cursor.par()->previous,
2170 cursor.par()->InsertInset(cursor.pos(), inset);
2171 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2172 * The character will not be inserted a
2177 void LyXText::copyEnvironmentType()
2179 copylayouttype = cursor.par()->GetLayout();
2183 void LyXText::pasteEnvironmentType(BufferView * bview)
2185 SetLayout(bview, copylayouttype);
2189 void LyXText::CutSelection(BufferView * bview, bool doclear)
2191 // Stuff what we got on the clipboard. Even if there is no selection.
2193 // There is a problem with having the stuffing here in that the
2194 // larger the selection the slower LyX will get. This can be
2195 // solved by running the line below only when the selection has
2196 // finished. The solution used currently just works, to make it
2197 // faster we need to be more clever and probably also have more
2198 // calls to stuffClipboard. (Lgb)
2199 bview->stuffClipboard(selectionAsString(bview->buffer()));
2201 // This doesn't make sense, if there is no selection
2205 // OK, we have a selection. This is always between sel_start_cursor
2206 // and sel_end cursor
2208 // Check whether there are half footnotes in the selection
2209 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2210 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2211 LyXParagraph * tmppar = sel_start_cursor.par();
2212 while (tmppar != sel_end_cursor.par()){
2213 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2214 WriteAlert(_("Impossible operation"),
2215 _("Don't know what to do with half floats."),
2219 tmppar = tmppar->Next();
2224 /* table stuff -- begin */
2225 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2226 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2227 WriteAlert(_("Impossible operation"),
2228 _("Don't know what to do with half tables."),
2232 sel_start_cursor.par()->table->Reinit();
2234 /* table stuff -- end */
2236 // make sure that the depth behind the selection are restored, too
2238 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2240 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2242 LyXParagraph * undoendpar = endpar;
2244 if (endpar && endpar->GetDepth()) {
2245 while (endpar && endpar->GetDepth()) {
2247 endpar = endpar->LastPhysicalPar()->Next();
2249 endpar = endpar->Next();
2251 undoendpar = endpar;
2253 } else if (endpar) {
2254 endpar = endpar->Next(); // because of parindents etc.
2257 SetUndo(bview->buffer(), Undo::DELETE,
2260 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2262 sel_start_cursor.par()->previous,
2268 // there are two cases: cut only within one paragraph or
2269 // more than one paragraph
2271 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2272 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2274 if (sel_start_cursor.par() == sel_end_cursor.par())
2277 // only within one paragraph
2278 endpar = sel_start_cursor.par();
2279 int pos = sel_end_cursor.pos();
2280 cap.cutSelection(sel_start_cursor.par(), &endpar,
2281 sel_start_cursor.pos(), pos,
2282 bview->buffer()->params.textclass, doclear);
2283 sel_end_cursor.pos(pos);
2285 endpar = sel_end_cursor.par();
2287 int pos = sel_end_cursor.pos();
2288 cap.cutSelection(sel_start_cursor.par(), &endpar,
2289 sel_start_cursor.pos(), pos,
2290 bview->buffer()->params.textclass, doclear);
2292 sel_end_cursor.par(endpar);
2293 sel_end_cursor.pos(pos);
2294 cursor.pos(sel_end_cursor.pos());
2296 endpar = endpar->Next();
2298 // sometimes necessary
2300 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2302 RedoParagraphs(bview, sel_start_cursor, endpar);
2305 cursor = sel_start_cursor;
2306 SetCursor(bview, cursor.par(), cursor.pos());
2307 sel_cursor = cursor;
2308 UpdateCounters(bview, cursor.row());
2312 void LyXText::CopySelection(BufferView * bview)
2314 // Stuff what we got on the clipboard. Even if there is no selection.
2316 // There is a problem with having the stuffing here in that the
2317 // larger the selection the slower LyX will get. This can be
2318 // solved by running the line below only when the selection has
2319 // finished. The solution used currently just works, to make it
2320 // faster we need to be more clever and probably also have more
2321 // calls to stuffClipboard. (Lgb)
2322 bview->stuffClipboard(selectionAsString(bview->buffer()));
2324 // this doesnt make sense, if there is no selection
2328 // ok we have a selection. This is always between sel_start_cursor
2329 // and sel_end cursor
2332 /* check wether there are half footnotes in the selection */
2333 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2334 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2335 LyXParagraph * tmppar = sel_start_cursor.par();
2336 while (tmppar != sel_end_cursor.par()) {
2337 if (tmppar->footnoteflag !=
2338 sel_end_cursor.par()->footnoteflag) {
2339 WriteAlert(_("Impossible operation"),
2340 _("Don't know what to do"
2341 " with half floats."),
2345 tmppar = tmppar->Next();
2350 /* table stuff -- begin */
2351 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2352 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2353 WriteAlert(_("Impossible operation"),
2354 _("Don't know what to do with half tables."),
2359 /* table stuff -- end */
2362 // copy behind a space if there is one
2363 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2364 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2365 && (sel_start_cursor.par() != sel_end_cursor.par()
2366 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2367 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2371 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2372 sel_start_cursor.pos(), sel_end_cursor.pos(),
2373 bview->buffer()->params.textclass);
2377 void LyXText::PasteSelection(BufferView * bview)
2381 // this does not make sense, if there is nothing to paste
2382 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2385 SetUndo(bview->buffer(), Undo::INSERT,
2387 cursor.par()->ParFromPos(cursor.pos())->previous,
2388 cursor.par()->ParFromPos(cursor.pos())->next
2390 cursor.par()->previous,
2395 LyXParagraph * endpar;
2396 LyXParagraph * actpar = cursor.par();
2398 int pos = cursor.pos();
2399 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2401 RedoParagraphs(bview, cursor, endpar);
2403 SetCursor(bview, cursor.par(), cursor.pos());
2406 sel_cursor = cursor;
2407 SetCursor(bview, actpar, pos);
2409 UpdateCounters(bview, cursor.row());
2413 // returns a pointer to the very first LyXParagraph
2414 LyXParagraph * LyXText::FirstParagraph() const
2416 return OwnerParagraph();
2420 // returns true if the specified string is at the specified position
2421 bool LyXText::IsStringInText(LyXParagraph * par,
2422 LyXParagraph::size_type pos,
2423 char const * str) const
2427 while (pos + i < par->Last() && str[i] &&
2428 str[i] == par->GetChar(pos + i)) {
2438 // sets the selection over the number of characters of string, no check!!
2439 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2441 sel_cursor = cursor;
2442 for (int i = 0; string[i]; ++i)
2448 // simple replacing. The font of the first selected character is used
2449 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2451 SetCursorParUndo(bview->buffer());
2454 if (!selection) { // create a dummy selection
2455 sel_end_cursor = cursor;
2456 sel_start_cursor = cursor;
2459 // Get font setting before we cut
2460 LyXParagraph::size_type pos = sel_end_cursor.pos();
2461 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2462 sel_start_cursor.pos());
2464 // Insert the new string
2465 for (int i = 0; str[i]; ++i) {
2466 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2470 // Cut the selection
2471 CutSelection(bview);
2477 // if the string can be found: return true and set the cursor to
2479 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2481 LyXParagraph * par = cursor.par();
2482 LyXParagraph::size_type pos = cursor.pos();
2483 while (par && !IsStringInText(par, pos, str)) {
2484 if (pos < par->Last() - 1)
2492 SetCursor(bview, par, pos);
2500 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2502 LyXParagraph * par = cursor.par();
2503 int pos = cursor.pos();
2509 // We skip empty paragraphs (Asger)
2511 par = par->Previous();
2513 pos = par->Last() - 1;
2514 } while (par && pos < 0);
2516 } while (par && !IsStringInText(par, pos, string));
2519 SetCursor(bview, par, pos);
2526 // needed to insert the selection
2527 void LyXText::InsertStringA(BufferView * bview, string const & str)
2529 LyXParagraph * par = cursor.par();
2530 LyXParagraph::size_type pos = cursor.pos();
2531 LyXParagraph::size_type a = 0;
2532 LyXParagraph * endpar = cursor.par()->Next();
2534 SetCursorParUndo(bview->buffer());
2537 textclasslist.Style(bview->buffer()->params.textclass,
2538 cursor.par()->GetLayout()).isEnvironment();
2539 // only to be sure, should not be neccessary
2542 // insert the string, don't insert doublespace
2543 string::size_type i = 0;
2544 while (i < str.length()) {
2545 if (str[i] != '\n') {
2547 && i + 1 < str.length() && str[i + 1] != ' '
2548 && pos && par->GetChar(pos - 1)!= ' ') {
2549 par->InsertChar(pos, ' ', current_font);
2552 } else if (par->table) {
2553 if (str[i] == '\t') {
2554 while((pos < par->size()) &&
2555 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2557 if (pos < par->size())
2559 else // no more fields to fill skip the rest
2561 } else if ((str[i] != 13) &&
2562 ((str[i] & 127) >= ' ')) {
2563 par->InsertChar(pos, str[i],
2568 } else if (str[i] == ' ') {
2569 InsetSpecialChar * new_inset =
2570 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2571 if (par->InsertInsetAllowed(new_inset)) {
2572 par->InsertInset(pos, new_inset,
2578 } else if (str[i] == '\t') {
2579 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2580 InsetSpecialChar * new_inset =
2581 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2582 if (par->InsertInsetAllowed(new_inset)) {
2583 par->InsertInset(pos, new_inset,
2590 } else if (str[i] != 13 &&
2591 // Ignore unprintables
2592 (str[i] & 127) >= ' ') {
2593 par->InsertChar(pos, str[i], current_font);
2599 if ((i + 1) >= str.length()) {
2600 if (pos < par->size())
2604 while((pos < par->size()) &&
2605 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2608 int cell = NumberOfCell(par, pos);
2609 while((pos < par->size()) &&
2610 !(par->table->IsFirstCell(cell))) {
2612 while((pos < par->size()) &&
2613 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2616 cell = NumberOfCell(par, pos);
2618 if (pos >= par->size())
2619 // no more fields to fill skip the rest
2623 if (!par->size()) { // par is empty
2624 InsetSpecialChar * new_inset =
2625 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2626 if (par->InsertInsetAllowed(new_inset)) {
2627 par->InsertInset(pos,
2635 par->BreakParagraph(bview->buffer()->params, pos, flag);
2645 RedoParagraphs(bview, cursor, endpar);
2646 SetCursor(bview, cursor.par(), cursor.pos());
2647 sel_cursor = cursor;
2648 SetCursor(bview, par, pos);
2653 /* turns double-CR to single CR, others where converted into one blank and 13s
2654 * that are ignored .Double spaces are also converted into one. Spaces at
2655 * the beginning of a paragraph are forbidden. tabs are converted into one
2656 * space. then InsertStringA is called */
2657 void LyXText::InsertStringB(BufferView * bview, string const & s)
2661 LyXParagraph * par = cursor.par();
2663 string::size_type i = 1;
2664 while (i < str.length()) {
2671 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2673 if (str[i] == '\n' && i + 1 < str.length()
2678 if (str[i + 1] != '\n') {
2679 if (str[i - 1] != ' ')
2684 while (i + 1 < str.length()
2685 && (str[i + 1] == ' '
2686 || str[i + 1] == '\t'
2687 || str[i + 1] == '\n'
2688 || str[i + 1] == 13)) {
2695 InsertStringA(bview, str);
2699 bool LyXText::GotoNextError(BufferView * bview) const
2701 LyXCursor res = cursor;
2703 if (res.pos() < res.par()->Last() - 1) {
2704 res.pos(res.pos() + 1);
2706 res.par(res.par()->Next());
2710 } while (res.par() &&
2711 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2712 && res.par()->GetInset(res.pos())->AutoDelete()));
2715 SetCursor(bview, res.par(), res.pos());
2722 bool LyXText::GotoNextNote(BufferView * bview) const
2724 LyXCursor res = cursor;
2726 if (res.pos() < res.par()->Last() - 1) {
2727 res.pos(res.pos() + 1);
2729 res.par(res.par()->Next());
2733 } while (res.par() &&
2734 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2735 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2738 SetCursor(bview, res.par(), res.pos());
2745 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2746 LyXParagraph::size_type pos)
2748 LyXCursor tmpcursor;
2751 /* table stuff -- begin*/
2754 CheckParagraphInTable(bview, par, pos);
2758 /* table stuff -- end*/
2761 LyXParagraph::size_type z;
2762 Row * row = GetRow(par, pos, y);
2764 // is there a break one row above
2765 if (row->previous() && row->previous()->par() == row->par()) {
2766 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2767 if ( z >= row->pos()) {
2768 // set the dimensions of the row above
2769 y -= row->previous()->height();
2771 refresh_row = row->previous();
2772 status = LyXText::NEED_MORE_REFRESH;
2774 BreakAgain(bview, row->previous());
2776 // set the cursor again. Otherwise
2777 // dangling pointers are possible
2778 SetCursor(bview, cursor.par(), cursor.pos());
2779 sel_cursor = cursor;
2784 int tmpheight = row->height();
2785 LyXParagraph::size_type tmplast = RowLast(row);
2789 BreakAgain(bview, row);
2790 if (row->height() == tmpheight && RowLast(row) == tmplast)
2791 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2793 status = LyXText::NEED_MORE_REFRESH;
2795 // check the special right address boxes
2796 if (textclasslist.Style(bview->buffer()->params.textclass,
2797 par->GetLayout()).margintype
2798 == MARGIN_RIGHT_ADDRESS_BOX) {
2805 RedoDrawingOfParagraph(bview, tmpcursor);
2811 // set the cursor again. Otherwise dangling pointers are possible
2812 // also set the selection
2816 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2817 sel_cursor = cursor;
2818 SetCursorIntern(bview, sel_start_cursor.par(),
2819 sel_start_cursor.pos());
2820 sel_start_cursor = cursor;
2821 SetCursorIntern(bview, sel_end_cursor.par(),
2822 sel_end_cursor.pos());
2823 sel_end_cursor = cursor;
2824 SetCursorIntern(bview, last_sel_cursor.par(),
2825 last_sel_cursor.pos());
2826 last_sel_cursor = cursor;
2829 SetCursorIntern(bview, cursor.par(), cursor.pos());
2833 // returns false if inset wasn't found
2834 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2836 // first check the current paragraph
2837 int pos = cursor.par()->GetPositionOfInset(inset);
2839 CheckParagraph(bview, cursor.par(), pos);
2843 // check every paragraph
2845 LyXParagraph * par = FirstParagraph();
2848 // make sure the paragraph is open
2849 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2851 pos = par->GetPositionOfInset(inset);
2853 CheckParagraph(bview, par, pos);
2866 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2867 LyXParagraph::size_type pos,
2868 bool setfont, bool boundary) const
2870 LyXCursor old_cursor = cursor;
2871 SetCursorIntern(bview, par, pos, setfont, boundary);
2872 DeleteEmptyParagraphMechanism(bview, old_cursor);
2876 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2877 LyXParagraph::size_type pos, bool boundary) const
2880 // correct the cursor position if impossible
2881 if (pos > par->Last()){
2882 LyXParagraph * tmppar = par->ParFromPos(pos);
2883 pos = par->PositionInParFromPos(pos);
2886 if (par->IsDummy() && par->previous &&
2887 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2888 while (par->previous &&
2889 ((par->previous->IsDummy() &&
2890 (par->previous->previous->footnoteflag ==
2891 LyXParagraph::CLOSED_FOOTNOTE)) ||
2892 (par->previous->footnoteflag ==
2893 LyXParagraph::CLOSED_FOOTNOTE))) {
2894 par = par->previous ;
2895 if (par->IsDummy() &&
2896 (par->previous->footnoteflag ==
2897 LyXParagraph::CLOSED_FOOTNOTE))
2898 pos += par->size() + 1;
2900 if (par->previous) {
2901 par = par->previous;
2903 pos += par->size() + 1;
2908 cur.boundary(boundary);
2910 /* get the cursor y position in text */
2912 Row * row = GetRow(par, pos, y);
2913 /* y is now the beginning of the cursor row */
2914 y += row->baseline();
2915 /* y is now the cursor baseline */
2918 /* now get the cursors x position */
2920 float fill_separator, fill_hfill, fill_label_hfill;
2921 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2923 LyXParagraph::size_type cursor_vpos = 0;
2924 LyXParagraph::size_type last = RowLastPrintable(row);
2926 if (pos > last + 1) // This shouldn't happen.
2928 else if (pos < row->pos())
2931 if (last < row->pos())
2932 cursor_vpos = row->pos();
2933 else if (pos > last && !boundary)
2934 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2935 ? row->pos() : last + 1;
2936 else if (pos > row->pos() &&
2937 (pos > last || boundary
2939 || (row->par()->table && row->par()->IsNewline(pos))
2942 /// Place cursor after char at (logical) position pos - 1
2943 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2944 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2946 /// Place cursor before char at (logical) position pos
2947 cursor_vpos = (bidi_level(pos) % 2 == 0)
2948 ? log2vis(pos) : log2vis(pos) + 1;
2951 /* table stuff -- begin*/
2952 if (row->par()->table) {
2953 int cell = NumberOfCell(row->par(), row->pos());
2955 x += row->par()->table->GetBeginningOfTextInCell(cell);
2956 for (LyXParagraph::size_type vpos = row->pos();
2957 vpos < cursor_vpos; ++vpos) {
2958 pos = vis2log(vpos);
2959 if (row->par()->IsNewline(pos)) {
2960 x = x_old + row->par()->table->WidthOfColumn(cell);
2963 x += row->par()->table->GetBeginningOfTextInCell(cell);
2965 x += SingleWidth(bview, row->par(), pos);
2969 /* table stuff -- end*/
2971 LyXParagraph::size_type main_body =
2972 BeginningOfMainBody(bview->buffer(), row->par());
2973 if ((main_body > 0) &&
2974 ((main_body-1 > last) ||
2975 !row->par()->IsLineSeparator(main_body-1)))
2978 for (LyXParagraph::size_type vpos = row->pos();
2979 vpos < cursor_vpos; ++vpos) {
2980 pos = vis2log(vpos);
2981 if (main_body > 0 && pos == main_body-1) {
2982 x += fill_label_hfill +
2983 lyxfont::width(textclasslist.Style(
2984 bview->buffer()->params.textclass,
2985 row->par()->GetLayout())
2987 GetFont(bview->buffer(), row->par(), -2));
2988 if (row->par()->IsLineSeparator(main_body-1))
2989 x -= SingleWidth(bview, row->par(),main_body-1);
2991 if (HfillExpansion(bview->buffer(), row, pos)) {
2992 x += SingleWidth(bview, row->par(), pos);
2993 if (pos >= main_body)
2996 x += fill_label_hfill;
2997 } else if (row->par()->IsSeparator(pos)) {
2998 x += SingleWidth(bview, row->par(), pos);
2999 if (pos >= main_body)
3000 x += fill_separator;
3002 x += SingleWidth(bview, row->par(), pos);
3014 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3015 LyXParagraph::size_type pos,
3016 bool setfont, bool boundary) const
3018 SetCursor(bview, cursor, par, pos, boundary);
3020 SetCurrentFont(bview);
3023 void LyXText::SetCurrentFont(BufferView * bview) const
3025 LyXParagraph::size_type pos = cursor.pos();
3026 if (cursor.boundary() && pos > 0)
3030 if (pos == cursor.par()->Last()
3032 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3036 else if (cursor.par()->IsSeparator(pos)) {
3037 if (pos > cursor.row()->pos() &&
3038 bidi_level(pos) % 2 ==
3039 bidi_level(pos - 1) % 2)
3041 else if (pos + 1 < cursor.par()->Last())
3047 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3048 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3050 if (cursor.pos() == cursor.par()->Last() &&
3051 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3052 !cursor.boundary()) {
3053 Language const * lang =
3054 cursor.par()->getParLanguage(bview->buffer()->params);
3055 current_font.setLanguage(lang);
3056 real_current_font.setLanguage(lang);
3061 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3063 LyXCursor old_cursor = cursor;
3065 /* get the row first */
3067 Row * row = GetRowNearY(y);
3068 cursor.par(row->par());
3071 int column = GetColumnNearX(bview, row, x, bound);
3072 cursor.pos(row->pos() + column);
3074 cursor.y(y + row->baseline());
3076 cursor.boundary(bound);
3077 SetCurrentFont(bview);
3078 DeleteEmptyParagraphMechanism(bview, old_cursor);
3082 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3083 int x, long y) const
3085 /* get the row first */
3087 Row * row = GetRowNearY(y);
3089 int column = GetColumnNearX(bview, row, x, bound);
3091 cur.par(row->par());
3092 cur.pos(row->pos() + column);
3094 cur.y(y + row->baseline());
3096 cur.boundary(bound);
3100 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3102 CursorLeftIntern(bview, internal);
3104 if (cursor.par()->table) {
3105 int cell = NumberOfCell(cursor.par(), cursor.pos());
3106 if (cursor.par()->table->IsContRow(cell)
3107 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3115 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3117 if (cursor.pos() > 0) {
3118 bool boundary = cursor.boundary();
3119 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3120 if (!internal && !boundary &&
3121 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3122 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3123 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3124 LyXParagraph * par = cursor.par()->Previous();
3125 SetCursor(bview, par, par->Last());
3130 void LyXText::CursorRight(BufferView * bview, bool internal) const
3132 CursorRightIntern(bview, internal);
3134 if (cursor.par()->table) {
3135 int cell = NumberOfCell(cursor.par(), cursor.pos());
3136 if (cursor.par()->table->IsContRow(cell) &&
3137 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3145 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3147 if (!internal && cursor.boundary() &&
3150 !cursor.par()->table ||
3152 !cursor.par()->IsNewline(cursor.pos())))
3153 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3154 else if (cursor.pos() < cursor.par()->Last()) {
3155 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3157 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3158 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3159 } else if (cursor.par()->Next())
3160 SetCursor(bview, cursor.par()->Next(), 0);
3164 void LyXText::CursorUp(BufferView * bview) const
3166 SetCursorFromCoordinates(bview, cursor.x_fix(),
3167 cursor.y() - cursor.row()->baseline() - 1);
3169 if (cursor.par()->table) {
3170 int cell = NumberOfCell(cursor.par(), cursor.pos());
3171 if (cursor.par()->table->IsContRow(cell) &&
3172 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3180 void LyXText::CursorDown(BufferView * bview) const
3183 if (cursor.par()->table &&
3184 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3185 !cursor.par()->next)
3189 SetCursorFromCoordinates(bview, cursor.x_fix(),
3190 cursor.y() - cursor.row()->baseline()
3191 + cursor.row()->height() + 1);
3193 if (cursor.par()->table) {
3194 int cell = NumberOfCell(cursor.par(), cursor.pos());
3195 int cell_above = cursor.par()->table->GetCellAbove(cell);
3196 while(cursor.par()->table &&
3197 cursor.par()->table->IsContRow(cell) &&
3198 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3199 SetCursorFromCoordinates(bview, cursor.x_fix(),
3200 cursor.y() - cursor.row()->baseline()
3201 + cursor.row()->height() + 1);
3202 if (cursor.par()->table) {
3203 cell = NumberOfCell(cursor.par(), cursor.pos());
3204 cell_above = cursor.par()->table->GetCellAbove(cell);
3212 void LyXText::CursorUpParagraph(BufferView * bview) const
3214 if (cursor.pos() > 0) {
3215 SetCursor(bview, cursor.par(), 0);
3217 else if (cursor.par()->Previous()) {
3218 SetCursor(bview, cursor.par()->Previous(), 0);
3223 void LyXText::CursorDownParagraph(BufferView * bview) const
3225 if (cursor.par()->Next()) {
3226 SetCursor(bview, cursor.par()->Next(), 0);
3228 SetCursor(bview, cursor.par(), cursor.par()->Last());
3233 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3234 LyXCursor const & old_cursor) const
3236 // Would be wrong to delete anything if we have a selection.
3237 if (selection) return;
3239 // We allow all kinds of "mumbo-jumbo" when freespacing.
3240 if (textclasslist.Style(bview->buffer()->params.textclass,
3241 old_cursor.par()->GetLayout()).free_spacing)
3244 bool deleted = false;
3246 /* Ok I'll put some comments here about what is missing.
3247 I have fixed BackSpace (and thus Delete) to not delete
3248 double-spaces automagically. I have also changed Cut,
3249 Copy and Paste to hopefully do some sensible things.
3250 There are still some small problems that can lead to
3251 double spaces stored in the document file or space at
3252 the beginning of paragraphs. This happens if you have
3253 the cursor betwenn to spaces and then save. Or if you
3254 cut and paste and the selection have a space at the
3255 beginning and then save right after the paste. I am
3256 sure none of these are very hard to fix, but I will
3257 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3258 that I can get some feedback. (Lgb)
3261 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3262 // delete the LineSeparator.
3265 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3266 // delete the LineSeparator.
3269 // If the pos around the old_cursor were spaces, delete one of them.
3270 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3271 // Only if the cursor has really moved
3273 if (old_cursor.pos() > 0
3274 && old_cursor.pos() < old_cursor.par()->Last()
3275 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3276 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3277 old_cursor.par()->Erase(old_cursor.pos() - 1);
3278 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3280 if (old_cursor.par() == cursor.par() &&
3281 cursor.pos() > old_cursor.pos()) {
3282 SetCursorIntern(bview, cursor.par(),
3285 SetCursorIntern(bview, cursor.par(),
3291 // Do not delete empty paragraphs with keepempty set.
3292 if ((textclasslist.Style(bview->buffer()->params.textclass,
3293 old_cursor.par()->GetLayout())).keepempty)
3296 LyXCursor tmpcursor;
3298 if (old_cursor.par() != cursor.par()) {
3299 if ( (old_cursor.par()->Last() == 0
3300 || (old_cursor.par()->Last() == 1
3301 && old_cursor.par()->IsLineSeparator(0)))
3303 && old_cursor.par()->FirstPhysicalPar()
3304 == old_cursor.par()->LastPhysicalPar()
3307 // ok, we will delete anything
3309 // make sure that you do not delete any environments
3312 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3313 !(old_cursor.row()->previous()
3314 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3315 && !(old_cursor.row()->next()
3316 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3317 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3318 && ((old_cursor.row()->previous()
3319 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3320 || (old_cursor.row()->next()
3321 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3324 status = LyXText::NEED_MORE_REFRESH;
3327 if (old_cursor.row()->previous()) {
3328 refresh_row = old_cursor.row()->previous();
3329 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3331 cursor = old_cursor; // that undo can restore the right cursor position
3332 LyXParagraph * endpar = old_cursor.par()->next;
3333 if (endpar && endpar->GetDepth()) {
3334 while (endpar && endpar->GetDepth()) {
3336 endpar = endpar->LastPhysicalPar()->Next();
3338 endpar = endpar->Next();
3342 SetUndo(bview->buffer(), Undo::DELETE,
3343 old_cursor.par()->previous,
3348 RemoveRow(old_cursor.row());
3349 if (OwnerParagraph() == old_cursor.par()) {
3350 OwnerParagraph(OwnerParagraph()->next);
3353 delete old_cursor.par();
3355 /* Breakagain the next par. Needed
3356 * because of the parindent that
3357 * can occur or dissappear. The
3358 * next row can change its height,
3359 * if there is another layout before */
3360 if (refresh_row->next()) {
3361 BreakAgain(bview, refresh_row->next());
3362 UpdateCounters(bview, refresh_row);
3364 SetHeightOfRow(bview, refresh_row);
3366 refresh_row = old_cursor.row()->next();
3367 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3370 cursor = old_cursor; // that undo can restore the right cursor position
3371 LyXParagraph * endpar = old_cursor.par()->next;
3372 if (endpar && endpar->GetDepth()) {
3373 while (endpar && endpar->GetDepth()) {
3375 endpar = endpar->LastPhysicalPar()->Next();
3377 endpar = endpar->Next();
3381 SetUndo(bview->buffer(), Undo::DELETE,
3382 old_cursor.par()->previous,
3387 RemoveRow(old_cursor.row());
3389 if (OwnerParagraph() == old_cursor.par()) {
3390 OwnerParagraph(OwnerParagraph()->next);
3392 delete old_cursor.par();
3394 /* Breakagain the next par. Needed
3395 because of the parindent that can
3396 occur or dissappear.
3397 The next row can change its height,
3398 if there is another layout before
3401 BreakAgain(bview, refresh_row);
3402 UpdateCounters(bview, refresh_row->previous());
3408 SetCursorIntern(bview, cursor.par(), cursor.pos());
3410 if (sel_cursor.par() == old_cursor.par()
3411 && sel_cursor.pos() == sel_cursor.pos()) {
3412 // correct selection
3413 sel_cursor = cursor;
3420 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3421 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3423 SetCursorIntern(bview, cursor.par(), cursor.pos());
3424 sel_cursor = cursor;
3431 LyXParagraph * LyXText::GetParFromID(int id)
3433 LyXParagraph * result = FirstParagraph();
3434 while (result && result->id() != id)
3435 result = result->next;
3441 bool LyXText::TextUndo(BufferView * bview)
3445 // returns false if no undo possible
3446 Undo * undo = bview->buffer()->undostack.pop();
3450 bview->buffer()->redostack
3451 .push(CreateUndo(bview->buffer(), undo->kind,
3452 GetParFromID(undo->number_of_before_par),
3453 GetParFromID(undo->number_of_behind_par)));
3455 return TextHandleUndo(bview, undo);
3459 bool LyXText::TextRedo(BufferView * bview)
3463 // returns false if no redo possible
3464 Undo * undo = bview->buffer()->redostack.pop();
3468 bview->buffer()->undostack
3469 .push(CreateUndo(bview->buffer(), undo->kind,
3470 GetParFromID(undo->number_of_before_par),
3471 GetParFromID(undo->number_of_behind_par)));
3473 return TextHandleUndo(bview, undo);
3477 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3481 // returns false if no undo possible
3482 bool result = false;
3484 LyXParagraph * before =
3485 GetParFromID(undo->number_of_before_par);
3486 LyXParagraph * behind =
3487 GetParFromID(undo->number_of_behind_par);
3488 LyXParagraph * tmppar;
3489 LyXParagraph * tmppar2;
3490 LyXParagraph * endpar;
3491 LyXParagraph * tmppar5;
3493 // if there's no before take the beginning
3494 // of the document for redoing
3496 SetCursorIntern(bview, FirstParagraph(), 0);
3498 // replace the paragraphs with the undo informations
3500 LyXParagraph * tmppar3 = undo->par;
3501 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3502 LyXParagraph * tmppar4 = tmppar3;
3504 while (tmppar4->next)
3505 tmppar4 = tmppar4->next;
3506 } // get last undo par
3508 // now remove the old text if there is any
3509 if (before != behind || (!behind && !before)){
3511 tmppar5 = before->next;
3513 tmppar5 = OwnerParagraph();
3515 while (tmppar5 && tmppar5 != behind){
3517 tmppar5 = tmppar5->next;
3518 // a memory optimization for edit: Only layout information
3519 // is stored in the undo. So restore the text informations.
3520 if (undo->kind == Undo::EDIT) {
3521 tmppar2->setContentsFromPar(tmppar);
3522 tmppar->clearContents();
3523 tmppar2 = tmppar2->next;
3528 // put the new stuff in the list if there is one
3531 before->next = tmppar3;
3533 OwnerParagraph(tmppar3);
3534 tmppar3->previous = before;
3537 OwnerParagraph(behind);
3540 tmppar4->next = behind;
3542 behind->previous = tmppar4;
3546 // Set the cursor for redoing
3549 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3551 SetCursorIntern(bview, before, 0);
3554 // check wether before points to a closed float and open it if necessary
3555 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3556 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3558 while (tmppar4->previous &&
3559 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3560 tmppar4 = tmppar4->previous;
3561 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3562 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3563 tmppar4 = tmppar4->next;
3570 // open a cosed footnote at the end if necessary
3571 if (behind && behind->previous &&
3572 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3573 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3574 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3575 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3576 behind = behind->next;
3581 // calculate the endpar for redoing the paragraphs.
3584 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3585 endpar = behind->LastPhysicalPar()->Next();
3587 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3589 endpar = behind->Next();
3594 tmppar = GetParFromID(undo->number_of_cursor_par);
3595 RedoParagraphs(bview, cursor, endpar);
3597 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3598 UpdateCounters(bview, cursor.row());
3608 void LyXText::FinishUndo()
3612 // makes sure the next operation will be stored
3613 undo_finished = true;
3617 void LyXText::FreezeUndo()
3621 // this is dangerous and for internal use only
3626 void LyXText::UnFreezeUndo()
3630 // this is dangerous and for internal use only
3631 undo_frozen = false;
3635 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3636 LyXParagraph const * before,
3637 LyXParagraph const * behind) const
3642 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3643 buf->redostack.clear();
3647 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3648 LyXParagraph const * before, LyXParagraph const * behind)
3652 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3656 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3657 LyXParagraph const * before,
3658 LyXParagraph const * behind) const
3663 int before_number = -1;
3664 int behind_number = -1;
3666 before_number = before->id();
3668 behind_number = behind->id();
3669 // Undo::EDIT and Undo::FINISH are
3670 // always finished. (no overlapping there)
3671 // overlapping only with insert and delete inside one paragraph:
3672 // Nobody wants all removed character
3673 // appear one by one when undoing.
3674 // EDIT is special since only layout information, not the
3675 // contents of a paragaph are stored.
3676 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3677 // check wether storing is needed
3678 if (!buf->undostack.empty() &&
3679 buf->undostack.top()->kind == kind &&
3680 buf->undostack.top()->number_of_before_par == before_number &&
3681 buf->undostack.top()->number_of_behind_par == behind_number ){
3686 // create a new Undo
3687 LyXParagraph * undopar;
3688 LyXParagraph * tmppar;
3689 LyXParagraph * tmppar2;
3691 LyXParagraph * start = 0;
3692 LyXParagraph * end = 0;
3695 start = before->next;
3697 start = FirstParagraph();
3699 end = behind->previous;
3701 end = FirstParagraph();
3707 && start != end->next
3708 && (before != behind || (!before && !behind))) {
3710 tmppar2 = tmppar->Clone();
3711 tmppar2->id(tmppar->id());
3713 // a memory optimization: Just store the layout information
3715 if (kind == Undo::EDIT){
3716 //tmppar2->text.clear();
3717 tmppar2->clearContents();
3722 while (tmppar != end && tmppar->next) {
3723 tmppar = tmppar->next;
3724 tmppar2->next = tmppar->Clone();
3725 tmppar2->next->id(tmppar->id());
3726 // a memory optimization: Just store the layout
3727 // information when only edit
3728 if (kind == Undo::EDIT){
3729 //tmppar2->next->text.clear();
3730 tmppar2->clearContents();
3732 tmppar2->next->previous = tmppar2;
3733 tmppar2 = tmppar2->next;
3737 undopar = 0; // nothing to replace (undo of delete maybe)
3740 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3741 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3743 int cursor_par = cursor.par()->id();
3744 int cursor_pos = cursor.pos();
3747 Undo * undo = new Undo(kind,
3748 before_number, behind_number,
3749 cursor_par, cursor_pos,
3752 undo_finished = false;
3757 void LyXText::SetCursorParUndo(Buffer * buf)
3761 SetUndo(buf, Undo::FINISH,
3763 cursor.par()->ParFromPos(cursor.pos())->previous,
3764 cursor.par()->ParFromPos(cursor.pos())->next
3766 cursor.par()->previous,
3774 void LyXText::RemoveTableRow(LyXCursor & cur) const
3780 // move to the previous row
3781 int cell_act = NumberOfCell(cur.par(), cur.pos());
3784 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3785 cur.pos(cur.pos() - 1);
3787 !cur.par()->table->IsFirstCell(cell_act)) {
3788 cur.pos(cur.pos() - 1);
3789 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3790 cur.pos(cur.pos() - 1);
3794 // now we have to pay attention if the actual table is the
3795 // main row of TableContRows and if yes to delete all of them
3800 // delete up to the next row
3801 while (cur.pos() < cur.par()->Last() &&
3803 || !cur.par()->table->IsFirstCell(cell_act))) {
3804 while (cur.pos() < cur.par()->Last() &&
3805 !cur.par()->IsNewline(cur.pos()))
3806 cur.par()->Erase(cur.pos());
3809 if (cur.pos() < cur.par()->Last())
3810 cur.par()->Erase(cur.pos());
3812 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3813 cur.pos(cur.pos() - 1);
3814 cur.par()->Erase(cur.pos()); // no newline at very end!
3816 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3817 !cur.par()->table->IsContRow(cell_org) &&
3818 cur.par()->table->IsContRow(cell));
3819 cur.par()->table->DeleteRow(cell_org);
3826 bool LyXText::IsEmptyTableCell() const
3828 LyXParagraph::size_type pos = cursor.pos() - 1;
3829 while (pos >= 0 && pos < cursor.par()->Last()
3830 && !cursor.par()->IsNewline(pos))
3832 return cursor.par()->IsNewline(pos + 1);
3837 void LyXText::toggleAppendix(BufferView * bview)
3840 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3842 LyXParagraph * par = cursor.par();
3844 bool start = !par->start_of_appendix;
3846 // ensure that we have only one start_of_appendix in this document
3847 LyXParagraph * tmp = FirstParagraph();
3848 for (; tmp; tmp = tmp->next)
3849 tmp->start_of_appendix = 0;
3850 par->start_of_appendix = start;
3852 // we can set the refreshing parameters now
3853 status = LyXText::NEED_MORE_REFRESH;
3855 refresh_row = 0; // not needed for full update
3856 UpdateCounters(bview, 0);
3857 SetCursor(bview, cursor.par(), cursor.pos());
3861 LyXParagraph * LyXText::OwnerParagraph() const
3864 return inset_owner->par;
3866 return bv_owner->buffer()->paragraph;
3870 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3873 inset_owner->par = p;
3875 bv_owner->buffer()->paragraph = p;