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 const 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 LyXFont f = par->GetFontSettings(buf->params,
195 return f.realize(layout.reslabelfont);
197 LyXFont f = par->GetFontSettings(buf->params, pos);
198 return f.realize(layout.resfont);
203 // process layoutfont for pos == -1 and labelfont for pos < -1
205 return layout.resfont;
207 return layout.reslabelfont;
211 // The uncommon case need not be optimized as much
213 LyXFont layoutfont, tmpfont;
217 if (pos < BeginningOfMainBody(buf, par)) {
219 layoutfont = layout.labelfont;
222 layoutfont = layout.font;
224 tmpfont = par->GetFontSettings(buf->params, pos);
225 tmpfont.realize(layoutfont);
228 // process layoutfont for pos == -1 and labelfont for pos < -1
230 tmpfont = layout.font;
232 tmpfont = layout.labelfont;
235 // Resolve against environment font information
236 while (par && par_depth && !tmpfont.resolved()) {
237 par = par->DepthHook(par_depth - 1);
239 tmpfont.realize(textclasslist.
240 Style(buf->params.textclass,
241 par->GetLayout()).font);
242 par_depth = par->GetDepth();
246 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
249 // Cosmetic improvement: If this is an open footnote, make the font
251 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
252 && par->footnotekind == LyXParagraph::FOOTNOTE) {
260 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
261 LyXParagraph::size_type pos,
265 // Let the insets convert their font
266 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
267 if (par->GetInset(pos))
268 font = par->GetInset(pos)->ConvertFont(font);
271 LyXLayout const & layout =
272 textclasslist.Style(buf->params.textclass,
275 // Get concrete layout font to reduce against
278 if (pos < BeginningOfMainBody(buf, par))
279 layoutfont = layout.labelfont;
281 layoutfont = layout.font;
283 // Realize against environment font information
284 if (par->GetDepth()){
285 LyXParagraph * tp = par;
286 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
287 tp = tp->DepthHook(tp->GetDepth()-1);
289 layoutfont.realize(textclasslist.
290 Style(buf->params.textclass,
291 tp->GetLayout()).font);
295 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
298 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
299 && par->footnotekind == LyXParagraph::FOOTNOTE) {
300 layoutfont.decSize();
303 // Now, reduce font against full layout font
304 font.reduce(layoutfont);
306 par->SetFont(pos, font);
310 /* inserts a new row behind the specified row, increments
311 * the touched counters */
312 void LyXText::InsertRow(Row * row, LyXParagraph * par,
313 LyXParagraph::size_type pos) const
315 Row * tmprow = new Row;
318 tmprow->next(firstrow);
321 tmprow->previous(row);
322 tmprow->next(row->next());
327 tmprow->next()->previous(tmprow);
329 if (tmprow->previous())
330 tmprow->previous()->next(tmprow);
338 ++number_of_rows; // one more row
342 // removes the row and reset the touched counters
343 void LyXText::RemoveRow(Row * row) const
345 /* this must not happen before the currentrow for clear reasons.
346 so the trick is just to set the current row onto the previous
349 GetRow(row->par(), row->pos(), unused_y);
352 row->next()->previous(row->previous());
353 if (!row->previous()) {
354 firstrow = row->next();
356 row->previous()->next(row->next());
359 lastrow = row->previous();
361 height -= row->height(); // the text becomes smaller
364 --number_of_rows; // one row less
368 // remove all following rows of the paragraph of the specified row.
369 void LyXText::RemoveParagraph(Row * row) const
371 LyXParagraph * tmppar = row->par();
375 while (row && row->par() == tmppar) {
376 tmprow = row->next();
383 // insert the specified paragraph behind the specified row
384 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
387 InsertRow(row, par, 0); /* insert a new row, starting
390 SetCounter(bview->buffer(), par); // set the counters
392 // and now append the whole paragraph behind the new row
395 AppendParagraph(bview, firstrow);
397 row->next()->height(0);
398 AppendParagraph(bview, row->next());
404 void LyXText::ToggleFootnote(BufferView * bview)
406 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
408 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
410 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
412 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
413 CloseFootnote(bview);
420 void LyXText::OpenStuff(BufferView * bview)
422 if (cursor.pos() == 0 && cursor.par()->bibkey){
423 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
424 } else if (cursor.pos() < cursor.par()->Last()
425 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
426 && cursor.par()->GetInset(cursor.pos())->Editable()) {
427 bview->owner()->getMiniBuffer()
428 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
429 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
430 SetCursorParUndo(bview->buffer());
431 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
435 ToggleFootnote(bview);
443 void LyXText::CloseFootnote(BufferView * bview)
445 LyXParagraph * tmppar;
446 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
448 // if the cursor is not in an open footnote, or
449 // there is no open footnote in this paragraph, just return.
450 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
453 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
454 bview->owner()->getMiniBuffer()
455 ->Set(_("Nothing to do"));
459 // ok, move the cursor right before the footnote
460 // just a little faster than using CursorRight()
462 cursor.par()->ParFromPos(cursor.pos()) != par;) {
463 cursor.pos(cursor.pos() + 1);
466 // now the cursor is at the beginning of the physical par
467 SetCursor(bview, cursor.par(),
469 cursor.par()->ParFromPos(cursor.pos())->size());
471 /* we are in a footnote, so let us move at the beginning */
472 /* this is just faster than using just CursorLeft() */
474 tmppar = cursor.par();
475 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
476 // just a little bit faster than movin the cursor
477 tmppar = tmppar->Previous();
479 SetCursor(bview, tmppar, tmppar->Last());
482 // the cursor must be exactly before the footnote
483 par = cursor.par()->ParFromPos(cursor.pos());
485 status = LyXText::NEED_MORE_REFRESH;
486 refresh_row = cursor.row();
487 refresh_y = cursor.y() - cursor.row()->baseline();
489 tmppar = cursor.par();
490 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
491 Row * row = cursor.row();
493 tmppar->CloseFootnote(cursor.pos());
495 while (tmppar != endpar) {
496 RemoveRow(row->next());
498 tmppar = row->next()->par();
503 AppendParagraph(bview, cursor.row());
505 SetCursor(bview, cursor.par(), cursor.pos());
509 if (cursor.row()->next())
510 SetHeightOfRow(bview, cursor.row()->next());
515 /* used in setlayout */
516 // Asger is not sure we want to do this...
517 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
521 LyXLayout const & layout =
522 textclasslist.Style(buf->params.textclass, par->GetLayout());
524 LyXFont layoutfont, tmpfont;
525 for (LyXParagraph::size_type pos = 0;
526 pos < par->Last(); ++pos) {
527 if (pos < BeginningOfMainBody(buf, par))
528 layoutfont = layout.labelfont;
530 layoutfont = layout.font;
532 tmpfont = par->GetFontSettings(buf->params, pos);
533 tmpfont.reduce(layoutfont);
534 par->SetFont(pos, tmpfont);
539 LyXParagraph * LyXText::SetLayout(BufferView * bview,
540 LyXCursor & cur, LyXCursor & sstart_cur,
541 LyXCursor & send_cur,
542 LyXTextClass::size_type layout)
545 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
547 LyXParagraph * endpar = send_cur.par()->Next();
549 LyXParagraph * undoendpar = endpar;
551 if (endpar && endpar->GetDepth()) {
552 while (endpar && endpar->GetDepth()) {
554 endpar = endpar->LastPhysicalPar()->Next();
556 endpar = endpar->Next();
561 endpar = endpar->Next(); // because of parindents etc.
564 SetUndo(bview->buffer(), Undo::EDIT,
566 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
568 sstart_cur.par()->previous,
572 /* ok we have a selection. This is always between sstart_cur
573 * and sel_end cursor */
576 LyXLayout const & lyxlayout =
577 textclasslist.Style(bview->buffer()->params.textclass, layout);
579 while (cur.par() != send_cur.par()) {
581 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
583 cur.par()->SetLayout(bview->buffer()->params, layout);
584 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
586 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
588 LyXParagraph * fppar = cur.par();
590 fppar->added_space_top = lyxlayout.fill_top ?
591 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
592 fppar->added_space_bottom = lyxlayout.fill_bottom ?
593 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
594 if (lyxlayout.margintype == MARGIN_MANUAL)
595 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
596 if (lyxlayout.labeltype != LABEL_BIBLIO
598 delete fppar->bibkey;
604 cur.par(cur.par()->Next());
607 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
609 cur.par()->SetLayout(bview->buffer()->params, layout);
610 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
612 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
614 LyXParagraph * fppar = cur.par();
616 fppar->added_space_top = lyxlayout.fill_top ?
617 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
618 fppar->added_space_bottom = lyxlayout.fill_bottom ?
619 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
620 if (lyxlayout.margintype == MARGIN_MANUAL)
621 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
622 if (lyxlayout.labeltype != LABEL_BIBLIO
624 delete fppar->bibkey;
633 // set layout over selection and make a total rebreak of those paragraphs
634 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
636 LyXCursor tmpcursor = cursor; /* store the current cursor */
638 // if there is no selection just set the layout
639 // of the current paragraph */
641 sel_start_cursor = cursor; // dummy selection
642 sel_end_cursor = cursor;
645 endpar = SetLayout(bview, cursor, sel_start_cursor,
646 sel_end_cursor, layout);
647 RedoParagraphs(bview, sel_start_cursor, endpar);
649 // we have to reset the selection, because the
650 // geometry could have changed
651 SetCursor(bview, sel_start_cursor.par(),
652 sel_start_cursor.pos(), false);
654 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
656 UpdateCounters(bview, cursor.row());
659 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
663 // increment depth over selection and
664 // make a total rebreak of those paragraphs
665 void LyXText::IncDepth(BufferView * bview)
667 // If there is no selection, just use the current paragraph
669 sel_start_cursor = cursor; // dummy selection
670 sel_end_cursor = cursor;
673 // We end at the next paragraph with depth 0
674 LyXParagraph * endpar =
676 sel_end_cursor.par()->LastPhysicalPar()->Next();
678 sel_end_cursor.par()->Next();
680 LyXParagraph * undoendpar = endpar;
682 if (endpar && endpar->GetDepth()) {
683 while (endpar && endpar->GetDepth()) {
685 endpar = endpar->LastPhysicalPar()->Next();
687 endpar = endpar->Next();
693 endpar = endpar->Next(); // because of parindents etc.
696 SetUndo(bview->buffer(), Undo::EDIT,
699 .par()->ParFromPos(sel_start_cursor.pos())->previous,
701 sel_start_cursor.par()->previous,
705 LyXCursor tmpcursor = cursor; // store the current cursor
707 // ok we have a selection. This is always between sel_start_cursor
708 // and sel_end cursor
709 cursor = sel_start_cursor;
711 bool anything_changed = false;
714 // NOTE: you can't change the depth of a bibliography entry
717 cursor.par()->footnoteflag ==
718 sel_start_cursor.par()->footnoteflag &&
720 textclasslist.Style(bview->buffer()->params.textclass,
721 cursor.par()->GetLayout()
722 ).labeltype != LABEL_BIBLIO) {
723 LyXParagraph * prev =
725 cursor.par()->FirstPhysicalPar()->Previous();
727 cursor.par()->Previous();
730 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
731 || (prev->GetDepth() == cursor.par()->GetDepth()
732 && textclasslist.Style(bview->buffer()->params.textclass,
733 prev->GetLayout()).isEnvironment()))) {
735 cursor.par()->FirstPhysicalPar()->depth++;
737 cursor.par()->depth++;
739 anything_changed = true;
742 if (cursor.par() == sel_end_cursor.par())
744 cursor.par(cursor.par()->Next());
747 // if nothing changed set all depth to 0
748 if (!anything_changed) {
749 cursor = sel_start_cursor;
750 while (cursor.par() != sel_end_cursor.par()) {
752 cursor.par()->FirstPhysicalPar()->depth = 0;
754 cursor.par()->depth = 0;
756 cursor.par(cursor.par()->Next());
759 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
760 cursor.par()->FirstPhysicalPar()->depth = 0;
762 cursor.par()->depth = 0;
766 RedoParagraphs(bview, sel_start_cursor, endpar);
768 // we have to reset the selection, because the
769 // geometry could have changed
770 SetCursor(bview, sel_start_cursor.par(),
771 sel_start_cursor.pos());
773 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
774 UpdateCounters(bview, cursor.row());
777 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
781 // decrement depth over selection and
782 // make a total rebreak of those paragraphs
783 void LyXText::DecDepth(BufferView * bview)
785 // if there is no selection just set the layout
786 // of the current paragraph
788 sel_start_cursor = cursor; // dummy selection
789 sel_end_cursor = cursor;
792 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
794 LyXParagraph * endpar = sel_end_cursor.par()->Next();
796 LyXParagraph * undoendpar = endpar;
798 if (endpar && endpar->GetDepth()) {
799 while (endpar && endpar->GetDepth()) {
801 endpar = endpar->LastPhysicalPar()->Next();
803 endpar = endpar->Next();
809 endpar = endpar->Next(); // because of parindents etc.
812 SetUndo(bview->buffer(), Undo::EDIT,
815 .par()->ParFromPos(sel_start_cursor.pos())->previous,
817 sel_start_cursor.par()->previous,
821 LyXCursor tmpcursor = cursor; // store the current cursor
823 // ok we have a selection. This is always between sel_start_cursor
824 // and sel_end cursor
825 cursor = sel_start_cursor;
829 if (cursor.par()->footnoteflag ==
830 sel_start_cursor.par()->footnoteflag) {
831 if (cursor.par()->FirstPhysicalPar()->depth)
832 cursor.par()->FirstPhysicalPar()->depth--;
835 if (cursor.par()->depth)
836 cursor.par()->depth--;
838 if (cursor.par() == sel_end_cursor.par())
840 cursor.par(cursor.par()->Next());
843 RedoParagraphs(bview, sel_start_cursor, endpar);
845 // we have to reset the selection, because the
846 // geometry could have changed
847 SetCursor(bview, sel_start_cursor.par(),
848 sel_start_cursor.pos());
850 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
851 UpdateCounters(bview, cursor.row());
854 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
858 // set font over selection and make a total rebreak of those paragraphs
859 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
861 // if there is no selection just set the current_font
863 // Determine basis font
865 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
867 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
869 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
870 // Update current font
871 real_current_font.update(font,
872 bview->buffer()->params.language_info,
875 // Reduce to implicit settings
876 current_font = real_current_font;
877 current_font.reduce(layoutfont);
878 // And resolve it completely
879 real_current_font.realize(layoutfont);
883 LyXCursor tmpcursor = cursor; // store the current cursor
885 // ok we have a selection. This is always between sel_start_cursor
886 // and sel_end cursor
888 SetUndo(bview->buffer(), Undo::EDIT,
890 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
891 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
893 sel_start_cursor.par()->previous,
894 sel_end_cursor.par()->next
897 cursor = sel_start_cursor;
898 while (cursor.par() != sel_end_cursor.par() ||
901 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
903 cursor.pos() < sel_end_cursor.pos()))
905 if (cursor.pos() < cursor.par()->Last()
907 && cursor.par()->footnoteflag
908 == sel_start_cursor.par()->footnoteflag
911 // an open footnote should behave
913 LyXFont newfont = GetFont(bview->buffer(),
914 cursor.par(), cursor.pos());
916 bview->buffer()->params.language_info,
918 SetCharFont(bview->buffer(),
919 cursor.par(), cursor.pos(), newfont);
920 cursor.pos(cursor.pos() + 1);
923 cursor.par(cursor.par()->Next());
927 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
929 // we have to reset the selection, because the
930 // geometry could have changed
931 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
933 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
936 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
937 tmpcursor.boundary());
941 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
943 Row * tmprow = cur.row();
944 long y = cur.y() - tmprow->baseline();
946 SetHeightOfRow(bview, tmprow);
948 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
950 LyXParagraph * first_phys_par = tmprow->par();
952 // find the first row of the paragraph
953 if (first_phys_par != tmprow->par())
954 while (tmprow->previous()
955 && tmprow->previous()->par() != first_phys_par) {
956 tmprow = tmprow->previous();
957 y -= tmprow->height();
958 SetHeightOfRow(bview, tmprow);
960 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
961 tmprow = tmprow->previous();
962 y -= tmprow->height();
963 SetHeightOfRow(bview, tmprow);
966 // we can set the refreshing parameters now
967 status = LyXText::NEED_MORE_REFRESH;
969 refresh_row = tmprow;
970 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
974 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
976 Row * tmprow = cur.row();
978 long y = cur.y() - tmprow->baseline();
979 SetHeightOfRow(bview, tmprow);
981 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
983 LyXParagraph * first_phys_par = tmprow->par();
985 // find the first row of the paragraph
986 if (first_phys_par != tmprow->par())
987 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
988 tmprow = tmprow->previous();
989 y -= tmprow->height();
991 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
992 tmprow = tmprow->previous();
993 y -= tmprow->height();
996 // we can set the refreshing parameters now
997 if (status == LyXText::UNCHANGED || y < refresh_y) {
999 refresh_row = tmprow;
1001 status = LyXText::NEED_MORE_REFRESH;
1002 SetCursor(bview, cur.par(), cur.pos());
1006 /* deletes and inserts again all paragaphs between the cursor
1007 * and the specified par
1008 * This function is needed after SetLayout and SetFont etc. */
1009 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1010 LyXParagraph const * endpar) const
1013 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1015 Row * tmprow = cur.row();
1017 long y = cur.y() - tmprow->baseline();
1019 if (!tmprow->previous()){
1020 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1023 first_phys_par = tmprow->par()->FirstPhysicalPar();
1025 first_phys_par = tmprow->par();
1027 // find the first row of the paragraph
1028 if (first_phys_par != tmprow->par())
1029 while (tmprow->previous() &&
1030 (tmprow->previous()->par() != first_phys_par)) {
1031 tmprow = tmprow->previous();
1032 y -= tmprow->height();
1034 while (tmprow->previous()
1035 && tmprow->previous()->par() == first_phys_par) {
1036 tmprow = tmprow->previous();
1037 y -= tmprow->height();
1041 // we can set the refreshing parameters now
1042 status = LyXText::NEED_MORE_REFRESH;
1044 refresh_row = tmprow->previous(); /* the real refresh row will
1045 be deleted, so I store
1046 the previous here */
1049 tmppar = tmprow->next()->par();
1052 while (tmppar != endpar) {
1053 RemoveRow(tmprow->next());
1055 tmppar = tmprow->next()->par();
1060 // remove the first one
1061 tmprow2 = tmprow; /* this is because tmprow->previous()
1063 tmprow = tmprow->previous();
1066 tmppar = first_phys_par;
1070 InsertParagraph(bview, tmppar, tmprow);
1073 while (tmprow->next() && tmprow->next()->par() == tmppar)
1074 tmprow = tmprow->next();
1075 tmppar = tmppar->Next();
1077 } while (tmppar != endpar);
1079 // this is because of layout changes
1081 refresh_y -= refresh_row->height();
1082 SetHeightOfRow(bview, refresh_row);
1084 refresh_row = firstrow;
1086 SetHeightOfRow(bview, refresh_row);
1089 if (tmprow && tmprow->next())
1090 SetHeightOfRow(bview, tmprow->next());
1094 bool LyXText::FullRebreak(BufferView * bview)
1100 if (need_break_row) {
1101 BreakAgain(bview, need_break_row);
1109 /* important for the screen */
1112 /* the cursor set functions have a special mechanism. When they
1113 * realize, that you left an empty paragraph, they will delete it.
1114 * They also delete the corresponding row */
1116 // need the selection cursor:
1117 void LyXText::SetSelection()
1120 last_sel_cursor = sel_cursor;
1121 sel_start_cursor = sel_cursor;
1122 sel_end_cursor = sel_cursor;
1127 // first the toggling area
1128 if (cursor.y() < last_sel_cursor.y()
1129 || (cursor.y() == last_sel_cursor.y()
1130 && cursor.x() < last_sel_cursor.x())) {
1131 toggle_end_cursor = last_sel_cursor;
1132 toggle_cursor = cursor;
1134 toggle_end_cursor = cursor;
1135 toggle_cursor = last_sel_cursor;
1138 last_sel_cursor = cursor;
1140 // and now the whole selection
1142 if (sel_cursor.par() == cursor.par())
1143 if (sel_cursor.pos() < cursor.pos()) {
1144 sel_end_cursor = cursor;
1145 sel_start_cursor = sel_cursor;
1147 sel_end_cursor = sel_cursor;
1148 sel_start_cursor = cursor;
1150 else if (sel_cursor.y() < cursor.y() ||
1151 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1152 sel_end_cursor = cursor;
1153 sel_start_cursor = sel_cursor;
1156 sel_end_cursor = sel_cursor;
1157 sel_start_cursor = cursor;
1160 // a selection with no contents is not a selection
1161 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1162 sel_start_cursor.pos() == sel_end_cursor.pos())
1167 string const LyXText::selectionAsString(Buffer const * buffer) const
1169 if (!selection) return string();
1172 // Special handling if the whole selection is within one paragraph
1173 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1174 result += sel_start_cursor.par()->String(buffer,
1175 sel_start_cursor.pos(),
1176 sel_end_cursor.pos());
1180 // The selection spans more than one paragraph
1182 // First paragraph in selection
1183 result += sel_start_cursor.par()->String(buffer,
1184 sel_start_cursor.pos(),
1185 sel_start_cursor.par()->Last())
1188 // The paragraphs in between (if any)
1189 LyXCursor tmpcur(sel_start_cursor);
1190 tmpcur.par(tmpcur.par()->Next());
1191 while (tmpcur.par() != sel_end_cursor.par()) {
1192 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1193 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1196 // Last paragraph in selection
1197 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1203 void LyXText::ClearSelection() const
1210 void LyXText::CursorHome(BufferView * bview) const
1212 SetCursor(bview, cursor.par(), cursor.row()->pos());
1216 void LyXText::CursorEnd(BufferView * bview) const
1218 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1219 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1221 if (cursor.par()->Last() &&
1222 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1223 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1224 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1226 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1229 if (cursor.par()->table) {
1230 int cell = NumberOfCell(cursor.par(), cursor.pos());
1231 if (cursor.par()->table->RowHasContRow(cell) &&
1232 cursor.par()->table->CellHasContRow(cell)<0) {
1233 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1234 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1236 if (cursor.par()->Last() &&
1237 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1238 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1239 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1241 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1249 void LyXText::CursorTop(BufferView * bview) const
1251 while (cursor.par()->Previous())
1252 cursor.par(cursor.par()->Previous());
1253 SetCursor(bview, cursor.par(), 0);
1257 void LyXText::CursorBottom(BufferView * bview) const
1259 while (cursor.par()->Next())
1260 cursor.par(cursor.par()->Next());
1261 SetCursor(bview, cursor.par(), cursor.par()->Last());
1265 /* returns a pointer to the row near the specified y-coordinate
1266 * (relative to the whole text). y is set to the real beginning
1268 Row * LyXText::GetRowNearY(long & y) const
1270 Row * tmprow = firstrow;
1273 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1274 tmpy += tmprow->height();
1275 tmprow = tmprow->next();
1278 y = tmpy; // return the real y
1283 void LyXText::ToggleFree(BufferView * bview,
1284 LyXFont const & font, bool toggleall)
1286 // If the mask is completely neutral, tell user
1287 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1288 // Could only happen with user style
1289 bview->owner()->getMiniBuffer()
1290 ->Set(_("No font change defined. Use Character under"
1291 " the Layout menu to define font change."));
1295 // Try implicit word selection
1296 // If there is a change in the language the implicit word selection
1298 LyXCursor resetCursor = cursor;
1299 bool implicitSelection = (font.language() == ignore_language)
1300 ? SelectWordWhenUnderCursor(bview) : false;
1303 SetFont(bview, font, toggleall);
1305 /* Implicit selections are cleared afterwards and cursor is set to the
1306 original position. */
1307 if (implicitSelection) {
1309 cursor = resetCursor;
1310 SetCursor(bview, cursor.par(), cursor.pos());
1311 sel_cursor = cursor;
1316 LyXParagraph::size_type
1317 LyXText::BeginningOfMainBody(Buffer const * buf,
1318 LyXParagraph const * par) const
1320 if (textclasslist.Style(buf->params.textclass,
1321 par->GetLayout()).labeltype != LABEL_MANUAL)
1324 return par->BeginningOfMainBody();
1329 /* if there is a selection, reset every environment you can find
1330 * in the selection, otherwise just the environment you are in */
1331 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1333 LyXParagraph * tmppar, * firsttmppar;
1337 /* is is only allowed, if the cursor is IN an open footnote.
1338 * Otherwise it is too dangerous */
1339 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1342 SetUndo(bview->buffer(), Undo::FINISH,
1343 cursor.par()->PreviousBeforeFootnote()->previous,
1344 cursor.par()->NextAfterFootnote()->next);
1346 /* ok, move to the beginning of the footnote. */
1347 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1348 cursor.par(cursor.par()->Previous());
1350 SetCursor(bview, cursor.par(), cursor.par()->Last());
1351 /* this is just faster than using CursorLeft(); */
1353 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1354 tmppar = firsttmppar;
1355 /* tmppar is now the paragraph right before the footnote */
1357 bool first_footnote_par_is_not_empty = tmppar->next->size();
1360 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1361 tmppar = tmppar->next; /* I use next instead of Next(),
1362 * because there cannot be any
1363 * footnotes in a footnote
1365 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1367 /* remember the captions and empty paragraphs */
1368 if ((textclasslist.Style(bview->buffer()->params.textclass,
1369 tmppar->GetLayout())
1370 .labeltype == LABEL_SENSITIVE)
1372 tmppar->SetLayout(bview->buffer()->params, 0);
1375 // now we will paste the ex-footnote, if the layouts allow it
1376 // first restore the layout of the paragraph right behind
1379 tmppar->next->MakeSameLayout(cursor.par());
1382 if ((!tmppar->GetLayout()
1388 && (!tmppar->Next()->Last()
1389 || tmppar->Next()->HasSameLayout(tmppar)))) {
1390 if (tmppar->Next()->Last()
1391 && tmppar->Next()->IsLineSeparator(0))
1392 tmppar->Next()->Erase(0);
1393 tmppar->PasteParagraph(bview->buffer()->params);
1396 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1397 * by the pasting of the beginning */
1399 /* then the beginning */
1400 /* if there is no space between the text and the footnote, so we insert
1402 * (only if the previous par and the footnotepar are not empty!) */
1403 if ((!firsttmppar->next->GetLayout()
1405 && !firsttmppar->next->table
1408 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1409 if (firsttmppar->size()
1410 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1411 && first_footnote_par_is_not_empty) {
1412 firsttmppar->next->InsertChar(0, ' ');
1414 firsttmppar->PasteParagraph(bview->buffer()->params);
1417 /* now redo the paragaphs */
1418 RedoParagraphs(bview, cursor, tmppar);
1420 SetCursor(bview, cursor.par(), cursor.pos());
1422 /* sometimes it can happen, that there is a counter change */
1423 Row * row = cursor.row();
1424 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1426 UpdateCounters(bview, row);
1434 /* the DTP switches for paragraphs. LyX will store them in the
1435 * first physicla paragraph. When a paragraph is broken, the top settings
1436 * rest, the bottom settings are given to the new one. So I can make shure,
1437 * they do not duplicate themself and you cannnot make dirty things with
1440 void LyXText::SetParagraph(BufferView * bview,
1441 bool line_top, bool line_bottom,
1442 bool pagebreak_top, bool pagebreak_bottom,
1443 VSpace const & space_top,
1444 VSpace const & space_bottom,
1446 string labelwidthstring,
1449 LyXCursor tmpcursor = cursor;
1451 sel_start_cursor = cursor;
1452 sel_end_cursor = cursor;
1455 // make sure that the depth behind the selection are restored, too
1457 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1459 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1461 LyXParagraph * undoendpar = endpar;
1463 if (endpar && endpar->GetDepth()) {
1464 while (endpar && endpar->GetDepth()) {
1466 endpar = endpar->LastPhysicalPar()->Next();
1468 endpar = endpar->Next();
1470 undoendpar = endpar;
1474 endpar = endpar->Next(); // because of parindents etc.
1477 SetUndo(bview->buffer(), Undo::EDIT,
1480 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1482 sel_start_cursor.par()->previous,
1487 LyXParagraph * tmppar = sel_end_cursor.par();
1489 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1490 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1492 while (tmppar != sel_start_cursor.par()->Previous()) {
1493 SetCursor(bview, tmppar, 0);
1495 status = LyXText::NEED_MORE_REFRESH;
1496 refresh_row = cursor.row();
1497 refresh_y = cursor.y() - cursor.row()->baseline();
1499 if (cursor.par()->footnoteflag ==
1500 sel_start_cursor.par()->footnoteflag) {
1502 cursor.par()->line_top = line_top;
1503 cursor.par()->line_bottom = line_bottom;
1504 cursor.par()->pagebreak_top = pagebreak_top;
1505 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1506 cursor.par()->added_space_top = space_top;
1507 cursor.par()->added_space_bottom = space_bottom;
1508 // does the layout allow the new alignment?
1509 if (align == LYX_ALIGN_LAYOUT)
1510 align = textclasslist
1511 .Style(bview->buffer()->params.textclass,
1512 cursor.par()->GetLayout()).align;
1513 if (align & textclasslist
1514 .Style(bview->buffer()->params.textclass,
1515 cursor.par()->GetLayout()).alignpossible) {
1516 if (align == textclasslist
1517 .Style(bview->buffer()->params.textclass,
1518 cursor.par()->GetLayout()).align)
1519 cursor.par()->align = LYX_ALIGN_LAYOUT;
1521 cursor.par()->align = align;
1523 cursor.par()->SetLabelWidthString(labelwidthstring);
1524 cursor.par()->noindent = noindent;
1528 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1530 tmppar = cursor.par()->Previous();
1534 RedoParagraphs(bview, sel_start_cursor, endpar);
1537 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1538 sel_cursor = cursor;
1539 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1541 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1543 bview->updateInset(inset_owner, true);
1547 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1548 string const & width,
1549 string const & widthp,
1550 int alignment, bool hfill,
1551 bool start_minipage)
1553 LyXCursor tmpcursor = cursor;
1554 LyXParagraph * tmppar;
1556 sel_start_cursor = cursor;
1557 sel_end_cursor = cursor;
1560 // make sure that the depth behind the selection are restored, too
1562 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1564 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1566 LyXParagraph * undoendpar = endpar;
1568 if (endpar && endpar->GetDepth()) {
1569 while (endpar && endpar->GetDepth()) {
1571 endpar = endpar->LastPhysicalPar()->Next();
1573 endpar = endpar->Next();
1575 undoendpar = endpar;
1579 endpar = endpar->Next(); // because of parindents etc.
1582 SetUndo(bview->buffer(), Undo::EDIT,
1585 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1587 sel_start_cursor.par()->previous,
1591 tmppar = sel_end_cursor.par();
1593 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1594 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1596 while(tmppar != sel_start_cursor.par()->Previous()) {
1597 SetCursor(bview, tmppar, 0);
1599 status = LyXText::NEED_MORE_REFRESH;
1600 refresh_row = cursor.row();
1601 refresh_y = cursor.y() - cursor.row()->baseline();
1603 if (cursor.par()->footnoteflag ==
1604 sel_start_cursor.par()->footnoteflag) {
1606 if (type == LyXParagraph::PEXTRA_NONE) {
1607 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1608 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1609 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1612 cursor.par()->SetPExtraType(bview->buffer()->params,
1613 type, width, widthp);
1614 cursor.par()->pextra_hfill = hfill;
1615 cursor.par()->pextra_start_minipage = start_minipage;
1616 cursor.par()->pextra_alignment = alignment;
1620 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1622 tmppar = cursor.par()->Previous();
1625 RedoParagraphs(bview, sel_start_cursor, endpar);
1627 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1628 sel_cursor = cursor;
1629 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1631 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1635 char loweralphaCounter(int n)
1637 if (n < 1 || n > 26)
1644 char alphaCounter(int n)
1646 if (n < 1 || n > 26)
1653 char hebrewCounter(int n)
1655 static const char hebrew[22] = {
1656 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1657 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1658 '÷', 'ø', 'ù', 'ú'
1660 if (n < 1 || n > 22)
1668 string const romanCounter(int n)
1670 static char const * roman[20] = {
1671 "i", "ii", "iii", "iv", "v",
1672 "vi", "vii", "viii", "ix", "x",
1673 "xi", "xii", "xiii", "xiv", "xv",
1674 "xvi", "xvii", "xviii", "xix", "xx"
1676 if (n < 1 || n > 20)
1683 // set the counter of a paragraph. This includes the labels
1684 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1687 // this is only relevant for the beginning of paragraph
1688 par = par->FirstPhysicalPar();
1690 LyXLayout const & layout =
1691 textclasslist.Style(buf->params.textclass,
1694 LyXTextClass const & textclass =
1695 textclasslist.TextClass(buf->params.textclass);
1697 /* copy the prev-counters to this one, unless this is the start of a
1698 footnote or of a bibliography or the very first paragraph */
1701 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1702 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1703 && par->footnotekind == LyXParagraph::FOOTNOTE)
1705 && !(textclasslist.Style(buf->params.textclass,
1706 par->Previous()->GetLayout()
1707 ).labeltype != LABEL_BIBLIO
1708 && layout.labeltype == LABEL_BIBLIO)) {
1709 for (int i = 0; i < 10; ++i) {
1710 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1713 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1715 par->appendix = par->Previous()->appendix;
1717 if (!par->appendix && par->start_of_appendix){
1718 par->appendix = true;
1719 for (int i = 0; i < 10; ++i) {
1720 par->setCounter(i, 0);
1724 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1725 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1727 par->enumdepth = par->Previous()->enumdepth;
1728 par->itemdepth = par->Previous()->itemdepth;
1731 for (int i = 0; i < 10; ++i) {
1732 par->setCounter(i, 0);
1734 par->appendix = par->start_of_appendix;
1740 // if this is an open marginnote and this is the first
1741 // entry in the marginnote and the enclosing
1742 // environment is an enum/item then correct for the
1743 // LaTeX behaviour (ARRae)
1744 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1745 && par->footnotekind == LyXParagraph::MARGIN
1747 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1748 && (par->PreviousBeforeFootnote()
1749 && textclasslist.Style(buf->params.textclass,
1750 par->PreviousBeforeFootnote()->GetLayout()
1751 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1752 // Any itemize or enumerate environment in a marginnote
1753 // that is embedded in an itemize or enumerate
1754 // paragraph is seen by LaTeX as being at a deeper
1755 // level within that enclosing itemization/enumeration
1756 // even if there is a "standard" layout at the start of
1762 /* Maybe we have to increment the enumeration depth.
1763 * BUT, enumeration in a footnote is considered in isolation from its
1764 * surrounding paragraph so don't increment if this is the
1765 * first line of the footnote
1766 * AND, bibliographies can't have their depth changed ie. they
1767 * are always of depth 0
1770 && par->Previous()->GetDepth() < par->GetDepth()
1771 && textclasslist.Style(buf->params.textclass,
1772 par->Previous()->GetLayout()
1773 ).labeltype == LABEL_COUNTER_ENUMI
1774 && par->enumdepth < 3
1776 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1777 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1778 && par->footnotekind == LyXParagraph::FOOTNOTE)
1780 && layout.labeltype != LABEL_BIBLIO) {
1784 /* Maybe we have to decrement the enumeration depth, see note above */
1786 && par->Previous()->GetDepth() > par->GetDepth()
1788 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1789 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1790 && par->footnotekind == LyXParagraph::FOOTNOTE)
1792 && layout.labeltype != LABEL_BIBLIO) {
1793 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1794 par->setCounter(6 + par->enumdepth,
1795 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1796 /* reset the counters.
1797 * A depth change is like a breaking layout
1799 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1800 par->setCounter(i, 0);
1803 if (!par->labelstring.empty()) {
1804 par->labelstring.erase();
1807 if (layout.margintype == MARGIN_MANUAL) {
1808 if (par->labelwidthstring.empty()) {
1809 par->SetLabelWidthString(layout.labelstring());
1812 par->SetLabelWidthString(string());
1815 /* is it a layout that has an automatic label ? */
1816 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1818 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1819 if (i >= 0 && i<= buf->params.secnumdepth) {
1820 par->incCounter(i); // increment the counter
1822 // Is there a label? Useful for Chapter layout
1823 if (!par->appendix){
1824 if (!layout.labelstring().empty())
1825 par->labelstring = layout.labelstring();
1827 par->labelstring.erase();
1829 if (!layout.labelstring_appendix().empty())
1830 par->labelstring = layout.labelstring_appendix();
1832 par->labelstring.erase();
1835 //#ifdef HAVE_SSTREAM
1836 std::ostringstream s;
1840 if (!par->appendix) {
1841 switch (2 * LABEL_COUNTER_CHAPTER -
1842 textclass.maxcounter() + i) {
1843 case LABEL_COUNTER_CHAPTER:
1844 s << par->getCounter(i);
1846 case LABEL_COUNTER_SECTION:
1847 s << par->getCounter(i - 1) << '.'
1848 << par->getCounter(i);
1850 case LABEL_COUNTER_SUBSECTION:
1851 s << par->getCounter(i - 2) << '.'
1852 << par->getCounter(i - 1) << '.'
1853 << par->getCounter(i);
1855 case LABEL_COUNTER_SUBSUBSECTION:
1856 s << par->getCounter(i - 3) << '.'
1857 << par->getCounter(i - 2) << '.'
1858 << par->getCounter(i - 1) << '.'
1859 << par->getCounter(i);
1862 case LABEL_COUNTER_PARAGRAPH:
1863 s << par->getCounter(i - 4) << '.'
1864 << par->getCounter(i - 3) << '.'
1865 << par->getCounter(i - 2) << '.'
1866 << par->getCounter(i - 1) << '.'
1867 << par->getCounter(i);
1869 case LABEL_COUNTER_SUBPARAGRAPH:
1870 s << par->getCounter(i - 5) << '.'
1871 << par->getCounter(i - 4) << '.'
1872 << par->getCounter(i - 3) << '.'
1873 << par->getCounter(i - 2) << '.'
1874 << par->getCounter(i - 1) << '.'
1875 << par->getCounter(i);
1879 // Can this ever be reached? And in the
1880 // case it is, how can this be correct?
1882 s << par->getCounter(i) << '.';
1885 } else { // appendix
1886 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1887 case LABEL_COUNTER_CHAPTER:
1888 if (par->isRightToLeftPar(buf->params))
1889 s << hebrewCounter(par->getCounter(i));
1891 s << alphaCounter(par->getCounter(i));
1893 case LABEL_COUNTER_SECTION:
1894 if (par->isRightToLeftPar(buf->params))
1895 s << hebrewCounter(par->getCounter(i - 1));
1897 s << alphaCounter(par->getCounter(i - 1));
1900 << par->getCounter(i);
1903 case LABEL_COUNTER_SUBSECTION:
1904 if (par->isRightToLeftPar(buf->params))
1905 s << hebrewCounter(par->getCounter(i - 2));
1907 s << alphaCounter(par->getCounter(i - 2));
1910 << par->getCounter(i-1) << '.'
1911 << par->getCounter(i);
1914 case LABEL_COUNTER_SUBSUBSECTION:
1915 if (par->isRightToLeftPar(buf->params))
1916 s << hebrewCounter(par->getCounter(i-3));
1918 s << alphaCounter(par->getCounter(i-3));
1921 << par->getCounter(i-2) << '.'
1922 << par->getCounter(i-1) << '.'
1923 << par->getCounter(i);
1926 case LABEL_COUNTER_PARAGRAPH:
1927 if (par->isRightToLeftPar(buf->params))
1928 s << hebrewCounter(par->getCounter(i-4));
1930 s << alphaCounter(par->getCounter(i-4));
1933 << par->getCounter(i-3) << '.'
1934 << par->getCounter(i-2) << '.'
1935 << par->getCounter(i-1) << '.'
1936 << par->getCounter(i);
1939 case LABEL_COUNTER_SUBPARAGRAPH:
1940 if (par->isRightToLeftPar(buf->params))
1941 s << hebrewCounter(par->getCounter(i-5));
1943 s << alphaCounter(par->getCounter(i-5));
1946 << par->getCounter(i-4) << '.'
1947 << par->getCounter(i-3) << '.'
1948 << par->getCounter(i-2) << '.'
1949 << par->getCounter(i-1) << '.'
1950 << par->getCounter(i);
1954 // Can this ever be reached? And in the
1955 // case it is, how can this be correct?
1957 s << par->getCounter(i) << '.';
1962 //#ifdef HAVE_SSTREAM
1963 par->labelstring += s.str().c_str();
1964 // We really want to remove the c_str as soon as
1968 // char * tmps = s.str();
1969 // par->labelstring += tmps;
1973 for (i++; i < 10; ++i) {
1974 // reset the following counters
1975 par->setCounter(i, 0);
1977 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1978 for (i++; i < 10; ++i) {
1979 // reset the following counters
1980 par->setCounter(i, 0);
1982 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1983 par->incCounter(i + par->enumdepth);
1984 int number = par->getCounter(i + par->enumdepth);
1986 //#ifdef HAVE_SSTREAM
1987 std::ostringstream s;
1991 switch (par->enumdepth) {
1993 if (par->isRightToLeftPar(buf->params))
1995 << hebrewCounter(number)
1999 << loweralphaCounter(number)
2003 if (par->isRightToLeftPar(buf->params))
2004 s << '.' << romanCounter(number);
2006 s << romanCounter(number) << '.';
2009 if (par->isRightToLeftPar(buf->params))
2011 << alphaCounter(number);
2013 s << alphaCounter(number)
2017 if (par->isRightToLeftPar(buf->params))
2023 //#ifdef HAVE_SSTREAM
2024 par->labelstring = s.str().c_str();
2025 // we really want to get rid of that c_str()
2028 // char * tmps = s.str();
2029 // par->labelstring = tmps;
2033 for (i += par->enumdepth + 1; i < 10; ++i)
2034 par->setCounter(i, 0); /* reset the following counters */
2037 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2038 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2040 int number = par->getCounter(i);
2042 InsetCommandParams p( "bibitem" );
2043 par->bibkey = new InsetBibKey(p);
2045 par->bibkey->setCounter(number);
2046 par->labelstring = layout.labelstring();
2048 // In biblio should't be following counters but...
2050 string s = layout.labelstring();
2052 // the caption hack:
2053 if (layout.labeltype == LABEL_SENSITIVE) {
2054 bool isOK (par->InInset() && par->InInset()->owner() &&
2055 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2057 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2058 && (par->footnotekind == LyXParagraph::FIG
2059 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2060 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2061 ? ":øåéà " : "Figure:";
2062 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2063 && (par->footnotekind == LyXParagraph::TAB
2064 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2065 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2066 ? ":äìáè" : "Table:";
2067 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2068 && par->footnotekind == LyXParagraph::ALGORITHM) {
2069 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2070 ? ":Ãúéøåâìà " : "Algorithm:";
2074 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2076 = floatList.getType(tmp->type());
2077 // We should get the correct number here too.
2078 s = fl.name + " #:";
2080 /* par->SetLayout(0);
2081 s = layout->labelstring; */
2082 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2083 ? " :úåòîùî øñç" : "Senseless: ";
2086 par->labelstring = s;
2088 /* reset the enumeration counter. They are always resetted
2089 * when there is any other layout between */
2090 for (int i = 6 + par->enumdepth; i < 10; ++i)
2091 par->setCounter(i, 0);
2096 /* Updates all counters BEHIND the row. Changed paragraphs
2097 * with a dynamic left margin will be rebroken. */
2098 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2105 if (row->par()->next
2107 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2111 par = row->par()->LastPhysicalPar()->Next();
2113 par = row->par()->Next();
2116 par = row->par()->next;
2121 while (row->par() != par)
2124 SetCounter(bview->buffer(), par);
2126 /* now check for the headline layouts. remember that they
2127 * have a dynamic left margin */
2132 ( textclasslist.Style(bview->buffer()->params.textclass,
2133 par->layout).margintype == MARGIN_DYNAMIC
2134 || textclasslist.Style(bview->buffer()->params.textclass,
2135 par->layout).labeltype == LABEL_SENSITIVE)
2138 /* Rebreak the paragraph */
2139 RemoveParagraph(row);
2140 AppendParagraph(bview, row);
2143 /* think about the damned open footnotes! */
2144 while (par->Next() &&
2145 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2146 || par->Next()->IsDummy())){
2148 if (par->IsDummy()) {
2149 while (row->par() != par)
2151 RemoveParagraph(row);
2152 AppendParagraph(bview, row);
2158 par = par->LastPhysicalPar()->Next();
2167 /* insets an inset. */
2168 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2170 if (!cursor.par()->InsertInsetAllowed(inset))
2172 SetUndo(bview->buffer(), Undo::INSERT,
2174 cursor.par()->ParFromPos(cursor.pos())->previous,
2175 cursor.par()->ParFromPos(cursor.pos())->next
2177 cursor.par()->previous,
2181 cursor.par()->InsertInset(cursor.pos(), inset);
2182 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2183 * The character will not be inserted a
2188 void LyXText::copyEnvironmentType()
2190 copylayouttype = cursor.par()->GetLayout();
2194 void LyXText::pasteEnvironmentType(BufferView * bview)
2196 SetLayout(bview, copylayouttype);
2200 void LyXText::CutSelection(BufferView * bview, bool doclear)
2202 // Stuff what we got on the clipboard. Even if there is no selection.
2204 // There is a problem with having the stuffing here in that the
2205 // larger the selection the slower LyX will get. This can be
2206 // solved by running the line below only when the selection has
2207 // finished. The solution used currently just works, to make it
2208 // faster we need to be more clever and probably also have more
2209 // calls to stuffClipboard. (Lgb)
2210 bview->stuffClipboard(selectionAsString(bview->buffer()));
2212 // This doesn't make sense, if there is no selection
2216 // OK, we have a selection. This is always between sel_start_cursor
2217 // and sel_end cursor
2219 // Check whether there are half footnotes in the selection
2220 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2221 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2222 LyXParagraph * tmppar = sel_start_cursor.par();
2223 while (tmppar != sel_end_cursor.par()){
2224 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2225 WriteAlert(_("Impossible operation"),
2226 _("Don't know what to do with half floats."),
2230 tmppar = tmppar->Next();
2235 /* table stuff -- begin */
2236 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2237 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2238 WriteAlert(_("Impossible operation"),
2239 _("Don't know what to do with half tables."),
2243 sel_start_cursor.par()->table->Reinit();
2245 /* table stuff -- end */
2247 // make sure that the depth behind the selection are restored, too
2249 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2251 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2253 LyXParagraph * undoendpar = endpar;
2255 if (endpar && endpar->GetDepth()) {
2256 while (endpar && endpar->GetDepth()) {
2258 endpar = endpar->LastPhysicalPar()->Next();
2260 endpar = endpar->Next();
2262 undoendpar = endpar;
2264 } else if (endpar) {
2265 endpar = endpar->Next(); // because of parindents etc.
2268 SetUndo(bview->buffer(), Undo::DELETE,
2271 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2273 sel_start_cursor.par()->previous,
2279 // there are two cases: cut only within one paragraph or
2280 // more than one paragraph
2282 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2283 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2285 if (sel_start_cursor.par() == sel_end_cursor.par())
2288 // only within one paragraph
2289 endpar = sel_start_cursor.par();
2290 int pos = sel_end_cursor.pos();
2291 cap.cutSelection(sel_start_cursor.par(), &endpar,
2292 sel_start_cursor.pos(), pos,
2293 bview->buffer()->params.textclass, doclear);
2294 sel_end_cursor.pos(pos);
2296 endpar = sel_end_cursor.par();
2298 int pos = sel_end_cursor.pos();
2299 cap.cutSelection(sel_start_cursor.par(), &endpar,
2300 sel_start_cursor.pos(), pos,
2301 bview->buffer()->params.textclass, doclear);
2303 sel_end_cursor.par(endpar);
2304 sel_end_cursor.pos(pos);
2305 cursor.pos(sel_end_cursor.pos());
2307 endpar = endpar->Next();
2309 // sometimes necessary
2311 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2313 RedoParagraphs(bview, sel_start_cursor, endpar);
2316 cursor = sel_start_cursor;
2317 SetCursor(bview, cursor.par(), cursor.pos());
2318 sel_cursor = cursor;
2319 UpdateCounters(bview, cursor.row());
2323 void LyXText::CopySelection(BufferView * bview)
2325 // Stuff what we got on the clipboard. Even if there is no selection.
2327 // There is a problem with having the stuffing here in that the
2328 // larger the selection the slower LyX will get. This can be
2329 // solved by running the line below only when the selection has
2330 // finished. The solution used currently just works, to make it
2331 // faster we need to be more clever and probably also have more
2332 // calls to stuffClipboard. (Lgb)
2333 bview->stuffClipboard(selectionAsString(bview->buffer()));
2335 // this doesnt make sense, if there is no selection
2339 // ok we have a selection. This is always between sel_start_cursor
2340 // and sel_end cursor
2343 /* check wether there are half footnotes in the selection */
2344 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2345 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2346 LyXParagraph * tmppar = sel_start_cursor.par();
2347 while (tmppar != sel_end_cursor.par()) {
2348 if (tmppar->footnoteflag !=
2349 sel_end_cursor.par()->footnoteflag) {
2350 WriteAlert(_("Impossible operation"),
2351 _("Don't know what to do"
2352 " with half floats."),
2356 tmppar = tmppar->Next();
2361 /* table stuff -- begin */
2362 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2363 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2364 WriteAlert(_("Impossible operation"),
2365 _("Don't know what to do with half tables."),
2370 /* table stuff -- end */
2373 // copy behind a space if there is one
2374 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2375 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2376 && (sel_start_cursor.par() != sel_end_cursor.par()
2377 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2378 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2382 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2383 sel_start_cursor.pos(), sel_end_cursor.pos(),
2384 bview->buffer()->params.textclass);
2388 void LyXText::PasteSelection(BufferView * bview)
2392 // this does not make sense, if there is nothing to paste
2393 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2396 SetUndo(bview->buffer(), Undo::INSERT,
2398 cursor.par()->ParFromPos(cursor.pos())->previous,
2399 cursor.par()->ParFromPos(cursor.pos())->next
2401 cursor.par()->previous,
2406 LyXParagraph * endpar;
2407 LyXParagraph * actpar = cursor.par();
2409 int pos = cursor.pos();
2410 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2412 RedoParagraphs(bview, cursor, endpar);
2414 SetCursor(bview, cursor.par(), cursor.pos());
2417 sel_cursor = cursor;
2418 SetCursor(bview, actpar, pos);
2420 UpdateCounters(bview, cursor.row());
2424 // returns a pointer to the very first LyXParagraph
2425 LyXParagraph * LyXText::FirstParagraph() const
2427 return OwnerParagraph();
2431 // returns true if the specified string is at the specified position
2432 bool LyXText::IsStringInText(LyXParagraph * par,
2433 LyXParagraph::size_type pos,
2434 string const & str) const
2438 while (pos + i < par->Last() && i < str.length()&&
2439 str[i] == par->GetChar(pos + i)) {
2442 if (str.length() == i)
2449 // sets the selection over the number of characters of string, no check!!
2450 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2452 sel_cursor = cursor;
2453 for (int i = 0; str[i]; ++i)
2459 // simple replacing. The font of the first selected character is used
2460 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2463 SetCursorParUndo(bview->buffer());
2466 if (!selection) { // create a dummy selection
2467 sel_end_cursor = cursor;
2468 sel_start_cursor = cursor;
2471 // Get font setting before we cut
2472 LyXParagraph::size_type pos = sel_end_cursor.pos();
2473 LyXFont const font = sel_start_cursor.par()
2474 ->GetFontSettings(bview->buffer()->params,
2475 sel_start_cursor.pos());
2477 // Insert the new string
2478 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2479 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2483 // Cut the selection
2484 CutSelection(bview);
2490 // if the string can be found: return true and set the cursor to
2492 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2494 LyXParagraph * par = cursor.par();
2495 LyXParagraph::size_type pos = cursor.pos();
2496 while (par && !IsStringInText(par, pos, str)) {
2497 if (pos < par->Last() - 1)
2505 SetCursor(bview, par, pos);
2513 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2515 LyXParagraph * par = cursor.par();
2516 int pos = cursor.pos();
2522 // We skip empty paragraphs (Asger)
2524 par = par->Previous();
2526 pos = par->Last() - 1;
2527 } while (par && pos < 0);
2529 } while (par && !IsStringInText(par, pos, str));
2532 SetCursor(bview, par, pos);
2539 // needed to insert the selection
2540 void LyXText::InsertStringA(BufferView * bview, string const & str)
2542 LyXParagraph * par = cursor.par();
2543 LyXParagraph::size_type pos = cursor.pos();
2544 LyXParagraph::size_type a = 0;
2545 LyXParagraph * endpar = cursor.par()->Next();
2547 SetCursorParUndo(bview->buffer());
2550 textclasslist.Style(bview->buffer()->params.textclass,
2551 cursor.par()->GetLayout()).isEnvironment();
2552 // only to be sure, should not be neccessary
2555 // insert the string, don't insert doublespace
2556 string::size_type i = 0;
2557 while (i < str.length()) {
2558 if (str[i] != '\n') {
2560 && i + 1 < str.length() && str[i + 1] != ' '
2561 && pos && par->GetChar(pos - 1)!= ' ') {
2562 par->InsertChar(pos, ' ', current_font);
2565 } else if (par->table) {
2566 if (str[i] == '\t') {
2567 while((pos < par->size()) &&
2568 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2570 if (pos < par->size())
2572 else // no more fields to fill skip the rest
2574 } else if ((str[i] != 13) &&
2575 ((str[i] & 127) >= ' ')) {
2576 par->InsertChar(pos, str[i],
2581 } else if (str[i] == ' ') {
2582 InsetSpecialChar * new_inset =
2583 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2584 if (par->InsertInsetAllowed(new_inset)) {
2585 par->InsertInset(pos, new_inset,
2591 } else if (str[i] == '\t') {
2592 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2593 InsetSpecialChar * new_inset =
2594 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2595 if (par->InsertInsetAllowed(new_inset)) {
2596 par->InsertInset(pos, new_inset,
2603 } else if (str[i] != 13 &&
2604 // Ignore unprintables
2605 (str[i] & 127) >= ' ') {
2606 par->InsertChar(pos, str[i], current_font);
2612 if ((i + 1) >= str.length()) {
2613 if (pos < par->size())
2617 while((pos < par->size()) &&
2618 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2621 int cell = NumberOfCell(par, pos);
2622 while((pos < par->size()) &&
2623 !(par->table->IsFirstCell(cell))) {
2625 while((pos < par->size()) &&
2626 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2629 cell = NumberOfCell(par, pos);
2631 if (pos >= par->size())
2632 // no more fields to fill skip the rest
2636 if (!par->size()) { // par is empty
2637 InsetSpecialChar * new_inset =
2638 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2639 if (par->InsertInsetAllowed(new_inset)) {
2640 par->InsertInset(pos,
2648 par->BreakParagraph(bview->buffer()->params, pos, flag);
2658 RedoParagraphs(bview, cursor, endpar);
2659 SetCursor(bview, cursor.par(), cursor.pos());
2660 sel_cursor = cursor;
2661 SetCursor(bview, par, pos);
2666 /* turns double-CR to single CR, others where converted into one blank and 13s
2667 * that are ignored .Double spaces are also converted into one. Spaces at
2668 * the beginning of a paragraph are forbidden. tabs are converted into one
2669 * space. then InsertStringA is called */
2670 void LyXText::InsertStringB(BufferView * bview, string const & s)
2674 LyXParagraph * par = cursor.par();
2676 string::size_type i = 1;
2677 while (i < str.length()) {
2684 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2686 if (str[i] == '\n' && i + 1 < str.length()
2691 if (str[i + 1] != '\n') {
2692 if (str[i - 1] != ' ')
2697 while (i + 1 < str.length()
2698 && (str[i + 1] == ' '
2699 || str[i + 1] == '\t'
2700 || str[i + 1] == '\n'
2701 || str[i + 1] == 13)) {
2708 InsertStringA(bview, str);
2712 bool LyXText::GotoNextError(BufferView * bview) const
2714 LyXCursor res = cursor;
2716 if (res.pos() < res.par()->Last() - 1) {
2717 res.pos(res.pos() + 1);
2719 res.par(res.par()->Next());
2723 } while (res.par() &&
2724 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2725 && res.par()->GetInset(res.pos())->AutoDelete()));
2728 SetCursor(bview, res.par(), res.pos());
2735 bool LyXText::GotoNextNote(BufferView * bview) const
2737 LyXCursor res = cursor;
2739 if (res.pos() < res.par()->Last() - 1) {
2740 res.pos(res.pos() + 1);
2742 res.par(res.par()->Next());
2746 } while (res.par() &&
2747 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2748 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2751 SetCursor(bview, res.par(), res.pos());
2758 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2759 LyXParagraph::size_type pos)
2761 LyXCursor tmpcursor;
2764 /* table stuff -- begin*/
2767 CheckParagraphInTable(bview, par, pos);
2771 /* table stuff -- end*/
2774 LyXParagraph::size_type z;
2775 Row * row = GetRow(par, pos, y);
2777 // is there a break one row above
2778 if (row->previous() && row->previous()->par() == row->par()) {
2779 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2780 if ( z >= row->pos()) {
2781 // set the dimensions of the row above
2782 y -= row->previous()->height();
2784 refresh_row = row->previous();
2785 status = LyXText::NEED_MORE_REFRESH;
2787 BreakAgain(bview, row->previous());
2789 // set the cursor again. Otherwise
2790 // dangling pointers are possible
2791 SetCursor(bview, cursor.par(), cursor.pos());
2792 sel_cursor = cursor;
2797 int tmpheight = row->height();
2798 LyXParagraph::size_type tmplast = RowLast(row);
2802 BreakAgain(bview, row);
2803 if (row->height() == tmpheight && RowLast(row) == tmplast)
2804 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2806 status = LyXText::NEED_MORE_REFRESH;
2808 // check the special right address boxes
2809 if (textclasslist.Style(bview->buffer()->params.textclass,
2810 par->GetLayout()).margintype
2811 == MARGIN_RIGHT_ADDRESS_BOX) {
2818 RedoDrawingOfParagraph(bview, tmpcursor);
2824 // set the cursor again. Otherwise dangling pointers are possible
2825 // also set the selection
2829 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2830 sel_cursor = cursor;
2831 SetCursorIntern(bview, sel_start_cursor.par(),
2832 sel_start_cursor.pos());
2833 sel_start_cursor = cursor;
2834 SetCursorIntern(bview, sel_end_cursor.par(),
2835 sel_end_cursor.pos());
2836 sel_end_cursor = cursor;
2837 SetCursorIntern(bview, last_sel_cursor.par(),
2838 last_sel_cursor.pos());
2839 last_sel_cursor = cursor;
2842 SetCursorIntern(bview, cursor.par(), cursor.pos());
2846 // returns false if inset wasn't found
2847 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2849 // first check the current paragraph
2850 int pos = cursor.par()->GetPositionOfInset(inset);
2852 CheckParagraph(bview, cursor.par(), pos);
2856 // check every paragraph
2858 LyXParagraph * par = FirstParagraph();
2861 // make sure the paragraph is open
2862 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2864 pos = par->GetPositionOfInset(inset);
2866 CheckParagraph(bview, par, pos);
2879 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2880 LyXParagraph::size_type pos,
2881 bool setfont, bool boundary) const
2883 LyXCursor old_cursor = cursor;
2884 SetCursorIntern(bview, par, pos, setfont, boundary);
2885 DeleteEmptyParagraphMechanism(bview, old_cursor);
2889 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2890 LyXParagraph::size_type pos, bool boundary) const
2893 // correct the cursor position if impossible
2894 if (pos > par->Last()){
2895 LyXParagraph * tmppar = par->ParFromPos(pos);
2896 pos = par->PositionInParFromPos(pos);
2899 if (par->IsDummy() && par->previous &&
2900 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2901 while (par->previous &&
2902 ((par->previous->IsDummy() &&
2903 (par->previous->previous->footnoteflag ==
2904 LyXParagraph::CLOSED_FOOTNOTE)) ||
2905 (par->previous->footnoteflag ==
2906 LyXParagraph::CLOSED_FOOTNOTE))) {
2907 par = par->previous ;
2908 if (par->IsDummy() &&
2909 (par->previous->footnoteflag ==
2910 LyXParagraph::CLOSED_FOOTNOTE))
2911 pos += par->size() + 1;
2913 if (par->previous) {
2914 par = par->previous;
2916 pos += par->size() + 1;
2921 cur.boundary(boundary);
2923 /* get the cursor y position in text */
2925 Row * row = GetRow(par, pos, y);
2926 /* y is now the beginning of the cursor row */
2927 y += row->baseline();
2928 /* y is now the cursor baseline */
2931 /* now get the cursors x position */
2933 float fill_separator, fill_hfill, fill_label_hfill;
2934 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2936 LyXParagraph::size_type cursor_vpos = 0;
2937 LyXParagraph::size_type last = RowLastPrintable(row);
2939 if (pos > last + 1) // This shouldn't happen.
2941 else if (pos < row->pos())
2944 if (last < row->pos())
2945 cursor_vpos = row->pos();
2946 else if (pos > last && !boundary)
2947 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2948 ? row->pos() : last + 1;
2949 else if (pos > row->pos() &&
2950 (pos > last || boundary
2952 || (row->par()->table && row->par()->IsNewline(pos))
2955 /// Place cursor after char at (logical) position pos - 1
2956 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2957 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2959 /// Place cursor before char at (logical) position pos
2960 cursor_vpos = (bidi_level(pos) % 2 == 0)
2961 ? log2vis(pos) : log2vis(pos) + 1;
2964 /* table stuff -- begin*/
2965 if (row->par()->table) {
2966 int cell = NumberOfCell(row->par(), row->pos());
2968 x += row->par()->table->GetBeginningOfTextInCell(cell);
2969 for (LyXParagraph::size_type vpos = row->pos();
2970 vpos < cursor_vpos; ++vpos) {
2971 pos = vis2log(vpos);
2972 if (row->par()->IsNewline(pos)) {
2973 x = x_old + row->par()->table->WidthOfColumn(cell);
2976 x += row->par()->table->GetBeginningOfTextInCell(cell);
2978 x += SingleWidth(bview, row->par(), pos);
2982 /* table stuff -- end*/
2984 LyXParagraph::size_type main_body =
2985 BeginningOfMainBody(bview->buffer(), row->par());
2986 if ((main_body > 0) &&
2987 ((main_body-1 > last) ||
2988 !row->par()->IsLineSeparator(main_body-1)))
2991 for (LyXParagraph::size_type vpos = row->pos();
2992 vpos < cursor_vpos; ++vpos) {
2993 pos = vis2log(vpos);
2994 if (main_body > 0 && pos == main_body-1) {
2995 x += fill_label_hfill +
2996 lyxfont::width(textclasslist.Style(
2997 bview->buffer()->params.textclass,
2998 row->par()->GetLayout())
3000 GetFont(bview->buffer(), row->par(), -2));
3001 if (row->par()->IsLineSeparator(main_body-1))
3002 x -= SingleWidth(bview, row->par(),main_body-1);
3004 if (HfillExpansion(bview->buffer(), row, pos)) {
3005 x += SingleWidth(bview, row->par(), pos);
3006 if (pos >= main_body)
3009 x += fill_label_hfill;
3010 } else if (row->par()->IsSeparator(pos)) {
3011 x += SingleWidth(bview, row->par(), pos);
3012 if (pos >= main_body)
3013 x += fill_separator;
3015 x += SingleWidth(bview, row->par(), pos);
3027 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3028 LyXParagraph::size_type pos,
3029 bool setfont, bool boundary) const
3031 SetCursor(bview, cursor, par, pos, boundary);
3033 SetCurrentFont(bview);
3036 void LyXText::SetCurrentFont(BufferView * bview) const
3038 LyXParagraph::size_type pos = cursor.pos();
3039 if (cursor.boundary() && pos > 0)
3043 if (pos == cursor.par()->Last()
3045 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3049 else if (cursor.par()->IsSeparator(pos)) {
3050 if (pos > cursor.row()->pos() &&
3051 bidi_level(pos) % 2 ==
3052 bidi_level(pos - 1) % 2)
3054 else if (pos + 1 < cursor.par()->Last())
3060 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3061 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3063 if (cursor.pos() == cursor.par()->Last() &&
3064 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3065 !cursor.boundary()) {
3066 Language const * lang =
3067 cursor.par()->getParLanguage(bview->buffer()->params);
3068 current_font.setLanguage(lang);
3069 real_current_font.setLanguage(lang);
3074 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3076 LyXCursor old_cursor = cursor;
3078 /* get the row first */
3080 Row * row = GetRowNearY(y);
3081 cursor.par(row->par());
3084 int column = GetColumnNearX(bview, row, x, bound);
3085 cursor.pos(row->pos() + column);
3087 cursor.y(y + row->baseline());
3089 cursor.boundary(bound);
3090 SetCurrentFont(bview);
3091 DeleteEmptyParagraphMechanism(bview, old_cursor);
3095 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3096 int x, long y) const
3098 /* get the row first */
3100 Row * row = GetRowNearY(y);
3102 int column = GetColumnNearX(bview, row, x, bound);
3104 cur.par(row->par());
3105 cur.pos(row->pos() + column);
3107 cur.y(y + row->baseline());
3109 cur.boundary(bound);
3113 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3115 CursorLeftIntern(bview, internal);
3117 if (cursor.par()->table) {
3118 int cell = NumberOfCell(cursor.par(), cursor.pos());
3119 if (cursor.par()->table->IsContRow(cell)
3120 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3128 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3130 if (cursor.pos() > 0) {
3131 bool boundary = cursor.boundary();
3132 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3133 if (!internal && !boundary &&
3134 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3135 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3136 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3137 LyXParagraph * par = cursor.par()->Previous();
3138 SetCursor(bview, par, par->Last());
3143 void LyXText::CursorRight(BufferView * bview, bool internal) const
3145 CursorRightIntern(bview, internal);
3147 if (cursor.par()->table) {
3148 int cell = NumberOfCell(cursor.par(), cursor.pos());
3149 if (cursor.par()->table->IsContRow(cell) &&
3150 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3158 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3160 if (!internal && cursor.boundary() &&
3163 !cursor.par()->table ||
3165 !cursor.par()->IsNewline(cursor.pos())))
3166 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3167 else if (cursor.pos() < cursor.par()->Last()) {
3168 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3170 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3171 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3172 } else if (cursor.par()->Next())
3173 SetCursor(bview, cursor.par()->Next(), 0);
3177 void LyXText::CursorUp(BufferView * bview) const
3179 SetCursorFromCoordinates(bview, cursor.x_fix(),
3180 cursor.y() - cursor.row()->baseline() - 1);
3182 if (cursor.par()->table) {
3183 int cell = NumberOfCell(cursor.par(), cursor.pos());
3184 if (cursor.par()->table->IsContRow(cell) &&
3185 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3193 void LyXText::CursorDown(BufferView * bview) const
3196 if (cursor.par()->table &&
3197 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3198 !cursor.par()->next)
3202 SetCursorFromCoordinates(bview, cursor.x_fix(),
3203 cursor.y() - cursor.row()->baseline()
3204 + cursor.row()->height() + 1);
3206 if (cursor.par()->table) {
3207 int cell = NumberOfCell(cursor.par(), cursor.pos());
3208 int cell_above = cursor.par()->table->GetCellAbove(cell);
3209 while(cursor.par()->table &&
3210 cursor.par()->table->IsContRow(cell) &&
3211 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3212 SetCursorFromCoordinates(bview, cursor.x_fix(),
3213 cursor.y() - cursor.row()->baseline()
3214 + cursor.row()->height() + 1);
3215 if (cursor.par()->table) {
3216 cell = NumberOfCell(cursor.par(), cursor.pos());
3217 cell_above = cursor.par()->table->GetCellAbove(cell);
3225 void LyXText::CursorUpParagraph(BufferView * bview) const
3227 if (cursor.pos() > 0) {
3228 SetCursor(bview, cursor.par(), 0);
3230 else if (cursor.par()->Previous()) {
3231 SetCursor(bview, cursor.par()->Previous(), 0);
3236 void LyXText::CursorDownParagraph(BufferView * bview) const
3238 if (cursor.par()->Next()) {
3239 SetCursor(bview, cursor.par()->Next(), 0);
3241 SetCursor(bview, cursor.par(), cursor.par()->Last());
3246 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3247 LyXCursor const & old_cursor) const
3249 // Would be wrong to delete anything if we have a selection.
3250 if (selection) return;
3252 // We allow all kinds of "mumbo-jumbo" when freespacing.
3253 if (textclasslist.Style(bview->buffer()->params.textclass,
3254 old_cursor.par()->GetLayout()).free_spacing)
3257 bool deleted = false;
3259 /* Ok I'll put some comments here about what is missing.
3260 I have fixed BackSpace (and thus Delete) to not delete
3261 double-spaces automagically. I have also changed Cut,
3262 Copy and Paste to hopefully do some sensible things.
3263 There are still some small problems that can lead to
3264 double spaces stored in the document file or space at
3265 the beginning of paragraphs. This happens if you have
3266 the cursor betwenn to spaces and then save. Or if you
3267 cut and paste and the selection have a space at the
3268 beginning and then save right after the paste. I am
3269 sure none of these are very hard to fix, but I will
3270 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3271 that I can get some feedback. (Lgb)
3274 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3275 // delete the LineSeparator.
3278 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3279 // delete the LineSeparator.
3282 // If the pos around the old_cursor were spaces, delete one of them.
3283 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3284 // Only if the cursor has really moved
3286 if (old_cursor.pos() > 0
3287 && old_cursor.pos() < old_cursor.par()->Last()
3288 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3289 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3290 old_cursor.par()->Erase(old_cursor.pos() - 1);
3291 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3293 if (old_cursor.par() == cursor.par() &&
3294 cursor.pos() > old_cursor.pos()) {
3295 SetCursorIntern(bview, cursor.par(),
3298 SetCursorIntern(bview, cursor.par(),
3304 // Do not delete empty paragraphs with keepempty set.
3305 if ((textclasslist.Style(bview->buffer()->params.textclass,
3306 old_cursor.par()->GetLayout())).keepempty)
3309 LyXCursor tmpcursor;
3311 if (old_cursor.par() != cursor.par()) {
3312 if ( (old_cursor.par()->Last() == 0
3313 || (old_cursor.par()->Last() == 1
3314 && old_cursor.par()->IsLineSeparator(0)))
3316 && old_cursor.par()->FirstPhysicalPar()
3317 == old_cursor.par()->LastPhysicalPar()
3320 // ok, we will delete anything
3322 // make sure that you do not delete any environments
3325 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3326 !(old_cursor.row()->previous()
3327 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3328 && !(old_cursor.row()->next()
3329 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3330 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3331 && ((old_cursor.row()->previous()
3332 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3333 || (old_cursor.row()->next()
3334 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3337 status = LyXText::NEED_MORE_REFRESH;
3340 if (old_cursor.row()->previous()) {
3341 refresh_row = old_cursor.row()->previous();
3342 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3344 cursor = old_cursor; // that undo can restore the right cursor position
3345 LyXParagraph * endpar = old_cursor.par()->next;
3346 if (endpar && endpar->GetDepth()) {
3347 while (endpar && endpar->GetDepth()) {
3349 endpar = endpar->LastPhysicalPar()->Next();
3351 endpar = endpar->Next();
3355 SetUndo(bview->buffer(), Undo::DELETE,
3356 old_cursor.par()->previous,
3361 RemoveRow(old_cursor.row());
3362 if (OwnerParagraph() == old_cursor.par()) {
3363 OwnerParagraph(OwnerParagraph()->next);
3366 delete old_cursor.par();
3368 /* Breakagain the next par. Needed
3369 * because of the parindent that
3370 * can occur or dissappear. The
3371 * next row can change its height,
3372 * if there is another layout before */
3373 if (refresh_row->next()) {
3374 BreakAgain(bview, refresh_row->next());
3375 UpdateCounters(bview, refresh_row);
3377 SetHeightOfRow(bview, refresh_row);
3379 refresh_row = old_cursor.row()->next();
3380 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3383 cursor = old_cursor; // that undo can restore the right cursor position
3384 LyXParagraph * endpar = old_cursor.par()->next;
3385 if (endpar && endpar->GetDepth()) {
3386 while (endpar && endpar->GetDepth()) {
3388 endpar = endpar->LastPhysicalPar()->Next();
3390 endpar = endpar->Next();
3394 SetUndo(bview->buffer(), Undo::DELETE,
3395 old_cursor.par()->previous,
3400 RemoveRow(old_cursor.row());
3402 if (OwnerParagraph() == old_cursor.par()) {
3403 OwnerParagraph(OwnerParagraph()->next);
3405 delete old_cursor.par();
3407 /* Breakagain the next par. Needed
3408 because of the parindent that can
3409 occur or dissappear.
3410 The next row can change its height,
3411 if there is another layout before
3414 BreakAgain(bview, refresh_row);
3415 UpdateCounters(bview, refresh_row->previous());
3421 SetCursorIntern(bview, cursor.par(), cursor.pos());
3423 if (sel_cursor.par() == old_cursor.par()
3424 && sel_cursor.pos() == sel_cursor.pos()) {
3425 // correct selection
3426 sel_cursor = cursor;
3433 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3434 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3436 SetCursorIntern(bview, cursor.par(), cursor.pos());
3437 sel_cursor = cursor;
3444 LyXParagraph * LyXText::GetParFromID(int id)
3446 LyXParagraph * result = FirstParagraph();
3447 while (result && result->id() != id)
3448 result = result->next;
3454 bool LyXText::TextUndo(BufferView * bview)
3458 // returns false if no undo possible
3459 Undo * undo = bview->buffer()->undostack.pop();
3463 bview->buffer()->redostack
3464 .push(CreateUndo(bview->buffer(), undo->kind,
3465 GetParFromID(undo->number_of_before_par),
3466 GetParFromID(undo->number_of_behind_par)));
3468 return TextHandleUndo(bview, undo);
3472 bool LyXText::TextRedo(BufferView * bview)
3476 // returns false if no redo possible
3477 Undo * undo = bview->buffer()->redostack.pop();
3481 bview->buffer()->undostack
3482 .push(CreateUndo(bview->buffer(), undo->kind,
3483 GetParFromID(undo->number_of_before_par),
3484 GetParFromID(undo->number_of_behind_par)));
3486 return TextHandleUndo(bview, undo);
3490 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3494 // returns false if no undo possible
3495 bool result = false;
3497 LyXParagraph * before =
3498 GetParFromID(undo->number_of_before_par);
3499 LyXParagraph * behind =
3500 GetParFromID(undo->number_of_behind_par);
3501 LyXParagraph * tmppar;
3502 LyXParagraph * tmppar2;
3503 LyXParagraph * endpar;
3504 LyXParagraph * tmppar5;
3506 // if there's no before take the beginning
3507 // of the document for redoing
3509 SetCursorIntern(bview, FirstParagraph(), 0);
3511 // replace the paragraphs with the undo informations
3513 LyXParagraph * tmppar3 = undo->par;
3514 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3515 LyXParagraph * tmppar4 = tmppar3;
3517 while (tmppar4->next)
3518 tmppar4 = tmppar4->next;
3519 } // get last undo par
3521 // now remove the old text if there is any
3522 if (before != behind || (!behind && !before)){
3524 tmppar5 = before->next;
3526 tmppar5 = OwnerParagraph();
3528 while (tmppar5 && tmppar5 != behind){
3530 tmppar5 = tmppar5->next;
3531 // a memory optimization for edit: Only layout information
3532 // is stored in the undo. So restore the text informations.
3533 if (undo->kind == Undo::EDIT) {
3534 tmppar2->setContentsFromPar(tmppar);
3535 tmppar->clearContents();
3536 tmppar2 = tmppar2->next;
3541 // put the new stuff in the list if there is one
3544 before->next = tmppar3;
3546 OwnerParagraph(tmppar3);
3547 tmppar3->previous = before;
3550 OwnerParagraph(behind);
3553 tmppar4->next = behind;
3555 behind->previous = tmppar4;
3559 // Set the cursor for redoing
3562 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3564 SetCursorIntern(bview, before, 0);
3567 // check wether before points to a closed float and open it if necessary
3568 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3569 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3571 while (tmppar4->previous &&
3572 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3573 tmppar4 = tmppar4->previous;
3574 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3575 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3576 tmppar4 = tmppar4->next;
3583 // open a cosed footnote at the end if necessary
3584 if (behind && behind->previous &&
3585 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3586 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3587 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3588 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3589 behind = behind->next;
3594 // calculate the endpar for redoing the paragraphs.
3597 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3598 endpar = behind->LastPhysicalPar()->Next();
3600 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3602 endpar = behind->Next();
3607 tmppar = GetParFromID(undo->number_of_cursor_par);
3608 RedoParagraphs(bview, cursor, endpar);
3610 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3611 UpdateCounters(bview, cursor.row());
3621 void LyXText::FinishUndo()
3625 // makes sure the next operation will be stored
3626 undo_finished = true;
3630 void LyXText::FreezeUndo()
3634 // this is dangerous and for internal use only
3639 void LyXText::UnFreezeUndo()
3643 // this is dangerous and for internal use only
3644 undo_frozen = false;
3648 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3649 LyXParagraph const * before,
3650 LyXParagraph const * behind) const
3655 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3656 buf->redostack.clear();
3660 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3661 LyXParagraph const * before, LyXParagraph const * behind)
3665 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3669 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3670 LyXParagraph const * before,
3671 LyXParagraph const * behind) const
3676 int before_number = -1;
3677 int behind_number = -1;
3679 before_number = before->id();
3681 behind_number = behind->id();
3682 // Undo::EDIT and Undo::FINISH are
3683 // always finished. (no overlapping there)
3684 // overlapping only with insert and delete inside one paragraph:
3685 // Nobody wants all removed character
3686 // appear one by one when undoing.
3687 // EDIT is special since only layout information, not the
3688 // contents of a paragaph are stored.
3689 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3690 // check wether storing is needed
3691 if (!buf->undostack.empty() &&
3692 buf->undostack.top()->kind == kind &&
3693 buf->undostack.top()->number_of_before_par == before_number &&
3694 buf->undostack.top()->number_of_behind_par == behind_number ){
3699 // create a new Undo
3700 LyXParagraph * undopar;
3701 LyXParagraph * tmppar;
3702 LyXParagraph * tmppar2;
3704 LyXParagraph * start = 0;
3705 LyXParagraph * end = 0;
3708 start = before->next;
3710 start = FirstParagraph();
3712 end = behind->previous;
3714 end = FirstParagraph();
3720 && start != end->next
3721 && (before != behind || (!before && !behind))) {
3723 tmppar2 = tmppar->Clone();
3724 tmppar2->id(tmppar->id());
3726 // a memory optimization: Just store the layout information
3728 if (kind == Undo::EDIT){
3729 //tmppar2->text.clear();
3730 tmppar2->clearContents();
3735 while (tmppar != end && tmppar->next) {
3736 tmppar = tmppar->next;
3737 tmppar2->next = tmppar->Clone();
3738 tmppar2->next->id(tmppar->id());
3739 // a memory optimization: Just store the layout
3740 // information when only edit
3741 if (kind == Undo::EDIT){
3742 //tmppar2->next->text.clear();
3743 tmppar2->clearContents();
3745 tmppar2->next->previous = tmppar2;
3746 tmppar2 = tmppar2->next;
3750 undopar = 0; // nothing to replace (undo of delete maybe)
3753 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3754 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3756 int cursor_par = cursor.par()->id();
3757 int cursor_pos = cursor.pos();
3760 Undo * undo = new Undo(kind,
3761 before_number, behind_number,
3762 cursor_par, cursor_pos,
3765 undo_finished = false;
3770 void LyXText::SetCursorParUndo(Buffer * buf)
3774 SetUndo(buf, Undo::FINISH,
3776 cursor.par()->ParFromPos(cursor.pos())->previous,
3777 cursor.par()->ParFromPos(cursor.pos())->next
3779 cursor.par()->previous,
3787 void LyXText::RemoveTableRow(LyXCursor & cur) const
3793 // move to the previous row
3794 int cell_act = NumberOfCell(cur.par(), cur.pos());
3797 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3798 cur.pos(cur.pos() - 1);
3800 !cur.par()->table->IsFirstCell(cell_act)) {
3801 cur.pos(cur.pos() - 1);
3802 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3803 cur.pos(cur.pos() - 1);
3807 // now we have to pay attention if the actual table is the
3808 // main row of TableContRows and if yes to delete all of them
3813 // delete up to the next row
3814 while (cur.pos() < cur.par()->Last() &&
3816 || !cur.par()->table->IsFirstCell(cell_act))) {
3817 while (cur.pos() < cur.par()->Last() &&
3818 !cur.par()->IsNewline(cur.pos()))
3819 cur.par()->Erase(cur.pos());
3822 if (cur.pos() < cur.par()->Last())
3823 cur.par()->Erase(cur.pos());
3825 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3826 cur.pos(cur.pos() - 1);
3827 cur.par()->Erase(cur.pos()); // no newline at very end!
3829 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3830 !cur.par()->table->IsContRow(cell_org) &&
3831 cur.par()->table->IsContRow(cell));
3832 cur.par()->table->DeleteRow(cell_org);
3839 bool LyXText::IsEmptyTableCell() const
3841 LyXParagraph::size_type pos = cursor.pos() - 1;
3842 while (pos >= 0 && pos < cursor.par()->Last()
3843 && !cursor.par()->IsNewline(pos))
3845 return cursor.par()->IsNewline(pos + 1);
3850 void LyXText::toggleAppendix(BufferView * bview)
3853 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3855 LyXParagraph * par = cursor.par();
3857 bool start = !par->start_of_appendix;
3859 // ensure that we have only one start_of_appendix in this document
3860 LyXParagraph * tmp = FirstParagraph();
3861 for (; tmp; tmp = tmp->next)
3862 tmp->start_of_appendix = 0;
3863 par->start_of_appendix = start;
3865 // we can set the refreshing parameters now
3866 status = LyXText::NEED_MORE_REFRESH;
3868 refresh_row = 0; // not needed for full update
3869 UpdateCounters(bview, 0);
3870 SetCursor(bview, cursor.par(), cursor.pos());
3874 LyXParagraph * LyXText::OwnerParagraph() const
3877 return inset_owner->par;
3879 return bv_owner->buffer()->paragraph;
3883 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3886 inset_owner->par = p;
3888 bv_owner->buffer()->paragraph = p;