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 std::ostringstream s;
1837 if (!par->appendix) {
1838 switch (2 * LABEL_COUNTER_CHAPTER -
1839 textclass.maxcounter() + i) {
1840 case LABEL_COUNTER_CHAPTER:
1841 s << par->getCounter(i);
1843 case LABEL_COUNTER_SECTION:
1844 s << par->getCounter(i - 1) << '.'
1845 << par->getCounter(i);
1847 case LABEL_COUNTER_SUBSECTION:
1848 s << par->getCounter(i - 2) << '.'
1849 << par->getCounter(i - 1) << '.'
1850 << par->getCounter(i);
1852 case LABEL_COUNTER_SUBSUBSECTION:
1853 s << par->getCounter(i - 3) << '.'
1854 << par->getCounter(i - 2) << '.'
1855 << par->getCounter(i - 1) << '.'
1856 << par->getCounter(i);
1859 case LABEL_COUNTER_PARAGRAPH:
1860 s << par->getCounter(i - 4) << '.'
1861 << par->getCounter(i - 3) << '.'
1862 << par->getCounter(i - 2) << '.'
1863 << par->getCounter(i - 1) << '.'
1864 << par->getCounter(i);
1866 case LABEL_COUNTER_SUBPARAGRAPH:
1867 s << par->getCounter(i - 5) << '.'
1868 << par->getCounter(i - 4) << '.'
1869 << par->getCounter(i - 3) << '.'
1870 << par->getCounter(i - 2) << '.'
1871 << par->getCounter(i - 1) << '.'
1872 << par->getCounter(i);
1876 // Can this ever be reached? And in the
1877 // case it is, how can this be correct?
1879 s << par->getCounter(i) << '.';
1882 } else { // appendix
1883 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1884 case LABEL_COUNTER_CHAPTER:
1885 if (par->isRightToLeftPar(buf->params))
1886 s << hebrewCounter(par->getCounter(i));
1888 s << alphaCounter(par->getCounter(i));
1890 case LABEL_COUNTER_SECTION:
1891 if (par->isRightToLeftPar(buf->params))
1892 s << hebrewCounter(par->getCounter(i - 1));
1894 s << alphaCounter(par->getCounter(i - 1));
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_SUBSECTION:
1901 if (par->isRightToLeftPar(buf->params))
1902 s << hebrewCounter(par->getCounter(i - 2));
1904 s << alphaCounter(par->getCounter(i - 2));
1907 << par->getCounter(i-1) << '.'
1908 << par->getCounter(i);
1911 case LABEL_COUNTER_SUBSUBSECTION:
1912 if (par->isRightToLeftPar(buf->params))
1913 s << hebrewCounter(par->getCounter(i-3));
1915 s << alphaCounter(par->getCounter(i-3));
1918 << par->getCounter(i-2) << '.'
1919 << par->getCounter(i-1) << '.'
1920 << par->getCounter(i);
1923 case LABEL_COUNTER_PARAGRAPH:
1924 if (par->isRightToLeftPar(buf->params))
1925 s << hebrewCounter(par->getCounter(i-4));
1927 s << alphaCounter(par->getCounter(i-4));
1930 << par->getCounter(i-3) << '.'
1931 << par->getCounter(i-2) << '.'
1932 << par->getCounter(i-1) << '.'
1933 << par->getCounter(i);
1936 case LABEL_COUNTER_SUBPARAGRAPH:
1937 if (par->isRightToLeftPar(buf->params))
1938 s << hebrewCounter(par->getCounter(i-5));
1940 s << alphaCounter(par->getCounter(i-5));
1943 << par->getCounter(i-4) << '.'
1944 << par->getCounter(i-3) << '.'
1945 << par->getCounter(i-2) << '.'
1946 << par->getCounter(i-1) << '.'
1947 << par->getCounter(i);
1951 // Can this ever be reached? And in the
1952 // case it is, how can this be correct?
1954 s << par->getCounter(i) << '.';
1960 par->labelstring += s.str().c_str();
1961 // We really want to remove the c_str as soon as
1964 for (i++; i < 10; ++i) {
1965 // reset the following counters
1966 par->setCounter(i, 0);
1968 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1969 for (i++; i < 10; ++i) {
1970 // reset the following counters
1971 par->setCounter(i, 0);
1973 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1974 par->incCounter(i + par->enumdepth);
1975 int number = par->getCounter(i + par->enumdepth);
1977 std::ostringstream s;
1979 switch (par->enumdepth) {
1981 if (par->isRightToLeftPar(buf->params))
1983 << hebrewCounter(number)
1987 << loweralphaCounter(number)
1991 if (par->isRightToLeftPar(buf->params))
1992 s << '.' << romanCounter(number);
1994 s << romanCounter(number) << '.';
1997 if (par->isRightToLeftPar(buf->params))
1999 << alphaCounter(number);
2001 s << alphaCounter(number)
2005 if (par->isRightToLeftPar(buf->params))
2012 par->labelstring = s.str().c_str();
2013 // we really want to get rid of that c_str()
2015 for (i += par->enumdepth + 1; i < 10; ++i)
2016 par->setCounter(i, 0); /* reset the following counters */
2019 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2020 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2022 int number = par->getCounter(i);
2024 InsetCommandParams p( "bibitem" );
2025 par->bibkey = new InsetBibKey(p);
2027 par->bibkey->setCounter(number);
2028 par->labelstring = layout.labelstring();
2030 // In biblio should't be following counters but...
2032 string s = layout.labelstring();
2034 // the caption hack:
2035 if (layout.labeltype == LABEL_SENSITIVE) {
2036 bool isOK (par->InInset() && par->InInset()->owner() &&
2037 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2039 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2040 && (par->footnotekind == LyXParagraph::FIG
2041 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2042 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2043 ? ":øåéà " : "Figure:";
2044 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2045 && (par->footnotekind == LyXParagraph::TAB
2046 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2047 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2048 ? ":äìáè" : "Table:";
2049 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2050 && par->footnotekind == LyXParagraph::ALGORITHM) {
2051 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2052 ? ":Ãúéøåâìà " : "Algorithm:";
2056 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2058 = floatList.getType(tmp->type());
2059 // We should get the correct number here too.
2060 s = fl.name + " #:";
2062 /* par->SetLayout(0);
2063 s = layout->labelstring; */
2064 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2065 ? " :úåòîùî øñç" : "Senseless: ";
2068 par->labelstring = s;
2070 /* reset the enumeration counter. They are always resetted
2071 * when there is any other layout between */
2072 for (int i = 6 + par->enumdepth; i < 10; ++i)
2073 par->setCounter(i, 0);
2078 /* Updates all counters BEHIND the row. Changed paragraphs
2079 * with a dynamic left margin will be rebroken. */
2080 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2087 if (row->par()->next
2089 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2093 par = row->par()->LastPhysicalPar()->Next();
2095 par = row->par()->Next();
2098 par = row->par()->next;
2103 while (row->par() != par)
2106 SetCounter(bview->buffer(), par);
2108 /* now check for the headline layouts. remember that they
2109 * have a dynamic left margin */
2114 ( textclasslist.Style(bview->buffer()->params.textclass,
2115 par->layout).margintype == MARGIN_DYNAMIC
2116 || textclasslist.Style(bview->buffer()->params.textclass,
2117 par->layout).labeltype == LABEL_SENSITIVE)
2120 /* Rebreak the paragraph */
2121 RemoveParagraph(row);
2122 AppendParagraph(bview, row);
2125 /* think about the damned open footnotes! */
2126 while (par->Next() &&
2127 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2128 || par->Next()->IsDummy())){
2130 if (par->IsDummy()) {
2131 while (row->par() != par)
2133 RemoveParagraph(row);
2134 AppendParagraph(bview, row);
2140 par = par->LastPhysicalPar()->Next();
2149 /* insets an inset. */
2150 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2152 if (!cursor.par()->InsertInsetAllowed(inset))
2154 SetUndo(bview->buffer(), Undo::INSERT,
2156 cursor.par()->ParFromPos(cursor.pos())->previous,
2157 cursor.par()->ParFromPos(cursor.pos())->next
2159 cursor.par()->previous,
2163 cursor.par()->InsertInset(cursor.pos(), inset);
2164 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2165 * The character will not be inserted a
2170 void LyXText::copyEnvironmentType()
2172 copylayouttype = cursor.par()->GetLayout();
2176 void LyXText::pasteEnvironmentType(BufferView * bview)
2178 SetLayout(bview, copylayouttype);
2182 void LyXText::CutSelection(BufferView * bview, bool doclear)
2184 // Stuff what we got on the clipboard. Even if there is no selection.
2186 // There is a problem with having the stuffing here in that the
2187 // larger the selection the slower LyX will get. This can be
2188 // solved by running the line below only when the selection has
2189 // finished. The solution used currently just works, to make it
2190 // faster we need to be more clever and probably also have more
2191 // calls to stuffClipboard. (Lgb)
2192 bview->stuffClipboard(selectionAsString(bview->buffer()));
2194 // This doesn't make sense, if there is no selection
2198 // OK, we have a selection. This is always between sel_start_cursor
2199 // and sel_end cursor
2201 // Check whether there are half footnotes in the selection
2202 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2203 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2204 LyXParagraph * tmppar = sel_start_cursor.par();
2205 while (tmppar != sel_end_cursor.par()){
2206 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2207 WriteAlert(_("Impossible operation"),
2208 _("Don't know what to do with half floats."),
2212 tmppar = tmppar->Next();
2217 /* table stuff -- begin */
2218 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2219 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2220 WriteAlert(_("Impossible operation"),
2221 _("Don't know what to do with half tables."),
2225 sel_start_cursor.par()->table->Reinit();
2227 /* table stuff -- end */
2229 // make sure that the depth behind the selection are restored, too
2231 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2233 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2235 LyXParagraph * undoendpar = endpar;
2237 if (endpar && endpar->GetDepth()) {
2238 while (endpar && endpar->GetDepth()) {
2240 endpar = endpar->LastPhysicalPar()->Next();
2242 endpar = endpar->Next();
2244 undoendpar = endpar;
2246 } else if (endpar) {
2247 endpar = endpar->Next(); // because of parindents etc.
2250 SetUndo(bview->buffer(), Undo::DELETE,
2253 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2255 sel_start_cursor.par()->previous,
2261 // there are two cases: cut only within one paragraph or
2262 // more than one paragraph
2264 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2265 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2267 if (sel_start_cursor.par() == sel_end_cursor.par())
2270 // only within one paragraph
2271 endpar = sel_start_cursor.par();
2272 int pos = sel_end_cursor.pos();
2273 cap.cutSelection(sel_start_cursor.par(), &endpar,
2274 sel_start_cursor.pos(), pos,
2275 bview->buffer()->params.textclass, doclear);
2276 sel_end_cursor.pos(pos);
2278 endpar = sel_end_cursor.par();
2280 int pos = sel_end_cursor.pos();
2281 cap.cutSelection(sel_start_cursor.par(), &endpar,
2282 sel_start_cursor.pos(), pos,
2283 bview->buffer()->params.textclass, doclear);
2285 sel_end_cursor.par(endpar);
2286 sel_end_cursor.pos(pos);
2287 cursor.pos(sel_end_cursor.pos());
2289 endpar = endpar->Next();
2291 // sometimes necessary
2293 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2295 RedoParagraphs(bview, sel_start_cursor, endpar);
2298 cursor = sel_start_cursor;
2299 SetCursor(bview, cursor.par(), cursor.pos());
2300 sel_cursor = cursor;
2301 UpdateCounters(bview, cursor.row());
2305 void LyXText::CopySelection(BufferView * bview)
2307 // Stuff what we got on the clipboard. Even if there is no selection.
2309 // There is a problem with having the stuffing here in that the
2310 // larger the selection the slower LyX will get. This can be
2311 // solved by running the line below only when the selection has
2312 // finished. The solution used currently just works, to make it
2313 // faster we need to be more clever and probably also have more
2314 // calls to stuffClipboard. (Lgb)
2315 bview->stuffClipboard(selectionAsString(bview->buffer()));
2317 // this doesnt make sense, if there is no selection
2321 // ok we have a selection. This is always between sel_start_cursor
2322 // and sel_end cursor
2325 /* check wether there are half footnotes in the selection */
2326 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2327 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2328 LyXParagraph * tmppar = sel_start_cursor.par();
2329 while (tmppar != sel_end_cursor.par()) {
2330 if (tmppar->footnoteflag !=
2331 sel_end_cursor.par()->footnoteflag) {
2332 WriteAlert(_("Impossible operation"),
2333 _("Don't know what to do"
2334 " with half floats."),
2338 tmppar = tmppar->Next();
2343 /* table stuff -- begin */
2344 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2345 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2346 WriteAlert(_("Impossible operation"),
2347 _("Don't know what to do with half tables."),
2352 /* table stuff -- end */
2355 // copy behind a space if there is one
2356 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2357 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2358 && (sel_start_cursor.par() != sel_end_cursor.par()
2359 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2360 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2364 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2365 sel_start_cursor.pos(), sel_end_cursor.pos(),
2366 bview->buffer()->params.textclass);
2370 void LyXText::PasteSelection(BufferView * bview)
2374 // this does not make sense, if there is nothing to paste
2375 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2378 SetUndo(bview->buffer(), Undo::INSERT,
2380 cursor.par()->ParFromPos(cursor.pos())->previous,
2381 cursor.par()->ParFromPos(cursor.pos())->next
2383 cursor.par()->previous,
2388 LyXParagraph * endpar;
2389 LyXParagraph * actpar = cursor.par();
2391 int pos = cursor.pos();
2392 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2394 RedoParagraphs(bview, cursor, endpar);
2396 SetCursor(bview, cursor.par(), cursor.pos());
2399 sel_cursor = cursor;
2400 SetCursor(bview, actpar, pos);
2402 UpdateCounters(bview, cursor.row());
2406 // returns a pointer to the very first LyXParagraph
2407 LyXParagraph * LyXText::FirstParagraph() const
2409 return OwnerParagraph();
2413 // returns true if the specified string is at the specified position
2414 bool LyXText::IsStringInText(LyXParagraph * par,
2415 LyXParagraph::size_type pos,
2416 string const & str) const
2419 LyXParagraph::size_type i = 0;
2420 while (pos + i < par->Last() && i < str.length()&&
2421 str[i] == par->GetChar(pos + i)) {
2424 if (str.length() == i)
2431 // sets the selection over the number of characters of string, no check!!
2432 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2434 sel_cursor = cursor;
2435 for (int i = 0; str[i]; ++i)
2441 // simple replacing. The font of the first selected character is used
2442 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2445 SetCursorParUndo(bview->buffer());
2448 if (!selection) { // create a dummy selection
2449 sel_end_cursor = cursor;
2450 sel_start_cursor = cursor;
2453 // Get font setting before we cut
2454 LyXParagraph::size_type pos = sel_end_cursor.pos();
2455 LyXFont const font = sel_start_cursor.par()
2456 ->GetFontSettings(bview->buffer()->params,
2457 sel_start_cursor.pos());
2459 // Insert the new string
2460 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2461 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2465 // Cut the selection
2466 CutSelection(bview);
2472 // if the string can be found: return true and set the cursor to
2474 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2476 LyXParagraph * par = cursor.par();
2477 LyXParagraph::size_type pos = cursor.pos();
2478 while (par && !IsStringInText(par, pos, str)) {
2479 if (pos < par->Last() - 1)
2487 SetCursor(bview, par, pos);
2495 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2497 LyXParagraph * par = cursor.par();
2498 int pos = cursor.pos();
2504 // We skip empty paragraphs (Asger)
2506 par = par->Previous();
2508 pos = par->Last() - 1;
2509 } while (par && pos < 0);
2511 } while (par && !IsStringInText(par, pos, str));
2514 SetCursor(bview, par, pos);
2521 // needed to insert the selection
2522 void LyXText::InsertStringA(BufferView * bview, string const & str)
2524 LyXParagraph * par = cursor.par();
2525 LyXParagraph::size_type pos = cursor.pos();
2526 LyXParagraph::size_type a = 0;
2527 LyXParagraph * endpar = cursor.par()->Next();
2529 SetCursorParUndo(bview->buffer());
2532 textclasslist.Style(bview->buffer()->params.textclass,
2533 cursor.par()->GetLayout()).isEnvironment();
2534 // only to be sure, should not be neccessary
2537 // insert the string, don't insert doublespace
2538 string::size_type i = 0;
2539 while (i < str.length()) {
2540 if (str[i] != '\n') {
2542 && i + 1 < str.length() && str[i + 1] != ' '
2543 && pos && par->GetChar(pos - 1)!= ' ') {
2544 par->InsertChar(pos, ' ', current_font);
2547 } else if (par->table) {
2548 if (str[i] == '\t') {
2549 while((pos < par->size()) &&
2550 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2552 if (pos < par->size())
2554 else // no more fields to fill skip the rest
2556 } else if ((str[i] != 13) &&
2557 ((str[i] & 127) >= ' ')) {
2558 par->InsertChar(pos, str[i],
2563 } else if (str[i] == ' ') {
2564 InsetSpecialChar * new_inset =
2565 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2566 if (par->InsertInsetAllowed(new_inset)) {
2567 par->InsertInset(pos, new_inset,
2573 } else if (str[i] == '\t') {
2574 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2575 InsetSpecialChar * new_inset =
2576 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2577 if (par->InsertInsetAllowed(new_inset)) {
2578 par->InsertInset(pos, new_inset,
2585 } else if (str[i] != 13 &&
2586 // Ignore unprintables
2587 (str[i] & 127) >= ' ') {
2588 par->InsertChar(pos, str[i], current_font);
2594 if ((i + 1) >= str.length()) {
2595 if (pos < par->size())
2599 while((pos < par->size()) &&
2600 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2603 int cell = NumberOfCell(par, pos);
2604 while((pos < par->size()) &&
2605 !(par->table->IsFirstCell(cell))) {
2607 while((pos < par->size()) &&
2608 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2611 cell = NumberOfCell(par, pos);
2613 if (pos >= par->size())
2614 // no more fields to fill skip the rest
2618 if (!par->size()) { // par is empty
2619 InsetSpecialChar * new_inset =
2620 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2621 if (par->InsertInsetAllowed(new_inset)) {
2622 par->InsertInset(pos,
2630 par->BreakParagraph(bview->buffer()->params, pos, flag);
2640 RedoParagraphs(bview, cursor, endpar);
2641 SetCursor(bview, cursor.par(), cursor.pos());
2642 sel_cursor = cursor;
2643 SetCursor(bview, par, pos);
2648 /* turns double-CR to single CR, others where converted into one blank and 13s
2649 * that are ignored .Double spaces are also converted into one. Spaces at
2650 * the beginning of a paragraph are forbidden. tabs are converted into one
2651 * space. then InsertStringA is called */
2652 void LyXText::InsertStringB(BufferView * bview, string const & s)
2656 LyXParagraph * par = cursor.par();
2658 string::size_type i = 1;
2659 while (i < str.length()) {
2666 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2668 if (str[i] == '\n' && i + 1 < str.length()
2673 if (str[i + 1] != '\n') {
2674 if (str[i - 1] != ' ')
2679 while (i + 1 < str.length()
2680 && (str[i + 1] == ' '
2681 || str[i + 1] == '\t'
2682 || str[i + 1] == '\n'
2683 || str[i + 1] == 13)) {
2690 InsertStringA(bview, str);
2694 bool LyXText::GotoNextError(BufferView * bview) const
2696 LyXCursor res = cursor;
2698 if (res.pos() < res.par()->Last() - 1) {
2699 res.pos(res.pos() + 1);
2701 res.par(res.par()->Next());
2705 } while (res.par() &&
2706 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2707 && res.par()->GetInset(res.pos())->AutoDelete()));
2710 SetCursor(bview, res.par(), res.pos());
2717 bool LyXText::GotoNextNote(BufferView * bview) const
2719 LyXCursor res = cursor;
2721 if (res.pos() < res.par()->Last() - 1) {
2722 res.pos(res.pos() + 1);
2724 res.par(res.par()->Next());
2728 } while (res.par() &&
2729 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2730 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2733 SetCursor(bview, res.par(), res.pos());
2740 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2741 LyXParagraph::size_type pos)
2743 LyXCursor tmpcursor;
2746 /* table stuff -- begin*/
2749 CheckParagraphInTable(bview, par, pos);
2753 /* table stuff -- end*/
2756 LyXParagraph::size_type z;
2757 Row * row = GetRow(par, pos, y);
2759 // is there a break one row above
2760 if (row->previous() && row->previous()->par() == row->par()) {
2761 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2762 if ( z >= row->pos()) {
2763 // set the dimensions of the row above
2764 y -= row->previous()->height();
2766 refresh_row = row->previous();
2767 status = LyXText::NEED_MORE_REFRESH;
2769 BreakAgain(bview, row->previous());
2771 // set the cursor again. Otherwise
2772 // dangling pointers are possible
2773 SetCursor(bview, cursor.par(), cursor.pos());
2774 sel_cursor = cursor;
2779 int tmpheight = row->height();
2780 LyXParagraph::size_type tmplast = RowLast(row);
2784 BreakAgain(bview, row);
2785 if (row->height() == tmpheight && RowLast(row) == tmplast)
2786 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2788 status = LyXText::NEED_MORE_REFRESH;
2790 // check the special right address boxes
2791 if (textclasslist.Style(bview->buffer()->params.textclass,
2792 par->GetLayout()).margintype
2793 == MARGIN_RIGHT_ADDRESS_BOX) {
2800 RedoDrawingOfParagraph(bview, tmpcursor);
2806 // set the cursor again. Otherwise dangling pointers are possible
2807 // also set the selection
2811 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2812 sel_cursor = cursor;
2813 SetCursorIntern(bview, sel_start_cursor.par(),
2814 sel_start_cursor.pos());
2815 sel_start_cursor = cursor;
2816 SetCursorIntern(bview, sel_end_cursor.par(),
2817 sel_end_cursor.pos());
2818 sel_end_cursor = cursor;
2819 SetCursorIntern(bview, last_sel_cursor.par(),
2820 last_sel_cursor.pos());
2821 last_sel_cursor = cursor;
2824 SetCursorIntern(bview, cursor.par(), cursor.pos());
2828 // returns false if inset wasn't found
2829 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2831 // first check the current paragraph
2832 int pos = cursor.par()->GetPositionOfInset(inset);
2834 CheckParagraph(bview, cursor.par(), pos);
2838 // check every paragraph
2840 LyXParagraph * par = FirstParagraph();
2843 // make sure the paragraph is open
2844 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2846 pos = par->GetPositionOfInset(inset);
2848 CheckParagraph(bview, par, pos);
2861 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2862 LyXParagraph::size_type pos,
2863 bool setfont, bool boundary) const
2865 LyXCursor old_cursor = cursor;
2866 SetCursorIntern(bview, par, pos, setfont, boundary);
2867 DeleteEmptyParagraphMechanism(bview, old_cursor);
2871 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2872 LyXParagraph::size_type pos, bool boundary) const
2875 // correct the cursor position if impossible
2876 if (pos > par->Last()){
2877 LyXParagraph * tmppar = par->ParFromPos(pos);
2878 pos = par->PositionInParFromPos(pos);
2881 if (par->IsDummy() && par->previous &&
2882 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2883 while (par->previous &&
2884 ((par->previous->IsDummy() &&
2885 (par->previous->previous->footnoteflag ==
2886 LyXParagraph::CLOSED_FOOTNOTE)) ||
2887 (par->previous->footnoteflag ==
2888 LyXParagraph::CLOSED_FOOTNOTE))) {
2889 par = par->previous ;
2890 if (par->IsDummy() &&
2891 (par->previous->footnoteflag ==
2892 LyXParagraph::CLOSED_FOOTNOTE))
2893 pos += par->size() + 1;
2895 if (par->previous) {
2896 par = par->previous;
2898 pos += par->size() + 1;
2903 cur.boundary(boundary);
2905 /* get the cursor y position in text */
2907 Row * row = GetRow(par, pos, y);
2908 /* y is now the beginning of the cursor row */
2909 y += row->baseline();
2910 /* y is now the cursor baseline */
2913 /* now get the cursors x position */
2915 float fill_separator, fill_hfill, fill_label_hfill;
2916 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2918 LyXParagraph::size_type cursor_vpos = 0;
2919 LyXParagraph::size_type last = RowLastPrintable(row);
2921 if (pos > last + 1) // This shouldn't happen.
2923 else if (pos < row->pos())
2926 if (last < row->pos())
2927 cursor_vpos = row->pos();
2928 else if (pos > last && !boundary)
2929 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2930 ? row->pos() : last + 1;
2931 else if (pos > row->pos() &&
2932 (pos > last || boundary
2934 || (row->par()->table && row->par()->IsNewline(pos))
2937 /// Place cursor after char at (logical) position pos - 1
2938 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2939 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2941 /// Place cursor before char at (logical) position pos
2942 cursor_vpos = (bidi_level(pos) % 2 == 0)
2943 ? log2vis(pos) : log2vis(pos) + 1;
2946 /* table stuff -- begin*/
2947 if (row->par()->table) {
2948 int cell = NumberOfCell(row->par(), row->pos());
2950 x += row->par()->table->GetBeginningOfTextInCell(cell);
2951 for (LyXParagraph::size_type vpos = row->pos();
2952 vpos < cursor_vpos; ++vpos) {
2953 pos = vis2log(vpos);
2954 if (row->par()->IsNewline(pos)) {
2955 x = x_old + row->par()->table->WidthOfColumn(cell);
2958 x += row->par()->table->GetBeginningOfTextInCell(cell);
2960 x += SingleWidth(bview, row->par(), pos);
2964 /* table stuff -- end*/
2966 LyXParagraph::size_type main_body =
2967 BeginningOfMainBody(bview->buffer(), row->par());
2968 if ((main_body > 0) &&
2969 ((main_body-1 > last) ||
2970 !row->par()->IsLineSeparator(main_body-1)))
2973 for (LyXParagraph::size_type vpos = row->pos();
2974 vpos < cursor_vpos; ++vpos) {
2975 pos = vis2log(vpos);
2976 if (main_body > 0 && pos == main_body-1) {
2977 x += fill_label_hfill +
2978 lyxfont::width(textclasslist.Style(
2979 bview->buffer()->params.textclass,
2980 row->par()->GetLayout())
2982 GetFont(bview->buffer(), row->par(), -2));
2983 if (row->par()->IsLineSeparator(main_body-1))
2984 x -= SingleWidth(bview, row->par(),main_body-1);
2986 if (HfillExpansion(bview->buffer(), row, pos)) {
2987 x += SingleWidth(bview, row->par(), pos);
2988 if (pos >= main_body)
2991 x += fill_label_hfill;
2992 } else if (row->par()->IsSeparator(pos)) {
2993 x += SingleWidth(bview, row->par(), pos);
2994 if (pos >= main_body)
2995 x += fill_separator;
2997 x += SingleWidth(bview, row->par(), pos);
3009 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3010 LyXParagraph::size_type pos,
3011 bool setfont, bool boundary) const
3013 SetCursor(bview, cursor, par, pos, boundary);
3015 SetCurrentFont(bview);
3018 void LyXText::SetCurrentFont(BufferView * bview) const
3020 LyXParagraph::size_type pos = cursor.pos();
3021 if (cursor.boundary() && pos > 0)
3025 if (pos == cursor.par()->Last()
3027 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3031 else if (cursor.par()->IsSeparator(pos)) {
3032 if (pos > cursor.row()->pos() &&
3033 bidi_level(pos) % 2 ==
3034 bidi_level(pos - 1) % 2)
3036 else if (pos + 1 < cursor.par()->Last())
3042 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3043 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3045 if (cursor.pos() == cursor.par()->Last() &&
3046 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3047 !cursor.boundary()) {
3048 Language const * lang =
3049 cursor.par()->getParLanguage(bview->buffer()->params);
3050 current_font.setLanguage(lang);
3051 real_current_font.setLanguage(lang);
3056 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3058 LyXCursor old_cursor = cursor;
3060 /* get the row first */
3062 Row * row = GetRowNearY(y);
3063 cursor.par(row->par());
3066 int column = GetColumnNearX(bview, row, x, bound);
3067 cursor.pos(row->pos() + column);
3069 cursor.y(y + row->baseline());
3071 cursor.boundary(bound);
3072 SetCurrentFont(bview);
3073 DeleteEmptyParagraphMechanism(bview, old_cursor);
3077 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3078 int x, long y) const
3080 /* get the row first */
3082 Row * row = GetRowNearY(y);
3084 int column = GetColumnNearX(bview, row, x, bound);
3086 cur.par(row->par());
3087 cur.pos(row->pos() + column);
3089 cur.y(y + row->baseline());
3091 cur.boundary(bound);
3095 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3097 CursorLeftIntern(bview, internal);
3099 if (cursor.par()->table) {
3100 int cell = NumberOfCell(cursor.par(), cursor.pos());
3101 if (cursor.par()->table->IsContRow(cell)
3102 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3110 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3112 if (cursor.pos() > 0) {
3113 bool boundary = cursor.boundary();
3114 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3115 if (!internal && !boundary &&
3116 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3117 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3118 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3119 LyXParagraph * par = cursor.par()->Previous();
3120 SetCursor(bview, par, par->Last());
3125 void LyXText::CursorRight(BufferView * bview, bool internal) const
3127 CursorRightIntern(bview, internal);
3129 if (cursor.par()->table) {
3130 int cell = NumberOfCell(cursor.par(), cursor.pos());
3131 if (cursor.par()->table->IsContRow(cell) &&
3132 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3140 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3142 if (!internal && cursor.boundary() &&
3145 !cursor.par()->table ||
3147 !cursor.par()->IsNewline(cursor.pos())))
3148 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3149 else if (cursor.pos() < cursor.par()->Last()) {
3150 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3152 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3153 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3154 } else if (cursor.par()->Next())
3155 SetCursor(bview, cursor.par()->Next(), 0);
3159 void LyXText::CursorUp(BufferView * bview) const
3161 SetCursorFromCoordinates(bview, cursor.x_fix(),
3162 cursor.y() - cursor.row()->baseline() - 1);
3164 if (cursor.par()->table) {
3165 int cell = NumberOfCell(cursor.par(), cursor.pos());
3166 if (cursor.par()->table->IsContRow(cell) &&
3167 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3175 void LyXText::CursorDown(BufferView * bview) const
3178 if (cursor.par()->table &&
3179 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3180 !cursor.par()->next)
3184 SetCursorFromCoordinates(bview, cursor.x_fix(),
3185 cursor.y() - cursor.row()->baseline()
3186 + cursor.row()->height() + 1);
3188 if (cursor.par()->table) {
3189 int cell = NumberOfCell(cursor.par(), cursor.pos());
3190 int cell_above = cursor.par()->table->GetCellAbove(cell);
3191 while(cursor.par()->table &&
3192 cursor.par()->table->IsContRow(cell) &&
3193 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3194 SetCursorFromCoordinates(bview, cursor.x_fix(),
3195 cursor.y() - cursor.row()->baseline()
3196 + cursor.row()->height() + 1);
3197 if (cursor.par()->table) {
3198 cell = NumberOfCell(cursor.par(), cursor.pos());
3199 cell_above = cursor.par()->table->GetCellAbove(cell);
3207 void LyXText::CursorUpParagraph(BufferView * bview) const
3209 if (cursor.pos() > 0) {
3210 SetCursor(bview, cursor.par(), 0);
3212 else if (cursor.par()->Previous()) {
3213 SetCursor(bview, cursor.par()->Previous(), 0);
3218 void LyXText::CursorDownParagraph(BufferView * bview) const
3220 if (cursor.par()->Next()) {
3221 SetCursor(bview, cursor.par()->Next(), 0);
3223 SetCursor(bview, cursor.par(), cursor.par()->Last());
3228 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3229 LyXCursor const & old_cursor) const
3231 // Would be wrong to delete anything if we have a selection.
3232 if (selection) return;
3234 // We allow all kinds of "mumbo-jumbo" when freespacing.
3235 if (textclasslist.Style(bview->buffer()->params.textclass,
3236 old_cursor.par()->GetLayout()).free_spacing)
3239 bool deleted = false;
3241 /* Ok I'll put some comments here about what is missing.
3242 I have fixed BackSpace (and thus Delete) to not delete
3243 double-spaces automagically. I have also changed Cut,
3244 Copy and Paste to hopefully do some sensible things.
3245 There are still some small problems that can lead to
3246 double spaces stored in the document file or space at
3247 the beginning of paragraphs. This happens if you have
3248 the cursor betwenn to spaces and then save. Or if you
3249 cut and paste and the selection have a space at the
3250 beginning and then save right after the paste. I am
3251 sure none of these are very hard to fix, but I will
3252 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3253 that I can get some feedback. (Lgb)
3256 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3257 // delete the LineSeparator.
3260 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3261 // delete the LineSeparator.
3264 // If the pos around the old_cursor were spaces, delete one of them.
3265 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3266 // Only if the cursor has really moved
3268 if (old_cursor.pos() > 0
3269 && old_cursor.pos() < old_cursor.par()->Last()
3270 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3271 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3272 old_cursor.par()->Erase(old_cursor.pos() - 1);
3273 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3275 if (old_cursor.par() == cursor.par() &&
3276 cursor.pos() > old_cursor.pos()) {
3277 SetCursorIntern(bview, cursor.par(),
3280 SetCursorIntern(bview, cursor.par(),
3286 // Do not delete empty paragraphs with keepempty set.
3287 if ((textclasslist.Style(bview->buffer()->params.textclass,
3288 old_cursor.par()->GetLayout())).keepempty)
3291 LyXCursor tmpcursor;
3293 if (old_cursor.par() != cursor.par()) {
3294 if ( (old_cursor.par()->Last() == 0
3295 || (old_cursor.par()->Last() == 1
3296 && old_cursor.par()->IsLineSeparator(0)))
3298 && old_cursor.par()->FirstPhysicalPar()
3299 == old_cursor.par()->LastPhysicalPar()
3302 // ok, we will delete anything
3304 // make sure that you do not delete any environments
3307 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3308 !(old_cursor.row()->previous()
3309 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3310 && !(old_cursor.row()->next()
3311 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3312 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3313 && ((old_cursor.row()->previous()
3314 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3315 || (old_cursor.row()->next()
3316 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3319 status = LyXText::NEED_MORE_REFRESH;
3322 if (old_cursor.row()->previous()) {
3323 refresh_row = old_cursor.row()->previous();
3324 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3326 cursor = old_cursor; // that undo can restore the right cursor position
3327 LyXParagraph * endpar = old_cursor.par()->next;
3328 if (endpar && endpar->GetDepth()) {
3329 while (endpar && endpar->GetDepth()) {
3331 endpar = endpar->LastPhysicalPar()->Next();
3333 endpar = endpar->Next();
3337 SetUndo(bview->buffer(), Undo::DELETE,
3338 old_cursor.par()->previous,
3343 RemoveRow(old_cursor.row());
3344 if (OwnerParagraph() == old_cursor.par()) {
3345 OwnerParagraph(OwnerParagraph()->next);
3348 delete old_cursor.par();
3350 /* Breakagain the next par. Needed
3351 * because of the parindent that
3352 * can occur or dissappear. The
3353 * next row can change its height,
3354 * if there is another layout before */
3355 if (refresh_row->next()) {
3356 BreakAgain(bview, refresh_row->next());
3357 UpdateCounters(bview, refresh_row);
3359 SetHeightOfRow(bview, refresh_row);
3361 refresh_row = old_cursor.row()->next();
3362 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3365 cursor = old_cursor; // that undo can restore the right cursor position
3366 LyXParagraph * endpar = old_cursor.par()->next;
3367 if (endpar && endpar->GetDepth()) {
3368 while (endpar && endpar->GetDepth()) {
3370 endpar = endpar->LastPhysicalPar()->Next();
3372 endpar = endpar->Next();
3376 SetUndo(bview->buffer(), Undo::DELETE,
3377 old_cursor.par()->previous,
3382 RemoveRow(old_cursor.row());
3384 if (OwnerParagraph() == old_cursor.par()) {
3385 OwnerParagraph(OwnerParagraph()->next);
3387 delete old_cursor.par();
3389 /* Breakagain the next par. Needed
3390 because of the parindent that can
3391 occur or dissappear.
3392 The next row can change its height,
3393 if there is another layout before
3396 BreakAgain(bview, refresh_row);
3397 UpdateCounters(bview, refresh_row->previous());
3403 SetCursorIntern(bview, cursor.par(), cursor.pos());
3405 if (sel_cursor.par() == old_cursor.par()
3406 && sel_cursor.pos() == sel_cursor.pos()) {
3407 // correct selection
3408 sel_cursor = cursor;
3415 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3416 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3418 SetCursorIntern(bview, cursor.par(), cursor.pos());
3419 sel_cursor = cursor;
3426 LyXParagraph * LyXText::GetParFromID(int id)
3428 LyXParagraph * result = FirstParagraph();
3429 while (result && result->id() != id)
3430 result = result->next;
3436 bool LyXText::TextUndo(BufferView * bview)
3440 // returns false if no undo possible
3441 Undo * undo = bview->buffer()->undostack.pop();
3445 bview->buffer()->redostack
3446 .push(CreateUndo(bview->buffer(), undo->kind,
3447 GetParFromID(undo->number_of_before_par),
3448 GetParFromID(undo->number_of_behind_par)));
3450 return TextHandleUndo(bview, undo);
3454 bool LyXText::TextRedo(BufferView * bview)
3458 // returns false if no redo possible
3459 Undo * undo = bview->buffer()->redostack.pop();
3463 bview->buffer()->undostack
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::TextHandleUndo(BufferView * bview, Undo * undo)
3476 // returns false if no undo possible
3477 bool result = false;
3479 LyXParagraph * before =
3480 GetParFromID(undo->number_of_before_par);
3481 LyXParagraph * behind =
3482 GetParFromID(undo->number_of_behind_par);
3483 LyXParagraph * tmppar;
3484 LyXParagraph * tmppar2;
3485 LyXParagraph * endpar;
3486 LyXParagraph * tmppar5;
3488 // if there's no before take the beginning
3489 // of the document for redoing
3491 SetCursorIntern(bview, FirstParagraph(), 0);
3493 // replace the paragraphs with the undo informations
3495 LyXParagraph * tmppar3 = undo->par;
3496 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3497 LyXParagraph * tmppar4 = tmppar3;
3499 while (tmppar4->next)
3500 tmppar4 = tmppar4->next;
3501 } // get last undo par
3503 // now remove the old text if there is any
3504 if (before != behind || (!behind && !before)){
3506 tmppar5 = before->next;
3508 tmppar5 = OwnerParagraph();
3510 while (tmppar5 && tmppar5 != behind){
3512 tmppar5 = tmppar5->next;
3513 // a memory optimization for edit: Only layout information
3514 // is stored in the undo. So restore the text informations.
3515 if (undo->kind == Undo::EDIT) {
3516 tmppar2->setContentsFromPar(tmppar);
3517 tmppar->clearContents();
3518 tmppar2 = tmppar2->next;
3523 // put the new stuff in the list if there is one
3526 before->next = tmppar3;
3528 OwnerParagraph(tmppar3);
3529 tmppar3->previous = before;
3532 OwnerParagraph(behind);
3535 tmppar4->next = behind;
3537 behind->previous = tmppar4;
3541 // Set the cursor for redoing
3544 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3546 SetCursorIntern(bview, before, 0);
3549 // check wether before points to a closed float and open it if necessary
3550 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3551 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3553 while (tmppar4->previous &&
3554 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3555 tmppar4 = tmppar4->previous;
3556 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3557 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3558 tmppar4 = tmppar4->next;
3565 // open a cosed footnote at the end if necessary
3566 if (behind && behind->previous &&
3567 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3568 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3569 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3570 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3571 behind = behind->next;
3576 // calculate the endpar for redoing the paragraphs.
3579 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3580 endpar = behind->LastPhysicalPar()->Next();
3582 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3584 endpar = behind->Next();
3589 tmppar = GetParFromID(undo->number_of_cursor_par);
3590 RedoParagraphs(bview, cursor, endpar);
3592 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3593 UpdateCounters(bview, cursor.row());
3603 void LyXText::FinishUndo()
3607 // makes sure the next operation will be stored
3608 undo_finished = true;
3612 void LyXText::FreezeUndo()
3616 // this is dangerous and for internal use only
3621 void LyXText::UnFreezeUndo()
3625 // this is dangerous and for internal use only
3626 undo_frozen = false;
3630 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3631 LyXParagraph const * before,
3632 LyXParagraph const * behind) const
3637 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3638 buf->redostack.clear();
3642 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3643 LyXParagraph const * before, LyXParagraph const * behind)
3647 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3651 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3652 LyXParagraph const * before,
3653 LyXParagraph const * behind) const
3658 int before_number = -1;
3659 int behind_number = -1;
3661 before_number = before->id();
3663 behind_number = behind->id();
3664 // Undo::EDIT and Undo::FINISH are
3665 // always finished. (no overlapping there)
3666 // overlapping only with insert and delete inside one paragraph:
3667 // Nobody wants all removed character
3668 // appear one by one when undoing.
3669 // EDIT is special since only layout information, not the
3670 // contents of a paragaph are stored.
3671 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3672 // check wether storing is needed
3673 if (!buf->undostack.empty() &&
3674 buf->undostack.top()->kind == kind &&
3675 buf->undostack.top()->number_of_before_par == before_number &&
3676 buf->undostack.top()->number_of_behind_par == behind_number ){
3681 // create a new Undo
3682 LyXParagraph * undopar;
3683 LyXParagraph * tmppar;
3684 LyXParagraph * tmppar2;
3686 LyXParagraph * start = 0;
3687 LyXParagraph * end = 0;
3690 start = before->next;
3692 start = FirstParagraph();
3694 end = behind->previous;
3696 end = FirstParagraph();
3702 && start != end->next
3703 && (before != behind || (!before && !behind))) {
3705 tmppar2 = tmppar->Clone();
3706 tmppar2->id(tmppar->id());
3708 // a memory optimization: Just store the layout information
3710 if (kind == Undo::EDIT){
3711 //tmppar2->text.clear();
3712 tmppar2->clearContents();
3717 while (tmppar != end && tmppar->next) {
3718 tmppar = tmppar->next;
3719 tmppar2->next = tmppar->Clone();
3720 tmppar2->next->id(tmppar->id());
3721 // a memory optimization: Just store the layout
3722 // information when only edit
3723 if (kind == Undo::EDIT){
3724 //tmppar2->next->text.clear();
3725 tmppar2->clearContents();
3727 tmppar2->next->previous = tmppar2;
3728 tmppar2 = tmppar2->next;
3732 undopar = 0; // nothing to replace (undo of delete maybe)
3735 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3736 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3738 int cursor_par = cursor.par()->id();
3739 int cursor_pos = cursor.pos();
3742 Undo * undo = new Undo(kind,
3743 before_number, behind_number,
3744 cursor_par, cursor_pos,
3747 undo_finished = false;
3752 void LyXText::SetCursorParUndo(Buffer * buf)
3756 SetUndo(buf, Undo::FINISH,
3758 cursor.par()->ParFromPos(cursor.pos())->previous,
3759 cursor.par()->ParFromPos(cursor.pos())->next
3761 cursor.par()->previous,
3769 void LyXText::RemoveTableRow(LyXCursor & cur) const
3775 // move to the previous row
3776 int cell_act = NumberOfCell(cur.par(), cur.pos());
3779 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3780 cur.pos(cur.pos() - 1);
3782 !cur.par()->table->IsFirstCell(cell_act)) {
3783 cur.pos(cur.pos() - 1);
3784 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3785 cur.pos(cur.pos() - 1);
3789 // now we have to pay attention if the actual table is the
3790 // main row of TableContRows and if yes to delete all of them
3795 // delete up to the next row
3796 while (cur.pos() < cur.par()->Last() &&
3798 || !cur.par()->table->IsFirstCell(cell_act))) {
3799 while (cur.pos() < cur.par()->Last() &&
3800 !cur.par()->IsNewline(cur.pos()))
3801 cur.par()->Erase(cur.pos());
3804 if (cur.pos() < cur.par()->Last())
3805 cur.par()->Erase(cur.pos());
3807 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3808 cur.pos(cur.pos() - 1);
3809 cur.par()->Erase(cur.pos()); // no newline at very end!
3811 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3812 !cur.par()->table->IsContRow(cell_org) &&
3813 cur.par()->table->IsContRow(cell));
3814 cur.par()->table->DeleteRow(cell_org);
3821 bool LyXText::IsEmptyTableCell() const
3823 LyXParagraph::size_type pos = cursor.pos() - 1;
3824 while (pos >= 0 && pos < cursor.par()->Last()
3825 && !cursor.par()->IsNewline(pos))
3827 return cursor.par()->IsNewline(pos + 1);
3832 void LyXText::toggleAppendix(BufferView * bview)
3835 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3837 LyXParagraph * par = cursor.par();
3839 bool start = !par->start_of_appendix;
3841 // ensure that we have only one start_of_appendix in this document
3842 LyXParagraph * tmp = FirstParagraph();
3843 for (; tmp; tmp = tmp->next)
3844 tmp->start_of_appendix = 0;
3845 par->start_of_appendix = start;
3847 // we can set the refreshing parameters now
3848 status = LyXText::NEED_MORE_REFRESH;
3850 refresh_row = 0; // not needed for full update
3851 UpdateCounters(bview, 0);
3852 SetCursor(bview, cursor.par(), cursor.pos());
3856 LyXParagraph * LyXText::OwnerParagraph() const
3859 return inset_owner->par;
3861 return bv_owner->buffer()->paragraph;
3865 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3868 inset_owner->par = p;
3870 bv_owner->buffer()->paragraph = p;