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());
1534 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1536 char const * widthp,
1537 int alignment, bool hfill,
1538 bool start_minipage)
1540 LyXCursor tmpcursor = cursor;
1541 LyXParagraph * tmppar;
1543 sel_start_cursor = cursor;
1544 sel_end_cursor = cursor;
1547 // make sure that the depth behind the selection are restored, too
1549 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1551 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1553 LyXParagraph * undoendpar = endpar;
1555 if (endpar && endpar->GetDepth()) {
1556 while (endpar && endpar->GetDepth()) {
1558 endpar = endpar->LastPhysicalPar()->Next();
1560 endpar = endpar->Next();
1562 undoendpar = endpar;
1566 endpar = endpar->Next(); // because of parindents etc.
1569 SetUndo(bview->buffer(), Undo::EDIT,
1572 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1574 sel_start_cursor.par()->previous,
1578 tmppar = sel_end_cursor.par();
1580 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1581 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1583 while(tmppar != sel_start_cursor.par()->Previous()) {
1584 SetCursor(bview, tmppar, 0);
1586 status = LyXText::NEED_MORE_REFRESH;
1587 refresh_row = cursor.row();
1588 refresh_y = cursor.y() - cursor.row()->baseline();
1590 if (cursor.par()->footnoteflag ==
1591 sel_start_cursor.par()->footnoteflag) {
1593 if (type == LyXParagraph::PEXTRA_NONE) {
1594 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1595 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1596 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1599 cursor.par()->SetPExtraType(bview->buffer()->params,
1600 type, width, widthp);
1601 cursor.par()->pextra_hfill = hfill;
1602 cursor.par()->pextra_start_minipage = start_minipage;
1603 cursor.par()->pextra_alignment = alignment;
1607 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1609 tmppar = cursor.par()->Previous();
1612 RedoParagraphs(bview, sel_start_cursor, endpar);
1614 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1615 sel_cursor = cursor;
1616 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1618 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1622 char loweralphaCounter(int n)
1624 if (n < 1 || n > 26)
1631 char alphaCounter(int n)
1633 if (n < 1 || n > 26)
1640 char hebrewCounter(int n)
1642 static const char hebrew[22] = {
1643 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1644 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1645 '÷', 'ø', 'ù', 'ú'
1647 if (n < 1 || n > 22)
1655 char const * romanCounter(int n)
1657 static char const * roman[20] = {
1658 "i", "ii", "iii", "iv", "v",
1659 "vi", "vii", "viii", "ix", "x",
1660 "xi", "xii", "xiii", "xiv", "xv",
1661 "xvi", "xvii", "xviii", "xix", "xx"
1663 if (n < 1 || n > 20)
1670 // set the counter of a paragraph. This includes the labels
1671 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1674 // this is only relevant for the beginning of paragraph
1675 par = par->FirstPhysicalPar();
1677 LyXLayout const & layout =
1678 textclasslist.Style(buf->params.textclass,
1681 LyXTextClass const & textclass =
1682 textclasslist.TextClass(buf->params.textclass);
1684 /* copy the prev-counters to this one, unless this is the start of a
1685 footnote or of a bibliography or the very first paragraph */
1688 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1689 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1690 && par->footnotekind == LyXParagraph::FOOTNOTE)
1692 && !(textclasslist.Style(buf->params.textclass,
1693 par->Previous()->GetLayout()
1694 ).labeltype != LABEL_BIBLIO
1695 && layout.labeltype == LABEL_BIBLIO)) {
1696 for (int i = 0; i < 10; ++i) {
1697 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1700 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1702 par->appendix = par->Previous()->appendix;
1704 if (!par->appendix && par->start_of_appendix){
1705 par->appendix = true;
1706 for (int i = 0; i < 10; ++i) {
1707 par->setCounter(i, 0);
1711 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1712 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1714 par->enumdepth = par->Previous()->enumdepth;
1715 par->itemdepth = par->Previous()->itemdepth;
1718 for (int i = 0; i < 10; ++i) {
1719 par->setCounter(i, 0);
1721 par->appendix = par->start_of_appendix;
1727 // if this is an open marginnote and this is the first
1728 // entry in the marginnote and the enclosing
1729 // environment is an enum/item then correct for the
1730 // LaTeX behaviour (ARRae)
1731 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1732 && par->footnotekind == LyXParagraph::MARGIN
1734 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1735 && (par->PreviousBeforeFootnote()
1736 && textclasslist.Style(buf->params.textclass,
1737 par->PreviousBeforeFootnote()->GetLayout()
1738 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1739 // Any itemize or enumerate environment in a marginnote
1740 // that is embedded in an itemize or enumerate
1741 // paragraph is seen by LaTeX as being at a deeper
1742 // level within that enclosing itemization/enumeration
1743 // even if there is a "standard" layout at the start of
1749 /* Maybe we have to increment the enumeration depth.
1750 * BUT, enumeration in a footnote is considered in isolation from its
1751 * surrounding paragraph so don't increment if this is the
1752 * first line of the footnote
1753 * AND, bibliographies can't have their depth changed ie. they
1754 * are always of depth 0
1757 && par->Previous()->GetDepth() < par->GetDepth()
1758 && textclasslist.Style(buf->params.textclass,
1759 par->Previous()->GetLayout()
1760 ).labeltype == LABEL_COUNTER_ENUMI
1761 && par->enumdepth < 3
1763 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1764 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1765 && par->footnotekind == LyXParagraph::FOOTNOTE)
1767 && layout.labeltype != LABEL_BIBLIO) {
1771 /* Maybe we have to decrement the enumeration depth, see note above */
1773 && par->Previous()->GetDepth() > par->GetDepth()
1775 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1776 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1777 && par->footnotekind == LyXParagraph::FOOTNOTE)
1779 && layout.labeltype != LABEL_BIBLIO) {
1780 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1781 par->setCounter(6 + par->enumdepth,
1782 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1783 /* reset the counters.
1784 * A depth change is like a breaking layout
1786 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1787 par->setCounter(i, 0);
1790 if (!par->labelstring.empty()) {
1791 par->labelstring.erase();
1794 if (layout.margintype == MARGIN_MANUAL) {
1795 if (par->labelwidthstring.empty()) {
1796 par->SetLabelWidthString(layout.labelstring());
1799 par->SetLabelWidthString(string());
1802 /* is it a layout that has an automatic label ? */
1803 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1805 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1806 if (i >= 0 && i<= buf->params.secnumdepth) {
1807 par->incCounter(i); // increment the counter
1809 // Is there a label? Useful for Chapter layout
1810 if (!par->appendix){
1811 if (!layout.labelstring().empty())
1812 par->labelstring = layout.labelstring();
1814 par->labelstring.erase();
1816 if (!layout.labelstring_appendix().empty())
1817 par->labelstring = layout.labelstring_appendix();
1819 par->labelstring.erase();
1823 std::ostringstream s;
1827 if (!par->appendix) {
1828 switch (2 * LABEL_COUNTER_CHAPTER -
1829 textclass.maxcounter() + i) {
1830 case LABEL_COUNTER_CHAPTER:
1831 s << par->getCounter(i);
1833 case LABEL_COUNTER_SECTION:
1834 s << par->getCounter(i - 1) << '.'
1835 << par->getCounter(i);
1837 case LABEL_COUNTER_SUBSECTION:
1838 s << par->getCounter(i - 2) << '.'
1839 << par->getCounter(i - 1) << '.'
1840 << par->getCounter(i);
1842 case LABEL_COUNTER_SUBSUBSECTION:
1843 s << par->getCounter(i - 3) << '.'
1844 << par->getCounter(i - 2) << '.'
1845 << par->getCounter(i - 1) << '.'
1846 << par->getCounter(i);
1849 case LABEL_COUNTER_PARAGRAPH:
1850 s << par->getCounter(i - 4) << '.'
1851 << par->getCounter(i - 3) << '.'
1852 << par->getCounter(i - 2) << '.'
1853 << par->getCounter(i - 1) << '.'
1854 << par->getCounter(i);
1856 case LABEL_COUNTER_SUBPARAGRAPH:
1857 s << par->getCounter(i - 5) << '.'
1858 << par->getCounter(i - 4) << '.'
1859 << par->getCounter(i - 3) << '.'
1860 << par->getCounter(i - 2) << '.'
1861 << par->getCounter(i - 1) << '.'
1862 << par->getCounter(i);
1866 // Can this ever be reached? And in the
1867 // case it is, how can this be correct?
1869 s << par->getCounter(i) << '.';
1872 } else { // appendix
1873 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1874 case LABEL_COUNTER_CHAPTER:
1875 if (par->isRightToLeftPar(buf->params))
1876 s << hebrewCounter(par->getCounter(i));
1878 s << alphaCounter(par->getCounter(i));
1880 case LABEL_COUNTER_SECTION:
1881 if (par->isRightToLeftPar(buf->params))
1882 s << hebrewCounter(par->getCounter(i - 1));
1884 s << alphaCounter(par->getCounter(i - 1));
1887 << par->getCounter(i);
1890 case LABEL_COUNTER_SUBSECTION:
1891 if (par->isRightToLeftPar(buf->params))
1892 s << hebrewCounter(par->getCounter(i - 2));
1894 s << alphaCounter(par->getCounter(i - 2));
1897 << par->getCounter(i-1) << '.'
1898 << par->getCounter(i);
1901 case LABEL_COUNTER_SUBSUBSECTION:
1902 if (par->isRightToLeftPar(buf->params))
1903 s << hebrewCounter(par->getCounter(i-3));
1905 s << alphaCounter(par->getCounter(i-3));
1908 << par->getCounter(i-2) << '.'
1909 << par->getCounter(i-1) << '.'
1910 << par->getCounter(i);
1913 case LABEL_COUNTER_PARAGRAPH:
1914 if (par->isRightToLeftPar(buf->params))
1915 s << hebrewCounter(par->getCounter(i-4));
1917 s << alphaCounter(par->getCounter(i-4));
1920 << par->getCounter(i-3) << '.'
1921 << par->getCounter(i-2) << '.'
1922 << par->getCounter(i-1) << '.'
1923 << par->getCounter(i);
1926 case LABEL_COUNTER_SUBPARAGRAPH:
1927 if (par->isRightToLeftPar(buf->params))
1928 s << hebrewCounter(par->getCounter(i-5));
1930 s << alphaCounter(par->getCounter(i-5));
1933 << par->getCounter(i-4) << '.'
1934 << par->getCounter(i-3) << '.'
1935 << par->getCounter(i-2) << '.'
1936 << par->getCounter(i-1) << '.'
1937 << par->getCounter(i);
1941 // Can this ever be reached? And in the
1942 // case it is, how can this be correct?
1944 s << par->getCounter(i) << '.';
1950 par->labelstring += s.str().c_str();
1951 // We really want to remove the c_str as soon as
1955 char * tmps = s.str();
1956 par->labelstring += tmps;
1960 for (i++; i < 10; ++i) {
1961 // reset the following counters
1962 par->setCounter(i, 0);
1964 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1965 for (i++; i < 10; ++i) {
1966 // reset the following counters
1967 par->setCounter(i, 0);
1969 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1970 par->incCounter(i + par->enumdepth);
1971 int number = par->getCounter(i + par->enumdepth);
1974 std::ostringstream s;
1978 switch (par->enumdepth) {
1980 if (par->isRightToLeftPar(buf->params))
1982 << hebrewCounter(number)
1986 << loweralphaCounter(number)
1990 if (par->isRightToLeftPar(buf->params))
1991 s << '.' << romanCounter(number);
1993 s << romanCounter(number) << '.';
1996 if (par->isRightToLeftPar(buf->params))
1998 << alphaCounter(number);
2000 s << alphaCounter(number)
2004 if (par->isRightToLeftPar(buf->params))
2011 par->labelstring = s.str().c_str();
2012 // we really want to get rid of that c_str()
2015 char * tmps = s.str();
2016 par->labelstring = tmps;
2020 for (i += par->enumdepth + 1; i < 10; ++i)
2021 par->setCounter(i, 0); /* reset the following counters */
2024 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2025 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2027 int number = par->getCounter(i);
2029 par->bibkey = new InsetBibKey();
2030 par->bibkey->setCounter(number);
2031 par->labelstring = layout.labelstring();
2033 // In biblio should't be following counters but...
2035 string s = layout.labelstring();
2037 // the caption hack:
2038 if (layout.labeltype == LABEL_SENSITIVE) {
2039 bool isOK (par->InInset() && par->InInset()->owner() &&
2040 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2042 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2043 && (par->footnotekind == LyXParagraph::FIG
2044 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2045 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2046 ? ":øåéà " : "Figure:";
2047 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2048 && (par->footnotekind == LyXParagraph::TAB
2049 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2050 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2051 ? ":äìáè" : "Table:";
2052 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2053 && par->footnotekind == LyXParagraph::ALGORITHM) {
2054 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2055 ? ":Ãúéøåâìà " : "Algorithm:";
2059 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2061 = floatList.getType(tmp->type());
2062 // We should get the correct number here too.
2063 s = fl.name + " #:";
2065 /* par->SetLayout(0);
2066 s = layout->labelstring; */
2067 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2068 ? " :úåòîùî øñç" : "Senseless: ";
2071 par->labelstring = s;
2073 /* reset the enumeration counter. They are always resetted
2074 * when there is any other layout between */
2075 for (int i = 6 + par->enumdepth; i < 10; ++i)
2076 par->setCounter(i, 0);
2081 /* Updates all counters BEHIND the row. Changed paragraphs
2082 * with a dynamic left margin will be rebroken. */
2083 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2090 if (row->par()->next
2092 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2096 par = row->par()->LastPhysicalPar()->Next();
2098 par = row->par()->Next();
2101 par = row->par()->next;
2106 while (row->par() != par)
2109 SetCounter(bview->buffer(), par);
2111 /* now check for the headline layouts. remember that they
2112 * have a dynamic left margin */
2117 ( textclasslist.Style(bview->buffer()->params.textclass,
2118 par->layout).margintype == MARGIN_DYNAMIC
2119 || textclasslist.Style(bview->buffer()->params.textclass,
2120 par->layout).labeltype == LABEL_SENSITIVE)
2123 /* Rebreak the paragraph */
2124 RemoveParagraph(row);
2125 AppendParagraph(bview, row);
2128 /* think about the damned open footnotes! */
2129 while (par->Next() &&
2130 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2131 || par->Next()->IsDummy())){
2133 if (par->IsDummy()) {
2134 while (row->par() != par)
2136 RemoveParagraph(row);
2137 AppendParagraph(bview, row);
2143 par = par->LastPhysicalPar()->Next();
2152 /* insets an inset. */
2153 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2155 if (!cursor.par()->InsertInsetAllowed(inset))
2157 SetUndo(bview->buffer(), Undo::INSERT,
2159 cursor.par()->ParFromPos(cursor.pos())->previous,
2160 cursor.par()->ParFromPos(cursor.pos())->next
2162 cursor.par()->previous,
2166 cursor.par()->InsertInset(cursor.pos(), inset);
2167 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2168 * The character will not be inserted a
2173 void LyXText::copyEnvironmentType()
2175 copylayouttype = cursor.par()->GetLayout();
2179 void LyXText::pasteEnvironmentType(BufferView * bview)
2181 SetLayout(bview, copylayouttype);
2185 void LyXText::CutSelection(BufferView * bview, bool doclear)
2187 // Stuff what we got on the clipboard. Even if there is no selection.
2189 // There is a problem with having the stuffing here in that the
2190 // larger the selection the slower LyX will get. This can be
2191 // solved by running the line below only when the selection has
2192 // finished. The solution used currently just works, to make it
2193 // faster we need to be more clever and probably also have more
2194 // calls to stuffClipboard. (Lgb)
2195 bview->stuffClipboard(selectionAsString(bview->buffer()));
2197 // This doesn't make sense, if there is no selection
2201 // OK, we have a selection. This is always between sel_start_cursor
2202 // and sel_end cursor
2204 // Check whether there are half footnotes in the selection
2205 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2206 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2207 LyXParagraph * tmppar = sel_start_cursor.par();
2208 while (tmppar != sel_end_cursor.par()){
2209 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2210 WriteAlert(_("Impossible operation"),
2211 _("Don't know what to do with half floats."),
2215 tmppar = tmppar->Next();
2220 /* table stuff -- begin */
2221 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2222 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2223 WriteAlert(_("Impossible operation"),
2224 _("Don't know what to do with half tables."),
2228 sel_start_cursor.par()->table->Reinit();
2230 /* table stuff -- end */
2232 // make sure that the depth behind the selection are restored, too
2234 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2236 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2238 LyXParagraph * undoendpar = endpar;
2240 if (endpar && endpar->GetDepth()) {
2241 while (endpar && endpar->GetDepth()) {
2243 endpar = endpar->LastPhysicalPar()->Next();
2245 endpar = endpar->Next();
2247 undoendpar = endpar;
2249 } else if (endpar) {
2250 endpar = endpar->Next(); // because of parindents etc.
2253 SetUndo(bview->buffer(), Undo::DELETE,
2256 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2258 sel_start_cursor.par()->previous,
2264 // there are two cases: cut only within one paragraph or
2265 // more than one paragraph
2267 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2268 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2270 if (sel_start_cursor.par() == sel_end_cursor.par())
2273 // only within one paragraph
2274 endpar = sel_start_cursor.par();
2275 int pos = sel_end_cursor.pos();
2276 cap.cutSelection(sel_start_cursor.par(), &endpar,
2277 sel_start_cursor.pos(), pos,
2278 bview->buffer()->params.textclass, doclear);
2279 sel_end_cursor.pos(pos);
2281 endpar = sel_end_cursor.par();
2283 int pos = sel_end_cursor.pos();
2284 cap.cutSelection(sel_start_cursor.par(), &endpar,
2285 sel_start_cursor.pos(), pos,
2286 bview->buffer()->params.textclass, doclear);
2288 sel_end_cursor.par(endpar);
2289 sel_end_cursor.pos(pos);
2290 cursor.pos(sel_end_cursor.pos());
2292 endpar = endpar->Next();
2294 // sometimes necessary
2296 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2298 RedoParagraphs(bview, sel_start_cursor, endpar);
2301 cursor = sel_start_cursor;
2302 SetCursor(bview, cursor.par(), cursor.pos());
2303 sel_cursor = cursor;
2304 UpdateCounters(bview, cursor.row());
2308 void LyXText::CopySelection(BufferView * bview)
2310 // Stuff what we got on the clipboard. Even if there is no selection.
2312 // There is a problem with having the stuffing here in that the
2313 // larger the selection the slower LyX will get. This can be
2314 // solved by running the line below only when the selection has
2315 // finished. The solution used currently just works, to make it
2316 // faster we need to be more clever and probably also have more
2317 // calls to stuffClipboard. (Lgb)
2318 bview->stuffClipboard(selectionAsString(bview->buffer()));
2320 // this doesnt make sense, if there is no selection
2324 // ok we have a selection. This is always between sel_start_cursor
2325 // and sel_end cursor
2328 /* check wether there are half footnotes in the selection */
2329 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2330 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2331 LyXParagraph * tmppar = sel_start_cursor.par();
2332 while (tmppar != sel_end_cursor.par()) {
2333 if (tmppar->footnoteflag !=
2334 sel_end_cursor.par()->footnoteflag) {
2335 WriteAlert(_("Impossible operation"),
2336 _("Don't know what to do"
2337 " with half floats."),
2341 tmppar = tmppar->Next();
2346 /* table stuff -- begin */
2347 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2348 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2349 WriteAlert(_("Impossible operation"),
2350 _("Don't know what to do with half tables."),
2355 /* table stuff -- end */
2358 // copy behind a space if there is one
2359 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2360 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2361 && (sel_start_cursor.par() != sel_end_cursor.par()
2362 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2363 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2367 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2368 sel_start_cursor.pos(), sel_end_cursor.pos(),
2369 bview->buffer()->params.textclass);
2373 void LyXText::PasteSelection(BufferView * bview)
2377 // this does not make sense, if there is nothing to paste
2378 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2381 SetUndo(bview->buffer(), Undo::INSERT,
2383 cursor.par()->ParFromPos(cursor.pos())->previous,
2384 cursor.par()->ParFromPos(cursor.pos())->next
2386 cursor.par()->previous,
2391 LyXParagraph * endpar;
2392 LyXParagraph * actpar = cursor.par();
2394 int pos = cursor.pos();
2395 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2397 RedoParagraphs(bview, cursor, endpar);
2399 SetCursor(bview, cursor.par(), cursor.pos());
2402 sel_cursor = cursor;
2403 SetCursor(bview, actpar, pos);
2405 UpdateCounters(bview, cursor.row());
2409 // returns a pointer to the very first LyXParagraph
2410 LyXParagraph * LyXText::FirstParagraph() const
2412 return OwnerParagraph();
2416 // returns true if the specified string is at the specified position
2417 bool LyXText::IsStringInText(LyXParagraph * par,
2418 LyXParagraph::size_type pos,
2419 char const * str) const
2423 while (pos + i < par->Last() && str[i] &&
2424 str[i] == par->GetChar(pos + i)) {
2434 // sets the selection over the number of characters of string, no check!!
2435 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2437 sel_cursor = cursor;
2438 for (int i = 0; string[i]; ++i)
2444 // simple replacing. The font of the first selected character is used
2445 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2447 SetCursorParUndo(bview->buffer());
2450 if (!selection) { // create a dummy selection
2451 sel_end_cursor = cursor;
2452 sel_start_cursor = cursor;
2455 // Get font setting before we cut
2456 LyXParagraph::size_type pos = sel_end_cursor.pos();
2457 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2458 sel_start_cursor.pos());
2460 // Insert the new string
2461 for (int i = 0; str[i]; ++i) {
2462 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2466 // Cut the selection
2467 CutSelection(bview);
2473 // if the string can be found: return true and set the cursor to
2475 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2477 LyXParagraph * par = cursor.par();
2478 LyXParagraph::size_type pos = cursor.pos();
2479 while (par && !IsStringInText(par, pos, str)) {
2480 if (pos < par->Last() - 1)
2488 SetCursor(bview, par, pos);
2496 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2498 LyXParagraph * par = cursor.par();
2499 int pos = cursor.pos();
2505 // We skip empty paragraphs (Asger)
2507 par = par->Previous();
2509 pos = par->Last() - 1;
2510 } while (par && pos < 0);
2512 } while (par && !IsStringInText(par, pos, string));
2515 SetCursor(bview, par, pos);
2522 // needed to insert the selection
2523 void LyXText::InsertStringA(BufferView * bview, string const & str)
2525 LyXParagraph * par = cursor.par();
2526 LyXParagraph::size_type pos = cursor.pos();
2527 LyXParagraph::size_type a = 0;
2528 LyXParagraph * endpar = cursor.par()->Next();
2530 SetCursorParUndo(bview->buffer());
2533 textclasslist.Style(bview->buffer()->params.textclass,
2534 cursor.par()->GetLayout()).isEnvironment();
2535 // only to be sure, should not be neccessary
2538 // insert the string, don't insert doublespace
2539 string::size_type i = 0;
2540 while (i < str.length()) {
2541 if (str[i] != '\n') {
2543 && i + 1 < str.length() && str[i + 1] != ' '
2544 && pos && par->GetChar(pos - 1)!= ' ') {
2545 par->InsertChar(pos, ' ', current_font);
2548 } else if (par->table) {
2549 if (str[i] == '\t') {
2550 while((pos < par->size()) &&
2551 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2553 if (pos < par->size())
2555 else // no more fields to fill skip the rest
2557 } else if ((str[i] != 13) &&
2558 ((str[i] & 127) >= ' ')) {
2559 par->InsertChar(pos, str[i],
2564 } else if (str[i] == ' ') {
2565 InsetSpecialChar * new_inset =
2566 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2567 if (par->InsertInsetAllowed(new_inset)) {
2568 par->InsertInset(pos, new_inset,
2574 } else if (str[i] == '\t') {
2575 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2576 InsetSpecialChar * new_inset =
2577 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2578 if (par->InsertInsetAllowed(new_inset)) {
2579 par->InsertInset(pos, new_inset,
2586 } else if (str[i] != 13 &&
2587 // Ignore unprintables
2588 (str[i] & 127) >= ' ') {
2589 par->InsertChar(pos, str[i], current_font);
2595 if ((i + 1) >= str.length()) {
2596 if (pos < par->size())
2600 while((pos < par->size()) &&
2601 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2604 int cell = NumberOfCell(par, pos);
2605 while((pos < par->size()) &&
2606 !(par->table->IsFirstCell(cell))) {
2608 while((pos < par->size()) &&
2609 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2612 cell = NumberOfCell(par, pos);
2614 if (pos >= par->size())
2615 // no more fields to fill skip the rest
2619 if (!par->size()) { // par is empty
2620 InsetSpecialChar * new_inset =
2621 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2622 if (par->InsertInsetAllowed(new_inset)) {
2623 par->InsertInset(pos,
2631 par->BreakParagraph(bview->buffer()->params, pos, flag);
2641 RedoParagraphs(bview, cursor, endpar);
2642 SetCursor(bview, cursor.par(), cursor.pos());
2643 sel_cursor = cursor;
2644 SetCursor(bview, par, pos);
2649 /* turns double-CR to single CR, others where converted into one blank and 13s
2650 * that are ignored .Double spaces are also converted into one. Spaces at
2651 * the beginning of a paragraph are forbidden. tabs are converted into one
2652 * space. then InsertStringA is called */
2653 void LyXText::InsertStringB(BufferView * bview, string const & s)
2657 LyXParagraph * par = cursor.par();
2659 string::size_type i = 1;
2660 while (i < str.length()) {
2667 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2669 if (str[i] == '\n' && i + 1 < str.length()
2674 if (str[i + 1] != '\n') {
2675 if (str[i - 1] != ' ')
2680 while (i + 1 < str.length()
2681 && (str[i + 1] == ' '
2682 || str[i + 1] == '\t'
2683 || str[i + 1] == '\n'
2684 || str[i + 1] == 13)) {
2691 InsertStringA(bview, str);
2695 bool LyXText::GotoNextError(BufferView * bview) const
2697 LyXCursor res = cursor;
2699 if (res.pos() < res.par()->Last() - 1) {
2700 res.pos(res.pos() + 1);
2702 res.par(res.par()->Next());
2706 } while (res.par() &&
2707 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2708 && res.par()->GetInset(res.pos())->AutoDelete()));
2711 SetCursor(bview, res.par(), res.pos());
2718 bool LyXText::GotoNextNote(BufferView * bview) const
2720 LyXCursor res = cursor;
2722 if (res.pos() < res.par()->Last() - 1) {
2723 res.pos(res.pos() + 1);
2725 res.par(res.par()->Next());
2729 } while (res.par() &&
2730 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2731 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2734 SetCursor(bview, res.par(), res.pos());
2741 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2742 LyXParagraph::size_type pos)
2744 LyXCursor tmpcursor;
2747 /* table stuff -- begin*/
2750 CheckParagraphInTable(bview, par, pos);
2754 /* table stuff -- end*/
2757 LyXParagraph::size_type z;
2758 Row * row = GetRow(par, pos, y);
2760 // is there a break one row above
2761 if (row->previous() && row->previous()->par() == row->par()) {
2762 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2763 if ( z >= row->pos()) {
2764 // set the dimensions of the row above
2765 y -= row->previous()->height();
2767 refresh_row = row->previous();
2768 status = LyXText::NEED_MORE_REFRESH;
2770 BreakAgain(bview, row->previous());
2772 // set the cursor again. Otherwise
2773 // dangling pointers are possible
2774 SetCursor(bview, cursor.par(), cursor.pos());
2775 sel_cursor = cursor;
2780 int tmpheight = row->height();
2781 LyXParagraph::size_type tmplast = RowLast(row);
2785 BreakAgain(bview, row);
2786 if (row->height() == tmpheight && RowLast(row) == tmplast)
2787 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2789 status = LyXText::NEED_MORE_REFRESH;
2791 // check the special right address boxes
2792 if (textclasslist.Style(bview->buffer()->params.textclass,
2793 par->GetLayout()).margintype
2794 == MARGIN_RIGHT_ADDRESS_BOX) {
2801 RedoDrawingOfParagraph(bview, tmpcursor);
2807 // set the cursor again. Otherwise dangling pointers are possible
2808 // also set the selection
2812 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2813 sel_cursor = cursor;
2814 SetCursorIntern(bview, sel_start_cursor.par(),
2815 sel_start_cursor.pos());
2816 sel_start_cursor = cursor;
2817 SetCursorIntern(bview, sel_end_cursor.par(),
2818 sel_end_cursor.pos());
2819 sel_end_cursor = cursor;
2820 SetCursorIntern(bview, last_sel_cursor.par(),
2821 last_sel_cursor.pos());
2822 last_sel_cursor = cursor;
2825 SetCursorIntern(bview, cursor.par(), cursor.pos());
2829 // returns false if inset wasn't found
2830 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2832 // first check the current paragraph
2833 int pos = cursor.par()->GetPositionOfInset(inset);
2835 CheckParagraph(bview, cursor.par(), pos);
2839 // check every paragraph
2841 LyXParagraph * par = FirstParagraph();
2844 // make sure the paragraph is open
2845 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2847 pos = par->GetPositionOfInset(inset);
2849 CheckParagraph(bview, par, pos);
2862 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2863 LyXParagraph::size_type pos,
2864 bool setfont, bool boundary) const
2866 LyXCursor old_cursor = cursor;
2867 SetCursorIntern(bview, par, pos, setfont, boundary);
2868 DeleteEmptyParagraphMechanism(bview, old_cursor);
2872 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2873 LyXParagraph::size_type pos, bool boundary) const
2876 // correct the cursor position if impossible
2877 if (pos > par->Last()){
2878 LyXParagraph * tmppar = par->ParFromPos(pos);
2879 pos = par->PositionInParFromPos(pos);
2882 if (par->IsDummy() && par->previous &&
2883 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2884 while (par->previous &&
2885 ((par->previous->IsDummy() &&
2886 (par->previous->previous->footnoteflag ==
2887 LyXParagraph::CLOSED_FOOTNOTE)) ||
2888 (par->previous->footnoteflag ==
2889 LyXParagraph::CLOSED_FOOTNOTE))) {
2890 par = par->previous ;
2891 if (par->IsDummy() &&
2892 (par->previous->footnoteflag ==
2893 LyXParagraph::CLOSED_FOOTNOTE))
2894 pos += par->size() + 1;
2896 if (par->previous) {
2897 par = par->previous;
2899 pos += par->size() + 1;
2904 cur.boundary(boundary);
2906 /* get the cursor y position in text */
2908 Row * row = GetRow(par, pos, y);
2909 /* y is now the beginning of the cursor row */
2910 y += row->baseline();
2911 /* y is now the cursor baseline */
2914 /* now get the cursors x position */
2916 float fill_separator, fill_hfill, fill_label_hfill;
2917 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2919 LyXParagraph::size_type cursor_vpos = 0;
2920 LyXParagraph::size_type last = RowLastPrintable(row);
2922 if (pos > last + 1) // This shouldn't happen.
2924 else if (pos < row->pos())
2927 if (last < row->pos())
2928 cursor_vpos = row->pos();
2929 else if (pos > last && !boundary)
2930 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2931 ? row->pos() : last + 1;
2932 else if (pos > row->pos() &&
2933 (pos > last || boundary
2935 || (row->par()->table && row->par()->IsNewline(pos))
2938 /// Place cursor after char at (logical) position pos - 1
2939 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2940 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2942 /// Place cursor before char at (logical) position pos
2943 cursor_vpos = (bidi_level(pos) % 2 == 0)
2944 ? log2vis(pos) : log2vis(pos) + 1;
2947 /* table stuff -- begin*/
2948 if (row->par()->table) {
2949 int cell = NumberOfCell(row->par(), row->pos());
2951 x += row->par()->table->GetBeginningOfTextInCell(cell);
2952 for (LyXParagraph::size_type vpos = row->pos();
2953 vpos < cursor_vpos; ++vpos) {
2954 pos = vis2log(vpos);
2955 if (row->par()->IsNewline(pos)) {
2956 x = x_old + row->par()->table->WidthOfColumn(cell);
2959 x += row->par()->table->GetBeginningOfTextInCell(cell);
2961 x += SingleWidth(bview, row->par(), pos);
2965 /* table stuff -- end*/
2967 LyXParagraph::size_type main_body =
2968 BeginningOfMainBody(bview->buffer(), row->par());
2969 if ((main_body > 0) &&
2970 ((main_body-1 > last) ||
2971 !row->par()->IsLineSeparator(main_body-1)))
2974 for (LyXParagraph::size_type vpos = row->pos();
2975 vpos < cursor_vpos; ++vpos) {
2976 pos = vis2log(vpos);
2977 if (main_body > 0 && pos == main_body-1) {
2978 x += fill_label_hfill +
2979 lyxfont::width(textclasslist.Style(
2980 bview->buffer()->params.textclass,
2981 row->par()->GetLayout())
2983 GetFont(bview->buffer(), row->par(), -2));
2984 if (row->par()->IsLineSeparator(main_body-1))
2985 x -= SingleWidth(bview, row->par(),main_body-1);
2987 if (HfillExpansion(bview->buffer(), row, pos)) {
2988 x += SingleWidth(bview, row->par(), pos);
2989 if (pos >= main_body)
2992 x += fill_label_hfill;
2993 } else if (row->par()->IsSeparator(pos)) {
2994 x += SingleWidth(bview, row->par(), pos);
2995 if (pos >= main_body)
2996 x += fill_separator;
2998 x += SingleWidth(bview, row->par(), pos);
3010 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3011 LyXParagraph::size_type pos,
3012 bool setfont, bool boundary) const
3014 SetCursor(bview, cursor, par, pos, boundary);
3016 SetCurrentFont(bview);
3019 void LyXText::SetCurrentFont(BufferView * bview) const
3021 LyXParagraph::size_type pos = cursor.pos();
3022 if (cursor.boundary() && pos > 0)
3026 if (pos == cursor.par()->Last()
3028 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3032 else if (cursor.par()->IsSeparator(pos)) {
3033 if (pos > cursor.row()->pos() &&
3034 bidi_level(pos) % 2 ==
3035 bidi_level(pos - 1) % 2)
3037 else if (pos + 1 < cursor.par()->Last())
3043 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3044 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3046 if (cursor.pos() == cursor.par()->Last() &&
3047 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3048 !cursor.boundary()) {
3049 Language const * lang =
3050 cursor.par()->getParLanguage(bview->buffer()->params);
3051 current_font.setLanguage(lang);
3052 real_current_font.setLanguage(lang);
3057 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3059 LyXCursor old_cursor = cursor;
3061 /* get the row first */
3063 Row * row = GetRowNearY(y);
3064 cursor.par(row->par());
3067 int column = GetColumnNearX(bview, row, x, bound);
3068 cursor.pos(row->pos() + column);
3070 cursor.y(y + row->baseline());
3072 cursor.boundary(bound);
3073 SetCurrentFont(bview);
3074 DeleteEmptyParagraphMechanism(bview, old_cursor);
3078 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3079 int x, long y) const
3081 /* get the row first */
3083 Row * row = GetRowNearY(y);
3085 int column = GetColumnNearX(bview, row, x, bound);
3087 cur.par(row->par());
3088 cur.pos(row->pos() + column);
3090 cur.y(y + row->baseline());
3092 cur.boundary(bound);
3096 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3098 CursorLeftIntern(bview, internal);
3100 if (cursor.par()->table) {
3101 int cell = NumberOfCell(cursor.par(), cursor.pos());
3102 if (cursor.par()->table->IsContRow(cell)
3103 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3111 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3113 if (cursor.pos() > 0) {
3114 bool boundary = cursor.boundary();
3115 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3116 if (!internal && !boundary &&
3117 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3118 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3119 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3120 LyXParagraph * par = cursor.par()->Previous();
3121 SetCursor(bview, par, par->Last());
3126 void LyXText::CursorRight(BufferView * bview, bool internal) const
3128 CursorRightIntern(bview, internal);
3130 if (cursor.par()->table) {
3131 int cell = NumberOfCell(cursor.par(), cursor.pos());
3132 if (cursor.par()->table->IsContRow(cell) &&
3133 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3141 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3143 if (!internal && cursor.boundary() &&
3146 !cursor.par()->table ||
3148 !cursor.par()->IsNewline(cursor.pos())))
3149 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3150 else if (cursor.pos() < cursor.par()->Last()) {
3151 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3153 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3154 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3155 } else if (cursor.par()->Next())
3156 SetCursor(bview, cursor.par()->Next(), 0);
3160 void LyXText::CursorUp(BufferView * bview) const
3162 SetCursorFromCoordinates(bview, cursor.x_fix(),
3163 cursor.y() - cursor.row()->baseline() - 1);
3165 if (cursor.par()->table) {
3166 int cell = NumberOfCell(cursor.par(), cursor.pos());
3167 if (cursor.par()->table->IsContRow(cell) &&
3168 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3176 void LyXText::CursorDown(BufferView * bview) const
3179 if (cursor.par()->table &&
3180 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3181 !cursor.par()->next)
3185 SetCursorFromCoordinates(bview, cursor.x_fix(),
3186 cursor.y() - cursor.row()->baseline()
3187 + cursor.row()->height() + 1);
3189 if (cursor.par()->table) {
3190 int cell = NumberOfCell(cursor.par(), cursor.pos());
3191 int cell_above = cursor.par()->table->GetCellAbove(cell);
3192 while(cursor.par()->table &&
3193 cursor.par()->table->IsContRow(cell) &&
3194 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3195 SetCursorFromCoordinates(bview, cursor.x_fix(),
3196 cursor.y() - cursor.row()->baseline()
3197 + cursor.row()->height() + 1);
3198 if (cursor.par()->table) {
3199 cell = NumberOfCell(cursor.par(), cursor.pos());
3200 cell_above = cursor.par()->table->GetCellAbove(cell);
3208 void LyXText::CursorUpParagraph(BufferView * bview) const
3210 if (cursor.pos() > 0) {
3211 SetCursor(bview, cursor.par(), 0);
3213 else if (cursor.par()->Previous()) {
3214 SetCursor(bview, cursor.par()->Previous(), 0);
3219 void LyXText::CursorDownParagraph(BufferView * bview) const
3221 if (cursor.par()->Next()) {
3222 SetCursor(bview, cursor.par()->Next(), 0);
3224 SetCursor(bview, cursor.par(), cursor.par()->Last());
3229 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3230 LyXCursor const & old_cursor) const
3232 // Would be wrong to delete anything if we have a selection.
3233 if (selection) return;
3235 // We allow all kinds of "mumbo-jumbo" when freespacing.
3236 if (textclasslist.Style(bview->buffer()->params.textclass,
3237 old_cursor.par()->GetLayout()).free_spacing)
3240 bool deleted = false;
3242 /* Ok I'll put some comments here about what is missing.
3243 I have fixed BackSpace (and thus Delete) to not delete
3244 double-spaces automagically. I have also changed Cut,
3245 Copy and Paste to hopefully do some sensible things.
3246 There are still some small problems that can lead to
3247 double spaces stored in the document file or space at
3248 the beginning of paragraphs. This happens if you have
3249 the cursor betwenn to spaces and then save. Or if you
3250 cut and paste and the selection have a space at the
3251 beginning and then save right after the paste. I am
3252 sure none of these are very hard to fix, but I will
3253 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3254 that I can get some feedback. (Lgb)
3257 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3258 // delete the LineSeparator.
3261 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3262 // delete the LineSeparator.
3265 // If the pos around the old_cursor were spaces, delete one of them.
3266 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3267 // Only if the cursor has really moved
3269 if (old_cursor.pos() > 0
3270 && old_cursor.pos() < old_cursor.par()->Last()
3271 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3272 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3273 old_cursor.par()->Erase(old_cursor.pos() - 1);
3274 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3276 if (old_cursor.par() == cursor.par() &&
3277 cursor.pos() > old_cursor.pos()) {
3278 SetCursorIntern(bview, cursor.par(),
3281 SetCursorIntern(bview, cursor.par(),
3287 // Do not delete empty paragraphs with keepempty set.
3288 if ((textclasslist.Style(bview->buffer()->params.textclass,
3289 old_cursor.par()->GetLayout())).keepempty)
3292 LyXCursor tmpcursor;
3294 if (old_cursor.par() != cursor.par()) {
3295 if ( (old_cursor.par()->Last() == 0
3296 || (old_cursor.par()->Last() == 1
3297 && old_cursor.par()->IsLineSeparator(0)))
3299 && old_cursor.par()->FirstPhysicalPar()
3300 == old_cursor.par()->LastPhysicalPar()
3303 // ok, we will delete anything
3305 // make sure that you do not delete any environments
3308 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3309 !(old_cursor.row()->previous()
3310 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3311 && !(old_cursor.row()->next()
3312 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3313 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3314 && ((old_cursor.row()->previous()
3315 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3316 || (old_cursor.row()->next()
3317 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3320 status = LyXText::NEED_MORE_REFRESH;
3323 if (old_cursor.row()->previous()) {
3324 refresh_row = old_cursor.row()->previous();
3325 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3327 cursor = old_cursor; // that undo can restore the right cursor position
3328 LyXParagraph * endpar = old_cursor.par()->next;
3329 if (endpar && endpar->GetDepth()) {
3330 while (endpar && endpar->GetDepth()) {
3332 endpar = endpar->LastPhysicalPar()->Next();
3334 endpar = endpar->Next();
3338 SetUndo(bview->buffer(), Undo::DELETE,
3339 old_cursor.par()->previous,
3344 RemoveRow(old_cursor.row());
3345 if (OwnerParagraph() == old_cursor.par()) {
3346 OwnerParagraph(OwnerParagraph()->next);
3349 delete old_cursor.par();
3351 /* Breakagain the next par. Needed
3352 * because of the parindent that
3353 * can occur or dissappear. The
3354 * next row can change its height,
3355 * if there is another layout before */
3356 if (refresh_row->next()) {
3357 BreakAgain(bview, refresh_row->next());
3358 UpdateCounters(bview, refresh_row);
3360 SetHeightOfRow(bview, refresh_row);
3362 refresh_row = old_cursor.row()->next();
3363 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3366 cursor = old_cursor; // that undo can restore the right cursor position
3367 LyXParagraph * endpar = old_cursor.par()->next;
3368 if (endpar && endpar->GetDepth()) {
3369 while (endpar && endpar->GetDepth()) {
3371 endpar = endpar->LastPhysicalPar()->Next();
3373 endpar = endpar->Next();
3377 SetUndo(bview->buffer(), Undo::DELETE,
3378 old_cursor.par()->previous,
3383 RemoveRow(old_cursor.row());
3385 if (OwnerParagraph() == old_cursor.par()) {
3386 OwnerParagraph(OwnerParagraph()->next);
3388 delete old_cursor.par();
3390 /* Breakagain the next par. Needed
3391 because of the parindent that can
3392 occur or dissappear.
3393 The next row can change its height,
3394 if there is another layout before
3397 BreakAgain(bview, refresh_row);
3398 UpdateCounters(bview, refresh_row->previous());
3404 SetCursorIntern(bview, cursor.par(), cursor.pos());
3406 if (sel_cursor.par() == old_cursor.par()
3407 && sel_cursor.pos() == sel_cursor.pos()) {
3408 // correct selection
3409 sel_cursor = cursor;
3416 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3417 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3419 SetCursorIntern(bview, cursor.par(), cursor.pos());
3420 sel_cursor = cursor;
3427 LyXParagraph * LyXText::GetParFromID(int id)
3429 LyXParagraph * result = FirstParagraph();
3430 while (result && result->id() != id)
3431 result = result->next;
3437 bool LyXText::TextUndo(BufferView * bview)
3441 // returns false if no undo possible
3442 Undo * undo = bview->buffer()->undostack.pop();
3446 bview->buffer()->redostack
3447 .push(CreateUndo(bview->buffer(), undo->kind,
3448 GetParFromID(undo->number_of_before_par),
3449 GetParFromID(undo->number_of_behind_par)));
3451 return TextHandleUndo(bview, undo);
3455 bool LyXText::TextRedo(BufferView * bview)
3459 // returns false if no redo possible
3460 Undo * undo = bview->buffer()->redostack.pop();
3464 bview->buffer()->undostack
3465 .push(CreateUndo(bview->buffer(), undo->kind,
3466 GetParFromID(undo->number_of_before_par),
3467 GetParFromID(undo->number_of_behind_par)));
3469 return TextHandleUndo(bview, undo);
3473 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3477 // returns false if no undo possible
3478 bool result = false;
3480 LyXParagraph * before =
3481 GetParFromID(undo->number_of_before_par);
3482 LyXParagraph * behind =
3483 GetParFromID(undo->number_of_behind_par);
3484 LyXParagraph * tmppar;
3485 LyXParagraph * tmppar2;
3486 LyXParagraph * endpar;
3487 LyXParagraph * tmppar5;
3489 // if there's no before take the beginning
3490 // of the document for redoing
3492 SetCursorIntern(bview, FirstParagraph(), 0);
3494 // replace the paragraphs with the undo informations
3496 LyXParagraph * tmppar3 = undo->par;
3497 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3498 LyXParagraph * tmppar4 = tmppar3;
3500 while (tmppar4->next)
3501 tmppar4 = tmppar4->next;
3502 } // get last undo par
3504 // now remove the old text if there is any
3505 if (before != behind || (!behind && !before)){
3507 tmppar5 = before->next;
3509 tmppar5 = OwnerParagraph();
3511 while (tmppar5 && tmppar5 != behind){
3513 tmppar5 = tmppar5->next;
3514 // a memory optimization for edit: Only layout information
3515 // is stored in the undo. So restore the text informations.
3516 if (undo->kind == Undo::EDIT) {
3517 tmppar2->setContentsFromPar(tmppar);
3518 tmppar->clearContents();
3519 tmppar2 = tmppar2->next;
3524 // put the new stuff in the list if there is one
3527 before->next = tmppar3;
3529 OwnerParagraph(tmppar3);
3530 tmppar3->previous = before;
3533 OwnerParagraph(behind);
3536 tmppar4->next = behind;
3538 behind->previous = tmppar4;
3542 // Set the cursor for redoing
3545 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3547 SetCursorIntern(bview, before, 0);
3550 // check wether before points to a closed float and open it if necessary
3551 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3552 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3554 while (tmppar4->previous &&
3555 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3556 tmppar4 = tmppar4->previous;
3557 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3558 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3559 tmppar4 = tmppar4->next;
3566 // open a cosed footnote at the end if necessary
3567 if (behind && behind->previous &&
3568 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3569 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3570 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3571 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3572 behind = behind->next;
3577 // calculate the endpar for redoing the paragraphs.
3580 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3581 endpar = behind->LastPhysicalPar()->Next();
3583 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3585 endpar = behind->Next();
3590 tmppar = GetParFromID(undo->number_of_cursor_par);
3591 RedoParagraphs(bview, cursor, endpar);
3593 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3594 UpdateCounters(bview, cursor.row());
3604 void LyXText::FinishUndo()
3608 // makes sure the next operation will be stored
3609 undo_finished = true;
3613 void LyXText::FreezeUndo()
3617 // this is dangerous and for internal use only
3622 void LyXText::UnFreezeUndo()
3626 // this is dangerous and for internal use only
3627 undo_frozen = false;
3631 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3632 LyXParagraph const * before,
3633 LyXParagraph const * behind) const
3638 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3639 buf->redostack.clear();
3643 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3644 LyXParagraph const * before, LyXParagraph const * behind)
3648 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3652 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3653 LyXParagraph const * before,
3654 LyXParagraph const * behind) const
3659 int before_number = -1;
3660 int behind_number = -1;
3662 before_number = before->id();
3664 behind_number = behind->id();
3665 // Undo::EDIT and Undo::FINISH are
3666 // always finished. (no overlapping there)
3667 // overlapping only with insert and delete inside one paragraph:
3668 // Nobody wants all removed character
3669 // appear one by one when undoing.
3670 // EDIT is special since only layout information, not the
3671 // contents of a paragaph are stored.
3672 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3673 // check wether storing is needed
3674 if (!buf->undostack.empty() &&
3675 buf->undostack.top()->kind == kind &&
3676 buf->undostack.top()->number_of_before_par == before_number &&
3677 buf->undostack.top()->number_of_behind_par == behind_number ){
3682 // create a new Undo
3683 LyXParagraph * undopar;
3684 LyXParagraph * tmppar;
3685 LyXParagraph * tmppar2;
3687 LyXParagraph * start = 0;
3688 LyXParagraph * end = 0;
3691 start = before->next;
3693 start = FirstParagraph();
3695 end = behind->previous;
3697 end = FirstParagraph();
3703 && start != end->next
3704 && (before != behind || (!before && !behind))) {
3706 tmppar2 = tmppar->Clone();
3707 tmppar2->id(tmppar->id());
3709 // a memory optimization: Just store the layout information
3711 if (kind == Undo::EDIT){
3712 //tmppar2->text.clear();
3713 tmppar2->clearContents();
3718 while (tmppar != end && tmppar->next) {
3719 tmppar = tmppar->next;
3720 tmppar2->next = tmppar->Clone();
3721 tmppar2->next->id(tmppar->id());
3722 // a memory optimization: Just store the layout
3723 // information when only edit
3724 if (kind == Undo::EDIT){
3725 //tmppar2->next->text.clear();
3726 tmppar2->clearContents();
3728 tmppar2->next->previous = tmppar2;
3729 tmppar2 = tmppar2->next;
3733 undopar = 0; // nothing to replace (undo of delete maybe)
3736 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3737 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3739 int cursor_par = cursor.par()->id();
3740 int cursor_pos = cursor.pos();
3743 Undo * undo = new Undo(kind,
3744 before_number, behind_number,
3745 cursor_par, cursor_pos,
3748 undo_finished = false;
3753 void LyXText::SetCursorParUndo(Buffer * buf)
3757 SetUndo(buf, Undo::FINISH,
3759 cursor.par()->ParFromPos(cursor.pos())->previous,
3760 cursor.par()->ParFromPos(cursor.pos())->next
3762 cursor.par()->previous,
3770 void LyXText::RemoveTableRow(LyXCursor & cur) const
3776 // move to the previous row
3777 int cell_act = NumberOfCell(cur.par(), cur.pos());
3780 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3781 cur.pos(cur.pos() - 1);
3783 !cur.par()->table->IsFirstCell(cell_act)) {
3784 cur.pos(cur.pos() - 1);
3785 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3786 cur.pos(cur.pos() - 1);
3790 // now we have to pay attention if the actual table is the
3791 // main row of TableContRows and if yes to delete all of them
3796 // delete up to the next row
3797 while (cur.pos() < cur.par()->Last() &&
3799 || !cur.par()->table->IsFirstCell(cell_act))) {
3800 while (cur.pos() < cur.par()->Last() &&
3801 !cur.par()->IsNewline(cur.pos()))
3802 cur.par()->Erase(cur.pos());
3805 if (cur.pos() < cur.par()->Last())
3806 cur.par()->Erase(cur.pos());
3808 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3809 cur.pos(cur.pos() - 1);
3810 cur.par()->Erase(cur.pos()); // no newline at very end!
3812 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3813 !cur.par()->table->IsContRow(cell_org) &&
3814 cur.par()->table->IsContRow(cell));
3815 cur.par()->table->DeleteRow(cell_org);
3822 bool LyXText::IsEmptyTableCell() const
3824 LyXParagraph::size_type pos = cursor.pos() - 1;
3825 while (pos >= 0 && pos < cursor.par()->Last()
3826 && !cursor.par()->IsNewline(pos))
3828 return cursor.par()->IsNewline(pos + 1);
3833 void LyXText::toggleAppendix(BufferView * bview)
3836 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3838 LyXParagraph * par = cursor.par();
3840 bool start = !par->start_of_appendix;
3842 // ensure that we have only one start_of_appendix in this document
3843 LyXParagraph * tmp = FirstParagraph();
3844 for (; tmp; tmp = tmp->next)
3845 tmp->start_of_appendix = 0;
3846 par->start_of_appendix = start;
3848 // we can set the refreshing parameters now
3849 status = LyXText::NEED_MORE_REFRESH;
3851 refresh_row = 0; // not needed for full update
3852 UpdateCounters(bview, 0);
3853 SetCursor(bview, cursor.par(), cursor.pos());
3857 LyXParagraph * LyXText::OwnerParagraph() const
3860 return inset_owner->par;
3862 return bv_owner->buffer()->paragraph;
3866 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3869 inset_owner->par = p;
3871 bv_owner->buffer()->paragraph = p;