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"
28 #include "support/textutils.h"
30 #include "minibuffer.h"
32 #include "bufferparams.h"
33 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
39 #include "CutAndPaste.h"
44 //#define USE_OLD_CUT_AND_PASTE 1
50 LyXText::LyXText(BufferView * bv)
58 LyXText::LyXText(InsetText * inset)
75 status = LyXText::UNCHANGED;
76 // set cursor at the very top position
77 selection = true; /* these setting is necessary
78 because of the delete-empty-
79 paragraph mechanism in
82 LyXParagraph * par = OwnerParagraph();
83 current_font = GetFont(bv_owner->buffer(), par, 0);
85 InsertParagraph(bv_owner, par, lastrow);
88 SetCursor(bv_owner, firstrow->par(), 0);
90 current_font = LyXFont(LyXFont::ALL_SANE);
96 // no rebreak necessary
102 // Default layouttype for copy environment type
106 // Dump all rowinformation:
107 Row * tmprow = firstrow;
108 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
110 lyxerr << tmprow->baseline() << '\t'
111 << tmprow->par << '\t'
112 << tmprow->pos() << '\t'
113 << tmprow->height << '\t'
114 << tmprow->ascent_of_text << '\t'
115 << tmprow->fill << '\n';
116 tmprow = tmprow->next();
123 void LyXText::init(BufferView * bview)
128 LyXParagraph * par = OwnerParagraph();
129 current_font = GetFont(bview->buffer(), par, 0);
131 InsertParagraph(bview, par, lastrow);
134 SetCursorIntern(bview, firstrow->par(), 0);
137 // Dump all rowinformation:
138 Row * tmprow = firstrow;
139 lyxerr << "Width = " << width << endl;
140 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
142 lyxerr << tmprow->baseline() << '\t'
143 << tmprow->par() << '\t'
144 << tmprow->pos() << '\t'
145 << tmprow->height() << '\t'
146 << tmprow->ascent_of_text() << '\t'
147 << tmprow->fill() << '\n';
148 tmprow = tmprow->next();
156 // Delete all rows, this does not touch the paragraphs!
157 Row * tmprow = firstrow;
159 tmprow = firstrow->next();
166 // Gets the fully instantiated font at a given position in a paragraph
167 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
168 // The difference is that this one is used for displaying, and thus we
169 // are allowed to make cosmetic improvements. For instance make footnotes
171 // If position is -1, we get the layout font of the paragraph.
172 // If position is -2, we get the font of the manual label of the paragraph.
173 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
174 LyXParagraph::size_type pos) const
176 LyXLayout const & layout =
177 textclasslist.Style(buf->params.textclass, par->GetLayout());
179 char par_depth = par->GetDepth();
180 // We specialize the 95% common case:
181 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
184 if (layout.labeltype == LABEL_MANUAL
185 && pos < BeginningOfMainBody(buf, par)) {
187 return par->GetFontSettings(buf->params, pos).
188 realize(layout.reslabelfont);
190 return par->GetFontSettings(buf->params, pos).
191 realize(layout.resfont);
194 // process layoutfont for pos == -1 and labelfont for pos < -1
196 return layout.resfont;
198 return layout.reslabelfont;
202 // The uncommon case need not be optimized as much
204 LyXFont layoutfont, tmpfont;
208 if (pos < BeginningOfMainBody(buf, par)) {
210 layoutfont = layout.labelfont;
213 layoutfont = layout.font;
215 tmpfont = par->GetFontSettings(buf->params, pos);
216 tmpfont.realize(layoutfont);
219 // process layoutfont for pos == -1 and labelfont for pos < -1
221 tmpfont = layout.font;
223 tmpfont = layout.labelfont;
226 // Resolve against environment font information
227 while (par && par_depth && !tmpfont.resolved()) {
228 par = par->DepthHook(par_depth - 1);
230 tmpfont.realize(textclasslist.
231 Style(buf->params.textclass,
232 par->GetLayout()).font);
233 par_depth = par->GetDepth();
237 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
240 // Cosmetic improvement: If this is an open footnote, make the font
242 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
243 && par->footnotekind == LyXParagraph::FOOTNOTE) {
251 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
252 LyXParagraph::size_type pos,
256 // Let the insets convert their font
257 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
258 if (par->GetInset(pos))
259 font = par->GetInset(pos)->ConvertFont(font);
262 LyXLayout const & layout =
263 textclasslist.Style(buf->params.textclass,
266 // Get concrete layout font to reduce against
269 if (pos < BeginningOfMainBody(buf, par))
270 layoutfont = layout.labelfont;
272 layoutfont = layout.font;
274 // Realize against environment font information
275 if (par->GetDepth()){
276 LyXParagraph * tp = par;
277 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
278 tp = tp->DepthHook(tp->GetDepth()-1);
280 layoutfont.realize(textclasslist.
281 Style(buf->params.textclass,
282 tp->GetLayout()).font);
286 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
289 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
290 && par->footnotekind == LyXParagraph::FOOTNOTE) {
291 layoutfont.decSize();
294 // Now, reduce font against full layout font
295 font.reduce(layoutfont);
297 par->SetFont(pos, font);
301 /* inserts a new row behind the specified row, increments
302 * the touched counters */
303 void LyXText::InsertRow(Row * row, LyXParagraph * par,
304 LyXParagraph::size_type pos) const
306 Row * tmprow = new Row;
309 tmprow->next(firstrow);
312 tmprow->previous(row);
313 tmprow->next(row->next());
318 tmprow->next()->previous(tmprow);
320 if (tmprow->previous())
321 tmprow->previous()->next(tmprow);
329 ++number_of_rows; // one more row
333 // removes the row and reset the touched counters
334 void LyXText::RemoveRow(Row * row) const
336 /* this must not happen before the currentrow for clear reasons.
337 so the trick is just to set the current row onto the previous
340 GetRow(row->par(), row->pos(), unused_y);
343 row->next()->previous(row->previous());
344 if (!row->previous()) {
345 firstrow = row->next();
347 row->previous()->next(row->next());
350 lastrow = row->previous();
352 height -= row->height(); // the text becomes smaller
355 --number_of_rows; // one row less
359 // remove all following rows of the paragraph of the specified row.
360 void LyXText::RemoveParagraph(Row * row) const
362 LyXParagraph * tmppar = row->par();
366 while (row && row->par() == tmppar) {
367 tmprow = row->next();
374 // insert the specified paragraph behind the specified row
375 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
378 InsertRow(row, par, 0); /* insert a new row, starting
381 SetCounter(bview->buffer(), par); // set the counters
383 // and now append the whole paragraph behind the new row
386 AppendParagraph(bview, firstrow);
388 row->next()->height(0);
389 AppendParagraph(bview, row->next());
395 void LyXText::ToggleFootnote(BufferView * bview)
397 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
399 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
401 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
403 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
404 CloseFootnote(bview);
410 void LyXText::OpenStuff(BufferView * bview)
412 if (cursor.pos() == 0 && cursor.par()->bibkey){
413 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
415 else if (cursor.pos() < cursor.par()->Last()
416 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
417 && cursor.par()->GetInset(cursor.pos())->Editable()) {
418 bview->owner()->getMiniBuffer()
419 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
420 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
421 SetCursorParUndo(bview->buffer());
422 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
424 ToggleFootnote(bview);
430 void LyXText::CloseFootnote(BufferView * bview)
432 LyXParagraph * tmppar;
433 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
435 // if the cursor is not in an open footnote, or
436 // there is no open footnote in this paragraph, just return.
437 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
440 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
441 bview->owner()->getMiniBuffer()
442 ->Set(_("Nothing to do"));
446 // ok, move the cursor right before the footnote
447 // just a little faster than using CursorRight()
449 cursor.par()->ParFromPos(cursor.pos()) != par;) {
450 cursor.pos(cursor.pos() + 1);
453 // now the cursor is at the beginning of the physical par
454 SetCursor(bview, cursor.par(),
456 cursor.par()->ParFromPos(cursor.pos())->size());
458 /* we are in a footnote, so let us move at the beginning */
459 /* this is just faster than using just CursorLeft() */
461 tmppar = cursor.par();
462 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
463 // just a little bit faster than movin the cursor
464 tmppar = tmppar->Previous();
466 SetCursor(bview, tmppar, tmppar->Last());
469 // the cursor must be exactly before the footnote
470 par = cursor.par()->ParFromPos(cursor.pos());
472 status = LyXText::NEED_MORE_REFRESH;
473 refresh_row = cursor.row();
474 refresh_y = cursor.y() - cursor.row()->baseline();
476 tmppar = cursor.par();
477 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
478 Row * row = cursor.row();
480 tmppar->CloseFootnote(cursor.pos());
482 while (tmppar != endpar) {
483 RemoveRow(row->next());
485 tmppar = row->next()->par();
490 AppendParagraph(bview, cursor.row());
492 SetCursor(bview, cursor.par(), cursor.pos());
496 if (cursor.row()->next())
497 SetHeightOfRow(bview, cursor.row()->next());
502 /* used in setlayout */
503 // Asger is not sure we want to do this...
504 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
508 LyXLayout const & layout =
509 textclasslist.Style(buf->params.textclass, par->GetLayout());
511 LyXFont layoutfont, tmpfont;
512 for (LyXParagraph::size_type pos = 0;
513 pos < par->Last(); ++pos) {
514 if (pos < BeginningOfMainBody(buf, par))
515 layoutfont = layout.labelfont;
517 layoutfont = layout.font;
519 tmpfont = par->GetFontSettings(buf->params, pos);
520 tmpfont.reduce(layoutfont);
521 par->SetFont(pos, tmpfont);
526 LyXParagraph * LyXText::SetLayout(BufferView * bview,
527 LyXCursor & cur, LyXCursor & sstart_cur,
528 LyXCursor & send_cur,
529 LyXTextClass::size_type layout)
531 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
532 LyXParagraph * undoendpar = endpar;
534 if (endpar && endpar->GetDepth()) {
535 while (endpar && endpar->GetDepth()) {
536 endpar = endpar->LastPhysicalPar()->Next();
540 endpar = endpar->Next(); // because of parindents etc.
543 SetUndo(bview->buffer(), Undo::EDIT,
544 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
547 /* ok we have a selection. This is always between sstart_cur
548 * and sel_end cursor */
551 LyXLayout const & lyxlayout =
552 textclasslist.Style(bview->buffer()->params.textclass, layout);
554 while (cur.par() != send_cur.par()) {
555 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
556 cur.par()->SetLayout(bview->buffer()->params, layout);
557 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
558 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
559 fppar->added_space_top = lyxlayout.fill_top ?
560 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
561 fppar->added_space_bottom = lyxlayout.fill_bottom ?
562 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
563 if (lyxlayout.margintype == MARGIN_MANUAL)
564 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
565 if (lyxlayout.labeltype != LABEL_BIBLIO
567 delete fppar->bibkey;
571 cur.par(cur.par()->Next());
573 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
574 cur.par()->SetLayout(bview->buffer()->params, layout);
575 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
576 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
577 fppar->added_space_top = lyxlayout.fill_top ?
578 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
579 fppar->added_space_bottom = lyxlayout.fill_bottom ?
580 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
581 if (lyxlayout.margintype == MARGIN_MANUAL)
582 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
583 if (lyxlayout.labeltype != LABEL_BIBLIO
585 delete fppar->bibkey;
592 // set layout over selection and make a total rebreak of those paragraphs
593 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
596 tmpcursor = cursor; /* store the current cursor */
598 #ifdef USE_OLD_SET_LAYOUT
599 // if there is no selection just set the layout
600 // of the current paragraph */
602 sel_start_cursor = cursor; // dummy selection
603 sel_end_cursor = cursor;
606 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
607 LyXParagraph * undoendpar = endpar;
609 if (endpar && endpar->GetDepth()) {
610 while (endpar && endpar->GetDepth()) {
611 endpar = endpar->LastPhysicalPar()->Next();
616 endpar = endpar->Next(); // because of parindents etc.
620 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
623 /* ok we have a selection. This is always between sel_start_cursor
624 * and sel_end cursor */
625 cursor = sel_start_cursor;
627 LyXLayout const & lyxlayout =
628 textclasslist.Style(bview->buffer()->params.textclass, layout);
630 while (cursor.par() != sel_end_cursor.par()) {
631 if (cursor.par()->footnoteflag ==
632 sel_start_cursor.par()->footnoteflag) {
633 cursor.par()->SetLayout(layout);
634 MakeFontEntriesLayoutSpecific(cursor.par());
635 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
636 fppar->added_space_top = lyxlayout.fill_top ?
637 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
638 fppar->added_space_bottom = lyxlayout.fill_bottom ?
639 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
640 if (lyxlayout.margintype == MARGIN_MANUAL)
641 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
642 if (lyxlayout.labeltype != LABEL_BIBLIO
644 delete fppar->bibkey;
648 cursor.par() = cursor.par()->Next();
650 if (cursor.par()->footnoteflag ==
651 sel_start_cursor.par()->footnoteflag) {
652 cursor.par()->SetLayout(layout);
653 MakeFontEntriesLayoutSpecific(cursor.par());
654 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
655 fppar->added_space_top = lyxlayout.fill_top ?
656 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
657 fppar->added_space_bottom = lyxlayout.fill_bottom ?
658 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
659 if (lyxlayout.margintype == MARGIN_MANUAL)
660 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
661 if (lyxlayout.labeltype != LABEL_BIBLIO
663 delete fppar->bibkey;
668 // if there is no selection just set the layout
669 // of the current paragraph */
671 sel_start_cursor = cursor; // dummy selection
672 sel_end_cursor = cursor;
675 endpar = SetLayout(bview, cursor, sel_start_cursor,
676 sel_end_cursor, layout);
678 RedoParagraphs(bview, sel_start_cursor, endpar);
680 // we have to reset the selection, because the
681 // geometry could have changed */
682 SetCursor(bview, sel_start_cursor.par(),
683 sel_start_cursor.pos(), false);
685 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
687 UpdateCounters(bview, cursor.row());
690 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
694 // increment depth over selection and
695 // make a total rebreak of those paragraphs
696 void LyXText::IncDepth(BufferView * bview)
698 // If there is no selection, just use the current paragraph
700 sel_start_cursor = cursor; // dummy selection
701 sel_end_cursor = cursor;
704 // We end at the next paragraph with depth 0
705 LyXParagraph * endpar =
706 sel_end_cursor.par()->LastPhysicalPar()->Next();
707 LyXParagraph * undoendpar = endpar;
709 if (endpar && endpar->GetDepth()) {
710 while (endpar && endpar->GetDepth()) {
711 endpar = endpar->LastPhysicalPar()->Next();
716 endpar = endpar->Next(); // because of parindents etc.
719 SetUndo(bview->buffer(), Undo::EDIT,
721 .par()->ParFromPos(sel_start_cursor.pos())->previous,
724 LyXCursor tmpcursor = cursor; // store the current cursor
726 // ok we have a selection. This is always between sel_start_cursor
727 // and sel_end cursor
728 cursor = sel_start_cursor;
730 bool anything_changed = false;
733 // NOTE: you can't change the depth of a bibliography entry
734 if (cursor.par()->footnoteflag ==
735 sel_start_cursor.par()->footnoteflag
736 && textclasslist.Style(bview->buffer()->params.textclass,
737 cursor.par()->GetLayout()
738 ).labeltype != LABEL_BIBLIO) {
739 LyXParagraph * prev =
740 cursor.par()->FirstPhysicalPar()->Previous();
742 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
743 || (prev->GetDepth() == cursor.par()->GetDepth()
744 && textclasslist.Style(bview->buffer()->params.textclass,
745 prev->GetLayout()).isEnvironment()))) {
746 cursor.par()->FirstPhysicalPar()->depth++;
747 anything_changed = true;
750 if (cursor.par() == sel_end_cursor.par())
752 cursor.par(cursor.par()->Next());
755 // if nothing changed set all depth to 0
756 if (!anything_changed) {
757 cursor = sel_start_cursor;
758 while (cursor.par() != sel_end_cursor.par()) {
759 cursor.par()->FirstPhysicalPar()->depth = 0;
760 cursor.par(cursor.par()->Next());
762 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
763 cursor.par()->FirstPhysicalPar()->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();
793 LyXParagraph * undoendpar = endpar;
795 if (endpar && endpar->GetDepth()) {
796 while (endpar && endpar->GetDepth()) {
797 endpar = endpar->LastPhysicalPar()->Next();
802 endpar = endpar->Next(); // because of parindents etc.
805 SetUndo(bview->buffer(), Undo::EDIT,
807 .par()->ParFromPos(sel_start_cursor.pos())->previous,
810 LyXCursor tmpcursor = cursor; // store the current cursor
812 // ok we have a selection. This is always between sel_start_cursor
813 // and sel_end cursor
814 cursor = sel_start_cursor;
817 if (cursor.par()->footnoteflag ==
818 sel_start_cursor.par()->footnoteflag) {
819 if (cursor.par()->FirstPhysicalPar()->depth)
820 cursor.par()->FirstPhysicalPar()->depth--;
822 if (cursor.par() == sel_end_cursor.par())
824 cursor.par(cursor.par()->Next());
827 RedoParagraphs(bview, sel_start_cursor, endpar);
829 // we have to reset the selection, because the
830 // geometry could have changed
831 SetCursor(bview, sel_start_cursor.par(),
832 sel_start_cursor.pos());
834 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
835 UpdateCounters(bview, cursor.row());
838 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
842 // set font over selection and make a total rebreak of those paragraphs
843 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
845 // if there is no selection just set the current_font
847 // Determine basis font
849 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
851 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
853 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
854 // Update current font
855 real_current_font.update(font,
856 bview->buffer()->params.language_info,
859 // Reduce to implicit settings
860 current_font = real_current_font;
861 current_font.reduce(layoutfont);
862 // And resolve it completely
863 real_current_font.realize(layoutfont);
867 LyXCursor tmpcursor = cursor; // store the current cursor
869 // ok we have a selection. This is always between sel_start_cursor
870 // and sel_end cursor
872 SetUndo(bview->buffer(), Undo::EDIT,
873 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
874 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
875 cursor = sel_start_cursor;
876 while (cursor.par() != sel_end_cursor.par() ||
877 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
878 && cursor.pos() < sel_end_cursor.pos()))
880 if (cursor.pos() < cursor.par()->Last()
881 && cursor.par()->footnoteflag
882 == sel_start_cursor.par()->footnoteflag) {
883 // an open footnote should behave
885 LyXFont newfont = GetFont(bview->buffer(),
886 cursor.par(), cursor.pos());
888 bview->buffer()->params.language_info,
890 SetCharFont(bview->buffer(),
891 cursor.par(), cursor.pos(), newfont);
892 cursor.pos(cursor.pos() + 1);
895 cursor.par(cursor.par()->Next());
899 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
901 // we have to reset the selection, because the
902 // geometry could have changed
903 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
905 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
908 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
909 tmpcursor.boundary());
913 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
915 Row * tmprow = cur.row();
916 long y = cur.y() - tmprow->baseline();
918 SetHeightOfRow(bview, tmprow);
919 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
920 // find the first row of the paragraph
921 if (first_phys_par != tmprow->par())
922 while (tmprow->previous()
923 && tmprow->previous()->par() != first_phys_par) {
924 tmprow = tmprow->previous();
925 y -= tmprow->height();
926 SetHeightOfRow(bview, tmprow);
928 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
929 tmprow = tmprow->previous();
930 y -= tmprow->height();
931 SetHeightOfRow(bview, tmprow);
934 // we can set the refreshing parameters now
935 status = LyXText::NEED_MORE_REFRESH;
937 refresh_row = tmprow;
938 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
942 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
944 Row * tmprow = cur.row();
946 long y = cur.y() - tmprow->baseline();
947 SetHeightOfRow(bview, tmprow);
948 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
949 // find the first row of the paragraph
950 if (first_phys_par != tmprow->par())
951 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
952 tmprow = tmprow->previous();
953 y -= tmprow->height();
955 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
956 tmprow = tmprow->previous();
957 y -= tmprow->height();
960 // we can set the refreshing parameters now
961 if (status == LyXText::UNCHANGED || y < refresh_y) {
963 refresh_row = tmprow;
965 status = LyXText::NEED_MORE_REFRESH;
966 SetCursor(bview, cur.par(), cur.pos());
970 /* deletes and inserts again all paragaphs between the cursor
971 * and the specified par
972 * This function is needed after SetLayout and SetFont etc. */
973 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
974 LyXParagraph const * endpar) const
977 LyXParagraph * tmppar = 0, * first_phys_par = 0;
979 Row * tmprow = cur.row();
981 long y = cur.y() - tmprow->baseline();
983 if (!tmprow->previous()){
984 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
986 first_phys_par = tmprow->par()->FirstPhysicalPar();
987 // find the first row of the paragraph
988 if (first_phys_par != tmprow->par())
989 while (tmprow->previous() &&
990 (tmprow->previous()->par() != first_phys_par)) {
991 tmprow = tmprow->previous();
992 y -= tmprow->height();
994 while (tmprow->previous()
995 && tmprow->previous()->par() == first_phys_par) {
996 tmprow = tmprow->previous();
997 y -= tmprow->height();
1001 // we can set the refreshing parameters now
1002 status = LyXText::NEED_MORE_REFRESH;
1004 refresh_row = tmprow->previous(); /* the real refresh row will
1005 be deleted, so I store
1006 the previous here */
1009 tmppar = tmprow->next()->par();
1012 while (tmppar != endpar) {
1013 RemoveRow(tmprow->next());
1015 tmppar = tmprow->next()->par();
1020 // remove the first one
1021 tmprow2 = tmprow; /* this is because tmprow->previous()
1023 tmprow = tmprow->previous();
1026 tmppar = first_phys_par;
1030 InsertParagraph(bview, tmppar, tmprow);
1033 while (tmprow->next() && tmprow->next()->par() == tmppar)
1034 tmprow = tmprow->next();
1035 tmppar = tmppar->Next();
1037 } while (tmppar != endpar);
1039 // this is because of layout changes
1041 refresh_y -= refresh_row->height();
1042 SetHeightOfRow(bview, refresh_row);
1044 refresh_row = firstrow;
1046 SetHeightOfRow(bview, refresh_row);
1049 if (tmprow && tmprow->next())
1050 SetHeightOfRow(bview, tmprow->next());
1054 bool LyXText::FullRebreak(BufferView * bview)
1060 if (need_break_row) {
1061 BreakAgain(bview, need_break_row);
1069 /* important for the screen */
1072 /* the cursor set functions have a special mechanism. When they
1073 * realize, that you left an empty paragraph, they will delete it.
1074 * They also delete the corresponding row */
1076 // need the selection cursor:
1077 void LyXText::SetSelection()
1080 last_sel_cursor = sel_cursor;
1081 sel_start_cursor = sel_cursor;
1082 sel_end_cursor = sel_cursor;
1087 // first the toggling area
1088 if (cursor.y() < last_sel_cursor.y()
1089 || (cursor.y() == last_sel_cursor.y()
1090 && cursor.x() < last_sel_cursor.x())) {
1091 toggle_end_cursor = last_sel_cursor;
1092 toggle_cursor = cursor;
1094 toggle_end_cursor = cursor;
1095 toggle_cursor = last_sel_cursor;
1098 last_sel_cursor = cursor;
1100 // and now the whole selection
1102 if (sel_cursor.par() == cursor.par())
1103 if (sel_cursor.pos() < cursor.pos()) {
1104 sel_end_cursor = cursor;
1105 sel_start_cursor = sel_cursor;
1107 sel_end_cursor = sel_cursor;
1108 sel_start_cursor = cursor;
1110 else if (sel_cursor.y() < cursor.y() ||
1111 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1112 sel_end_cursor = cursor;
1113 sel_start_cursor = sel_cursor;
1116 sel_end_cursor = sel_cursor;
1117 sel_start_cursor = cursor;
1120 // a selection with no contents is not a selection
1121 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1122 sel_start_cursor.pos() == sel_end_cursor.pos())
1127 string LyXText::selectionAsString(Buffer const * buffer) const
1129 if (!selection) return string();
1132 // Special handling if the whole selection is within one paragraph
1133 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1134 result += sel_start_cursor.par()->String(buffer,
1135 sel_start_cursor.pos(),
1136 sel_end_cursor.pos());
1140 // The selection spans more than one paragraph
1142 // First paragraph in selection
1143 result += sel_start_cursor.par()->String(buffer,
1144 sel_start_cursor.pos(),
1145 sel_start_cursor.par()->Last())
1148 // The paragraphs in between (if any)
1149 LyXCursor tmpcur(sel_start_cursor);
1150 tmpcur.par(tmpcur.par()->Next());
1151 while (tmpcur.par() != sel_end_cursor.par()) {
1152 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1153 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1156 // Last paragraph in selection
1157 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1163 void LyXText::ClearSelection() const
1170 void LyXText::CursorHome(BufferView * bview) const
1172 SetCursor(bview, cursor.par(), cursor.row()->pos());
1176 void LyXText::CursorEnd(BufferView * bview) const
1178 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1179 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1181 if (cursor.par()->Last() &&
1182 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1183 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1184 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1186 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1189 if (cursor.par()->table) {
1190 int cell = NumberOfCell(cursor.par(), cursor.pos());
1191 if (cursor.par()->table->RowHasContRow(cell) &&
1192 cursor.par()->table->CellHasContRow(cell)<0) {
1193 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1194 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1196 if (cursor.par()->Last() &&
1197 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1198 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1199 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1201 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1209 void LyXText::CursorTop(BufferView * bview) const
1211 while (cursor.par()->Previous())
1212 cursor.par(cursor.par()->Previous());
1213 SetCursor(bview, cursor.par(), 0);
1217 void LyXText::CursorBottom(BufferView * bview) const
1219 while (cursor.par()->Next())
1220 cursor.par(cursor.par()->Next());
1221 SetCursor(bview, cursor.par(), cursor.par()->Last());
1225 /* returns a pointer to the row near the specified y-coordinate
1226 * (relative to the whole text). y is set to the real beginning
1228 Row * LyXText::GetRowNearY(long & y) const
1230 Row * tmprow = firstrow;
1233 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1234 tmpy += tmprow->height();
1235 tmprow = tmprow->next();
1238 y = tmpy; // return the real y
1243 void LyXText::ToggleFree(BufferView * bview,
1244 LyXFont const & font, bool toggleall)
1246 // If the mask is completely neutral, tell user
1247 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1248 // Could only happen with user style
1249 bview->owner()->getMiniBuffer()
1250 ->Set(_("No font change defined. Use Character under"
1251 " the Layout menu to define font change."));
1255 // Try implicit word selection
1256 // If there is a change in the language the implicit word selection
1258 LyXCursor resetCursor = cursor;
1259 bool implicitSelection = (font.language() == ignore_language)
1260 ? SelectWordWhenUnderCursor(bview) : false;
1263 SetFont(bview, font, toggleall);
1265 /* Implicit selections are cleared afterwards and cursor is set to the
1266 original position. */
1267 if (implicitSelection) {
1269 cursor = resetCursor;
1270 SetCursor(bview, cursor.par(), cursor.pos());
1271 sel_cursor = cursor;
1276 LyXParagraph::size_type
1277 LyXText::BeginningOfMainBody(Buffer const * buf,
1278 LyXParagraph const * par) const
1280 if (textclasslist.Style(buf->params.textclass,
1281 par->GetLayout()).labeltype != LABEL_MANUAL)
1284 return par->BeginningOfMainBody();
1289 /* if there is a selection, reset every environment you can find
1290 * in the selection, otherwise just the environment you are in */
1291 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1293 LyXParagraph * tmppar, * firsttmppar;
1297 /* is is only allowed, if the cursor is IN an open footnote.
1298 * Otherwise it is too dangerous */
1299 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1302 SetUndo(bview->buffer(), Undo::FINISH,
1303 cursor.par()->PreviousBeforeFootnote()->previous,
1304 cursor.par()->NextAfterFootnote()->next);
1306 /* ok, move to the beginning of the footnote. */
1307 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1308 cursor.par(cursor.par()->Previous());
1310 SetCursor(bview, cursor.par(), cursor.par()->Last());
1311 /* this is just faster than using CursorLeft(); */
1313 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1314 tmppar = firsttmppar;
1315 /* tmppar is now the paragraph right before the footnote */
1317 bool first_footnote_par_is_not_empty = tmppar->next->size();
1320 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1321 tmppar = tmppar->next; /* I use next instead of Next(),
1322 * because there cannot be any
1323 * footnotes in a footnote
1325 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1327 /* remember the captions and empty paragraphs */
1328 if ((textclasslist.Style(bview->buffer()->params.textclass,
1329 tmppar->GetLayout())
1330 .labeltype == LABEL_SENSITIVE)
1332 tmppar->SetLayout(bview->buffer()->params, 0);
1335 // now we will paste the ex-footnote, if the layouts allow it
1336 // first restore the layout of the paragraph right behind
1339 tmppar->next->MakeSameLayout(cursor.par());
1342 if ((!tmppar->GetLayout() && !tmppar->table)
1344 && (!tmppar->Next()->Last()
1345 || tmppar->Next()->HasSameLayout(tmppar)))) {
1346 if (tmppar->Next()->Last()
1347 && tmppar->Next()->IsLineSeparator(0))
1348 tmppar->Next()->Erase(0);
1349 tmppar->PasteParagraph(bview->buffer()->params);
1352 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1353 * by the pasting of the beginning */
1355 /* then the beginning */
1356 /* if there is no space between the text and the footnote, so we insert
1358 * (only if the previous par and the footnotepar are not empty!) */
1359 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1360 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1361 if (firsttmppar->size()
1362 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1363 && first_footnote_par_is_not_empty) {
1364 firsttmppar->next->InsertChar(0, ' ');
1366 firsttmppar->PasteParagraph(bview->buffer()->params);
1369 /* now redo the paragaphs */
1370 RedoParagraphs(bview, cursor, tmppar);
1372 SetCursor(bview, cursor.par(), cursor.pos());
1374 /* sometimes it can happen, that there is a counter change */
1375 Row * row = cursor.row();
1376 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1378 UpdateCounters(bview, row);
1386 /* the DTP switches for paragraphs. LyX will store them in the
1387 * first physicla paragraph. When a paragraph is broken, the top settings
1388 * rest, the bottom settings are given to the new one. So I can make shure,
1389 * they do not duplicate themself and you cannnot make dirty things with
1392 void LyXText::SetParagraph(BufferView * bview,
1393 bool line_top, bool line_bottom,
1394 bool pagebreak_top, bool pagebreak_bottom,
1395 VSpace const & space_top,
1396 VSpace const & space_bottom,
1398 string labelwidthstring,
1401 LyXCursor tmpcursor = cursor;
1403 sel_start_cursor = cursor;
1404 sel_end_cursor = cursor;
1407 // make sure that the depth behind the selection are restored, too
1408 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1409 LyXParagraph * undoendpar = endpar;
1411 if (endpar && endpar->GetDepth()) {
1412 while (endpar && endpar->GetDepth()) {
1413 endpar = endpar->LastPhysicalPar()->Next();
1414 undoendpar = endpar;
1418 endpar = endpar->Next(); // because of parindents etc.
1421 SetUndo(bview->buffer(), Undo::EDIT,
1423 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1427 LyXParagraph * tmppar = sel_end_cursor.par();
1428 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1429 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1430 status = LyXText::NEED_MORE_REFRESH;
1431 refresh_row = cursor.row();
1432 refresh_y = cursor.y() - cursor.row()->baseline();
1433 if (cursor.par()->footnoteflag ==
1434 sel_start_cursor.par()->footnoteflag) {
1435 cursor.par()->line_top = line_top;
1436 cursor.par()->line_bottom = line_bottom;
1437 cursor.par()->pagebreak_top = pagebreak_top;
1438 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1439 cursor.par()->added_space_top = space_top;
1440 cursor.par()->added_space_bottom = space_bottom;
1441 // does the layout allow the new alignment?
1442 if (align == LYX_ALIGN_LAYOUT)
1443 align = textclasslist
1444 .Style(bview->buffer()->params.textclass,
1445 cursor.par()->GetLayout()).align;
1446 if (align & textclasslist
1447 .Style(bview->buffer()->params.textclass,
1448 cursor.par()->GetLayout()).alignpossible) {
1449 if (align == textclasslist
1450 .Style(bview->buffer()->params.textclass,
1451 cursor.par()->GetLayout()).align)
1452 cursor.par()->align = LYX_ALIGN_LAYOUT;
1454 cursor.par()->align = align;
1456 cursor.par()->SetLabelWidthString(labelwidthstring);
1457 cursor.par()->noindent = noindent;
1460 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1463 RedoParagraphs(bview, sel_start_cursor, endpar);
1466 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1467 sel_cursor = cursor;
1468 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1470 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1474 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1476 char const * widthp,
1477 int alignment, bool hfill,
1478 bool start_minipage)
1480 LyXCursor tmpcursor = cursor;
1481 LyXParagraph * tmppar;
1483 sel_start_cursor = cursor;
1484 sel_end_cursor = cursor;
1487 // make sure that the depth behind the selection are restored, too
1488 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1489 LyXParagraph * undoendpar = endpar;
1491 if (endpar && endpar->GetDepth()) {
1492 while (endpar && endpar->GetDepth()) {
1493 endpar = endpar->LastPhysicalPar()->Next();
1494 undoendpar = endpar;
1498 endpar = endpar->Next(); // because of parindents etc.
1501 SetUndo(bview->buffer(), Undo::EDIT,
1503 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1506 tmppar = sel_end_cursor.par();
1507 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1508 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1509 status = LyXText::NEED_MORE_REFRESH;
1510 refresh_row = cursor.row();
1511 refresh_y = cursor.y() - cursor.row()->baseline();
1512 if (cursor.par()->footnoteflag ==
1513 sel_start_cursor.par()->footnoteflag) {
1514 if (type == LyXParagraph::PEXTRA_NONE) {
1515 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1516 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1517 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1520 cursor.par()->SetPExtraType(bview->buffer()->params,
1521 type, width, widthp);
1522 cursor.par()->pextra_hfill = hfill;
1523 cursor.par()->pextra_start_minipage = start_minipage;
1524 cursor.par()->pextra_alignment = alignment;
1527 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1529 RedoParagraphs(bview, sel_start_cursor, endpar);
1531 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1532 sel_cursor = cursor;
1533 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1535 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1539 char loweralphaCounter(int n)
1541 if (n < 1 || n > 26)
1547 char alphaCounter(int n)
1549 if (n < 1 || n > 26)
1555 char hebrewCounter(int n)
1557 static const char hebrew[22] = {
1558 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1559 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1560 '÷', 'ø', 'ù', 'ú'
1562 if (n < 1 || n > 22)
1568 static char const * romanCounter(int n)
1570 static char const * roman[20] = {
1571 "i", "ii", "iii", "iv", "v",
1572 "vi", "vii", "viii", "ix", "x",
1573 "xi", "xii", "xiii", "xiv", "xv",
1574 "xvi", "xvii", "xviii", "xix", "xx"
1576 if (n < 1 || n > 20)
1582 // set the counter of a paragraph. This includes the labels
1583 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1585 // this is only relevant for the beginning of paragraph
1586 par = par->FirstPhysicalPar();
1588 LyXLayout const & layout =
1589 textclasslist.Style(buf->params.textclass,
1592 LyXTextClass const & textclass =
1593 textclasslist.TextClass(buf->params.textclass);
1595 /* copy the prev-counters to this one, unless this is the start of a
1596 footnote or of a bibliography or the very first paragraph */
1598 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1599 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1600 && par->footnotekind == LyXParagraph::FOOTNOTE)
1601 && !(textclasslist.Style(buf->params.textclass,
1602 par->Previous()->GetLayout()
1603 ).labeltype != LABEL_BIBLIO
1604 && layout.labeltype == LABEL_BIBLIO)) {
1605 for (int i = 0; i < 10; ++i) {
1606 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1608 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1609 if (!par->appendix && par->start_of_appendix){
1610 par->appendix = true;
1611 for (int i = 0; i < 10; ++i) {
1612 par->setCounter(i, 0);
1615 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1616 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1619 for (int i = 0; i < 10; ++i) {
1620 par->setCounter(i, 0);
1622 par->appendix = par->start_of_appendix;
1628 // if this is an open marginnote and this is the first
1629 // entry in the marginnote and the enclosing
1630 // environment is an enum/item then correct for the
1631 // LaTeX behaviour (ARRae)
1632 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1633 && par->footnotekind == LyXParagraph::MARGIN
1635 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1636 && (par->PreviousBeforeFootnote()
1637 && textclasslist.Style(buf->params.textclass,
1638 par->PreviousBeforeFootnote()->GetLayout()
1639 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1640 // Any itemize or enumerate environment in a marginnote
1641 // that is embedded in an itemize or enumerate
1642 // paragraph is seen by LaTeX as being at a deeper
1643 // level within that enclosing itemization/enumeration
1644 // even if there is a "standard" layout at the start of
1650 /* Maybe we have to increment the enumeration depth.
1651 * BUT, enumeration in a footnote is considered in isolation from its
1652 * surrounding paragraph so don't increment if this is the
1653 * first line of the footnote
1654 * AND, bibliographies can't have their depth changed ie. they
1655 * are always of depth 0
1658 && par->Previous()->GetDepth() < par->GetDepth()
1659 && textclasslist.Style(buf->params.textclass,
1660 par->Previous()->GetLayout()
1661 ).labeltype == LABEL_COUNTER_ENUMI
1662 && par->enumdepth < 3
1663 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1664 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1665 && par->footnotekind == LyXParagraph::FOOTNOTE)
1666 && layout.labeltype != LABEL_BIBLIO) {
1670 /* Maybe we have to decrement the enumeration depth, see note above */
1672 && par->Previous()->GetDepth() > par->GetDepth()
1673 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1674 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1675 && par->footnotekind == LyXParagraph::FOOTNOTE)
1676 && layout.labeltype != LABEL_BIBLIO) {
1677 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1678 par->setCounter(6 + par->enumdepth,
1679 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1680 /* reset the counters.
1681 * A depth change is like a breaking layout
1683 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1684 par->setCounter(i, 0);
1687 if (!par->labelstring.empty()) {
1688 par->labelstring.erase();
1691 if (layout.margintype == MARGIN_MANUAL) {
1692 if (par->labelwidthstring.empty()) {
1693 par->SetLabelWidthString(layout.labelstring());
1696 par->SetLabelWidthString(string());
1699 /* is it a layout that has an automatic label ? */
1700 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1702 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1703 if (i >= 0 && i<= buf->params.secnumdepth) {
1704 par->incCounter(i); // increment the counter
1706 // Is there a label? Useful for Chapter layout
1707 if (!par->appendix){
1708 if (!layout.labelstring().empty())
1709 par->labelstring = layout.labelstring();
1711 par->labelstring.erase();
1713 if (!layout.labelstring_appendix().empty())
1714 par->labelstring = layout.labelstring_appendix();
1716 par->labelstring.erase();
1720 std::ostringstream s;
1724 if (!par->appendix) {
1725 switch (2 * LABEL_FIRST_COUNTER -
1726 textclass.maxcounter() + i) {
1727 case LABEL_COUNTER_CHAPTER:
1728 s << par->getCounter(i);
1730 case LABEL_COUNTER_SECTION:
1731 s << par->getCounter(i - 1) << '.'
1732 << par->getCounter(i);
1734 case LABEL_COUNTER_SUBSECTION:
1735 s << par->getCounter(i - 2) << '.'
1736 << par->getCounter(i - 1) << '.'
1737 << par->getCounter(i);
1739 case LABEL_COUNTER_SUBSUBSECTION:
1740 s << par->getCounter(i - 3) << '.'
1741 << par->getCounter(i - 2) << '.'
1742 << par->getCounter(i - 1) << '.'
1743 << par->getCounter(i);
1746 case LABEL_COUNTER_PARAGRAPH:
1747 s << par->getCounter(i - 4) << '.'
1748 << par->getCounter(i - 3) << '.'
1749 << par->getCounter(i - 2) << '.'
1750 << par->getCounter(i - 1) << '.'
1751 << par->getCounter(i);
1753 case LABEL_COUNTER_SUBPARAGRAPH:
1754 s << par->getCounter(i - 5) << '.'
1755 << par->getCounter(i - 4) << '.'
1756 << par->getCounter(i - 3) << '.'
1757 << par->getCounter(i - 2) << '.'
1758 << par->getCounter(i - 1) << '.'
1759 << par->getCounter(i);
1763 s << par->getCounter(i) << '.';
1766 } else { // appendix
1767 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1768 case LABEL_COUNTER_CHAPTER:
1769 if (par->isRightToLeftPar(buf->params))
1770 s << hebrewCounter(par->getCounter(i));
1772 s << alphaCounter(par->getCounter(i));
1774 case LABEL_COUNTER_SECTION:
1775 if (par->isRightToLeftPar(buf->params))
1776 s << hebrewCounter(par->getCounter(i - 1));
1778 s << alphaCounter(par->getCounter(i - 1));
1781 << par->getCounter(i);
1784 case LABEL_COUNTER_SUBSECTION:
1785 if (par->isRightToLeftPar(buf->params))
1786 s << hebrewCounter(par->getCounter(i - 2));
1788 s << alphaCounter(par->getCounter(i - 2));
1791 << par->getCounter(i-1) << '.'
1792 << par->getCounter(i);
1795 case LABEL_COUNTER_SUBSUBSECTION:
1796 if (par->isRightToLeftPar(buf->params))
1797 s << hebrewCounter(par->getCounter(i-3));
1799 s << alphaCounter(par->getCounter(i-3));
1802 << par->getCounter(i-2) << '.'
1803 << par->getCounter(i-1) << '.'
1804 << par->getCounter(i);
1807 case LABEL_COUNTER_PARAGRAPH:
1808 if (par->isRightToLeftPar(buf->params))
1809 s << hebrewCounter(par->getCounter(i-4));
1811 s << alphaCounter(par->getCounter(i-4));
1814 << par->getCounter(i-3) << '.'
1815 << par->getCounter(i-2) << '.'
1816 << par->getCounter(i-1) << '.'
1817 << par->getCounter(i);
1820 case LABEL_COUNTER_SUBPARAGRAPH:
1821 if (par->isRightToLeftPar(buf->params))
1822 s << hebrewCounter(par->getCounter(i-5));
1824 s << alphaCounter(par->getCounter(i-5));
1827 << par->getCounter(i-4) << '.'
1828 << par->getCounter(i-3) << '.'
1829 << par->getCounter(i-2) << '.'
1830 << par->getCounter(i-1) << '.'
1831 << par->getCounter(i);
1835 // Can this ever be reached? And in the
1836 // case it is, how can this be correct?
1838 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1844 par->labelstring += s.str().c_str();
1845 // We really want to remove the c_str as soon as
1849 char * tmps = s.str();
1850 par->labelstring += tmps;
1854 for (i++; i < 10; ++i) {
1855 // reset the following counters
1856 par->setCounter(i, 0);
1858 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1859 for (i++; i < 10; ++i) {
1860 // reset the following counters
1861 par->setCounter(i, 0);
1863 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1864 par->incCounter(i + par->enumdepth);
1865 int number = par->getCounter(i + par->enumdepth);
1868 std::ostringstream s;
1872 switch (par->enumdepth) {
1874 if (par->isRightToLeftPar(buf->params))
1876 << hebrewCounter(number)
1880 << loweralphaCounter(number)
1884 if (par->isRightToLeftPar(buf->params))
1885 s << '.' << romanCounter(number);
1887 s << romanCounter(number) << '.';
1890 if (par->isRightToLeftPar(buf->params))
1892 << alphaCounter(number);
1894 s << alphaCounter(number)
1898 if (par->isRightToLeftPar(buf->params))
1905 par->labelstring = s.str().c_str();
1906 // we really want to get rid of that c_str()
1909 char * tmps = s.str();
1910 par->labelstring = tmps;
1914 for (i += par->enumdepth + 1; i < 10; ++i)
1915 par->setCounter(i, 0); /* reset the following counters */
1918 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1919 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1921 int number = par->getCounter(i);
1923 par->bibkey = new InsetBibKey();
1924 par->bibkey->setCounter(number);
1925 par->labelstring = layout.labelstring();
1927 // In biblio should't be following counters but...
1929 string s = layout.labelstring();
1931 // the caption hack:
1933 if (layout.labeltype == LABEL_SENSITIVE) {
1934 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1935 && (par->footnotekind == LyXParagraph::FIG
1936 || par->footnotekind == LyXParagraph::WIDE_FIG))
1937 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1938 ? ":øåéà " : "Figure:";
1939 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1940 && (par->footnotekind == LyXParagraph::TAB
1941 || par->footnotekind == LyXParagraph::WIDE_TAB))
1942 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1943 ? ":äìáè" : "Table:";
1944 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1945 && par->footnotekind == LyXParagraph::ALGORITHM)
1946 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1947 ? ":Ãúéøåâìà " : "Algorithm:";
1949 /* par->SetLayout(0);
1950 s = layout->labelstring; */
1951 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1952 ? " :úåòîùî øñç" : "Senseless: ";
1955 par->labelstring = s;
1957 /* reset the enumeration counter. They are always resetted
1958 * when there is any other layout between */
1959 for (int i = 6 + par->enumdepth; i < 10; ++i)
1960 par->setCounter(i, 0);
1965 /* Updates all counters BEHIND the row. Changed paragraphs
1966 * with a dynamic left margin will be rebroken. */
1967 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1975 if (row->par()->next
1976 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1977 par = row->par()->LastPhysicalPar()->Next();
1979 par = row->par()->next;
1984 while (row->par() != par)
1987 SetCounter(bview->buffer(), par);
1989 /* now check for the headline layouts. remember that they
1990 * have a dynamic left margin */
1992 && ( textclasslist.Style(bview->buffer()->params.textclass,
1993 par->layout).margintype == MARGIN_DYNAMIC
1994 || textclasslist.Style(bview->buffer()->params.textclass,
1995 par->layout).labeltype == LABEL_SENSITIVE)
1998 /* Rebreak the paragraph */
1999 RemoveParagraph(row);
2000 AppendParagraph(bview, row);
2003 /* think about the damned open footnotes! */
2004 while (par->Next() &&
2005 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2006 || par->Next()->IsDummy())){
2008 if (par->IsDummy()) {
2009 while (row->par() != par)
2011 RemoveParagraph(row);
2012 AppendParagraph(bview, row);
2018 par = par->LastPhysicalPar()->Next();
2024 /* insets an inset. */
2025 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2027 if (!cursor.par()->InsertInsetAllowed(inset))
2029 SetUndo(bview->buffer(), Undo::INSERT,
2030 cursor.par()->ParFromPos(cursor.pos())->previous,
2031 cursor.par()->ParFromPos(cursor.pos())->next);
2032 cursor.par()->InsertInset(cursor.pos(), inset);
2033 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2034 * The character will not be inserted a
2039 void LyXText::copyEnvironmentType()
2041 copylayouttype = cursor.par()->GetLayout();
2045 void LyXText::pasteEnvironmentType(BufferView * bview)
2047 SetLayout(bview, copylayouttype);
2051 void LyXText::CutSelection(BufferView * bview, bool doclear)
2053 // Stuff what we got on the clipboard. Even if there is no selection.
2055 // There is a problem with having the stuffing here in that the
2056 // larger the selection the slower LyX will get. This can be
2057 // solved by running the line below only when the selection has
2058 // finished. The solution used currently just works, to make it
2059 // faster we need to be more clever and probably also have more
2060 // calls to stuffClipboard. (Lgb)
2061 bview->stuffClipboard(selectionAsString(bview->buffer()));
2063 // This doesn't make sense, if there is no selection
2067 // OK, we have a selection. This is always between sel_start_cursor
2068 // and sel_end cursor
2069 LyXParagraph * tmppar;
2072 // Check whether there are half footnotes in the selection
2073 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2074 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2075 tmppar = sel_start_cursor.par();
2076 while (tmppar != sel_end_cursor.par()){
2077 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2078 WriteAlert(_("Impossible operation"),
2079 _("Don't know what to do with half floats."),
2083 tmppar = tmppar->Next();
2088 /* table stuff -- begin */
2089 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2090 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2091 WriteAlert(_("Impossible operation"),
2092 _("Don't know what to do with half tables."),
2096 sel_start_cursor.par()->table->Reinit();
2098 /* table stuff -- end */
2100 // make sure that the depth behind the selection are restored, too
2101 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2102 LyXParagraph * undoendpar = endpar;
2104 if (endpar && endpar->GetDepth()) {
2105 while (endpar && endpar->GetDepth()) {
2106 endpar = endpar->LastPhysicalPar()->Next();
2107 undoendpar = endpar;
2109 } else if (endpar) {
2110 endpar = endpar->Next(); // because of parindents etc.
2113 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2114 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2118 // there are two cases: cut only within one paragraph or
2119 // more than one paragraph
2120 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2121 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2122 // only within one paragraph
2123 endpar = sel_start_cursor.par();
2124 int pos = sel_end_cursor.pos();
2125 cap.cutSelection(sel_start_cursor.par(), &endpar,
2126 sel_start_cursor.pos(), pos,
2127 bview->buffer()->params.textclass, doclear);
2128 sel_end_cursor.pos(pos);
2130 endpar = sel_end_cursor.par();
2132 int pos = sel_end_cursor.pos();
2133 cap.cutSelection(sel_start_cursor.par(), &endpar,
2134 sel_start_cursor.pos(), pos,
2135 bview->buffer()->params.textclass, doclear);
2137 sel_end_cursor.par(endpar);
2138 sel_end_cursor.pos(pos);
2139 cursor.pos(sel_end_cursor.pos());
2141 endpar = endpar->Next();
2143 // sometimes necessary
2145 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2147 RedoParagraphs(bview, sel_start_cursor, endpar);
2150 cursor = sel_start_cursor;
2151 SetCursor(bview, cursor.par(), cursor.pos());
2152 sel_cursor = cursor;
2153 UpdateCounters(bview, cursor.row());
2157 void LyXText::CopySelection(BufferView * bview)
2159 // Stuff what we got on the clipboard. Even if there is no selection.
2161 // There is a problem with having the stuffing here in that the
2162 // larger the selection the slower LyX will get. This can be
2163 // solved by running the line below only when the selection has
2164 // finished. The solution used currently just works, to make it
2165 // faster we need to be more clever and probably also have more
2166 // calls to stuffClipboard. (Lgb)
2167 bview->stuffClipboard(selectionAsString(bview->buffer()));
2169 // this doesnt make sense, if there is no selection
2173 // ok we have a selection. This is always between sel_start_cursor
2174 // and sel_end cursor
2175 LyXParagraph * tmppar;
2178 /* check wether there are half footnotes in the selection */
2179 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2180 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2181 tmppar = sel_start_cursor.par();
2182 while (tmppar != sel_end_cursor.par()) {
2183 if (tmppar->footnoteflag !=
2184 sel_end_cursor.par()->footnoteflag) {
2185 WriteAlert(_("Impossible operation"),
2186 _("Don't know what to do"
2187 " with half floats."),
2191 tmppar = tmppar->Next();
2196 /* table stuff -- begin */
2197 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2198 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2199 WriteAlert(_("Impossible operation"),
2200 _("Don't know what to do with half tables."),
2205 /* table stuff -- end */
2208 // copy behind a space if there is one
2209 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2210 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2211 && (sel_start_cursor.par() != sel_end_cursor.par()
2212 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2213 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2217 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2218 sel_start_cursor.pos(), sel_end_cursor.pos(),
2219 bview->buffer()->params.textclass);
2223 void LyXText::PasteSelection(BufferView * bview)
2227 // this does not make sense, if there is nothing to paste
2228 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2231 SetUndo(bview->buffer(), Undo::INSERT,
2232 cursor.par()->ParFromPos(cursor.pos())->previous,
2233 cursor.par()->ParFromPos(cursor.pos())->next);
2235 LyXParagraph * endpar;
2236 LyXParagraph * actpar = cursor.par();
2238 int pos = cursor.pos();
2239 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2241 RedoParagraphs(bview, cursor, endpar);
2243 SetCursor(bview, cursor.par(), cursor.pos());
2246 sel_cursor = cursor;
2247 SetCursor(bview, actpar, pos);
2249 UpdateCounters(bview, cursor.row());
2253 // returns a pointer to the very first LyXParagraph
2254 LyXParagraph * LyXText::FirstParagraph() const
2256 return OwnerParagraph();
2260 // returns true if the specified string is at the specified position
2261 bool LyXText::IsStringInText(LyXParagraph * par,
2262 LyXParagraph::size_type pos,
2263 char const * str) const
2267 while (pos + i < par->Last() && str[i] &&
2268 str[i] == par->GetChar(pos + i)) {
2278 // sets the selection over the number of characters of string, no check!!
2279 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2281 sel_cursor = cursor;
2282 for (int i = 0; string[i]; ++i)
2288 // simple replacing. The font of the first selected character is used
2289 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2291 SetCursorParUndo(bview->buffer());
2294 if (!selection) { // create a dummy selection
2295 sel_end_cursor = cursor;
2296 sel_start_cursor = cursor;
2299 // Get font setting before we cut
2300 LyXParagraph::size_type pos = sel_end_cursor.pos();
2301 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2302 sel_start_cursor.pos());
2304 // Insert the new string
2305 for (int i = 0; str[i]; ++i) {
2306 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2310 // Cut the selection
2311 CutSelection(bview);
2317 // if the string can be found: return true and set the cursor to
2319 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2321 LyXParagraph * par = cursor.par();
2322 LyXParagraph::size_type pos = cursor.pos();
2323 while (par && !IsStringInText(par, pos, str)) {
2324 if (pos < par->Last() - 1)
2332 SetCursor(bview, par, pos);
2340 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2342 LyXParagraph * par = cursor.par();
2343 int pos = cursor.pos();
2349 // We skip empty paragraphs (Asger)
2351 par = par->Previous();
2353 pos = par->Last() - 1;
2354 } while (par && pos < 0);
2356 } while (par && !IsStringInText(par, pos, string));
2359 SetCursor(bview, par, pos);
2366 // needed to insert the selection
2367 void LyXText::InsertStringA(BufferView * bview, string const & str)
2369 LyXParagraph * par = cursor.par();
2370 LyXParagraph::size_type pos = cursor.pos();
2371 LyXParagraph::size_type a = 0;
2373 LyXParagraph * endpar = cursor.par()->Next();
2375 SetCursorParUndo(bview->buffer());
2378 textclasslist.Style(bview->buffer()->params.textclass,
2379 cursor.par()->GetLayout()).isEnvironment();
2380 // only to be sure, should not be neccessary
2383 // insert the string, don't insert doublespace
2384 string::size_type i = 0;
2385 while (i < str.length()) {
2386 if (str[i] != '\n') {
2388 && i + 1 < str.length() && str[i + 1] != ' '
2389 && pos && par->GetChar(pos - 1)!= ' ') {
2390 par->InsertChar(pos, ' ', current_font);
2393 } else if (par->table) {
2394 if (str[i] == '\t') {
2395 while((pos < par->size()) &&
2396 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2398 if (pos < par->size())
2400 else // no more fields to fill skip the rest
2402 } else if ((str[i] != 13) &&
2403 ((str[i] & 127) >= ' ')) {
2404 par->InsertChar(pos, str[i],
2409 } else if (str[i] == ' ') {
2410 InsetSpecialChar * new_inset =
2411 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2412 if (par->InsertInsetAllowed(new_inset)) {
2413 par->InsertInset(pos, new_inset,
2419 } else if (str[i] == '\t') {
2420 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2421 InsetSpecialChar * new_inset =
2422 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2423 if (par->InsertInsetAllowed(new_inset)) {
2424 par->InsertInset(pos, new_inset,
2431 } else if (str[i] != 13 &&
2432 // Ignore unprintables
2433 (str[i] & 127) >= ' ') {
2434 par->InsertChar(pos, str[i], current_font);
2440 if ((i + 1) >= str.length()) {
2441 if (pos < par->size())
2445 while((pos < par->size()) &&
2446 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2449 cell = NumberOfCell(par, pos);
2450 while((pos < par->size()) &&
2451 !(par->table->IsFirstCell(cell))) {
2453 while((pos < par->size()) &&
2454 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2457 cell = NumberOfCell(par, pos);
2459 if (pos >= par->size())
2460 // no more fields to fill skip the rest
2464 if (!par->size()) { // par is empty
2465 InsetSpecialChar * new_inset =
2466 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2467 if (par->InsertInsetAllowed(new_inset)) {
2468 par->InsertInset(pos,
2476 par->BreakParagraph(bview->buffer()->params, pos, flag);
2486 RedoParagraphs(bview, cursor, endpar);
2487 SetCursor(bview, cursor.par(), cursor.pos());
2488 sel_cursor = cursor;
2489 SetCursor(bview, par, pos);
2494 /* turns double-CR to single CR, others where converted into one blank and 13s
2495 * that are ignored .Double spaces are also converted into one. Spaces at
2496 * the beginning of a paragraph are forbidden. tabs are converted into one
2497 * space. then InsertStringA is called */
2498 void LyXText::InsertStringB(BufferView * bview, string const & s)
2501 LyXParagraph * par = cursor.par();
2502 string::size_type i = 1;
2503 while (i < str.length()) {
2504 if (str[i] == '\t' && !par->table)
2506 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2508 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2509 if (str[i + 1] != '\n') {
2510 if (str[i - 1] != ' ')
2515 while (i + 1 < str.length()
2516 && (str[i + 1] == ' '
2517 || str[i + 1] == '\t'
2518 || str[i + 1] == '\n'
2519 || str[i + 1] == 13)) {
2526 InsertStringA(bview, str);
2530 bool LyXText::GotoNextError(BufferView * bview) const
2532 LyXCursor res = cursor;
2534 if (res.pos() < res.par()->Last() - 1) {
2535 res.pos(res.pos() + 1);
2537 res.par(res.par()->Next());
2541 } while (res.par() &&
2542 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2543 && res.par()->GetInset(res.pos())->AutoDelete()));
2546 SetCursor(bview, res.par(), res.pos());
2553 bool LyXText::GotoNextNote(BufferView * bview) const
2555 LyXCursor res = cursor;
2557 if (res.pos() < res.par()->Last() - 1) {
2558 res.pos(res.pos() + 1);
2560 res.par(res.par()->Next());
2564 } while (res.par() &&
2565 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2566 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2569 SetCursor(bview, res.par(), res.pos());
2576 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2577 LyXParagraph::size_type pos)
2579 LyXCursor tmpcursor;
2582 /* table stuff -- begin*/
2585 CheckParagraphInTable(bview, par, pos);
2589 /* table stuff -- end*/
2592 LyXParagraph::size_type z;
2593 Row * row = GetRow(par, pos, y);
2595 // is there a break one row above
2596 if (row->previous() && row->previous()->par() == row->par()) {
2597 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2598 if ( z >= row->pos()) {
2599 // set the dimensions of the row above
2600 y -= row->previous()->height();
2602 refresh_row = row->previous();
2603 status = LyXText::NEED_MORE_REFRESH;
2605 BreakAgain(bview, row->previous());
2607 // set the cursor again. Otherwise
2608 // dangling pointers are possible
2609 SetCursor(bview, cursor.par(), cursor.pos());
2610 sel_cursor = cursor;
2615 int tmpheight = row->height();
2616 LyXParagraph::size_type tmplast = RowLast(row);
2620 BreakAgain(bview, row);
2621 if (row->height() == tmpheight && RowLast(row) == tmplast)
2622 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2624 status = LyXText::NEED_MORE_REFRESH;
2626 // check the special right address boxes
2627 if (textclasslist.Style(bview->buffer()->params.textclass,
2628 par->GetLayout()).margintype
2629 == MARGIN_RIGHT_ADDRESS_BOX) {
2636 RedoDrawingOfParagraph(bview, tmpcursor);
2642 // set the cursor again. Otherwise dangling pointers are possible
2643 // also set the selection
2647 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2648 sel_cursor = cursor;
2649 SetCursorIntern(bview, sel_start_cursor.par(),
2650 sel_start_cursor.pos());
2651 sel_start_cursor = cursor;
2652 SetCursorIntern(bview, sel_end_cursor.par(),
2653 sel_end_cursor.pos());
2654 sel_end_cursor = cursor;
2655 SetCursorIntern(bview, last_sel_cursor.par(),
2656 last_sel_cursor.pos());
2657 last_sel_cursor = cursor;
2660 SetCursorIntern(bview, cursor.par(), cursor.pos());
2664 // returns false if inset wasn't found
2665 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2667 // first check the current paragraph
2668 int pos = cursor.par()->GetPositionOfInset(inset);
2670 CheckParagraph(bview, cursor.par(), pos);
2674 // check every paragraph
2676 LyXParagraph * par = FirstParagraph();
2678 // make sure the paragraph is open
2679 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2680 pos = par->GetPositionOfInset(inset);
2682 CheckParagraph(bview, par, pos);
2693 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2694 LyXParagraph::size_type pos,
2695 bool setfont, bool boundary) const
2697 LyXCursor old_cursor = cursor;
2698 SetCursorIntern(bview, par, pos, setfont, boundary);
2699 DeleteEmptyParagraphMechanism(bview, old_cursor);
2703 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2704 LyXParagraph::size_type pos, bool boundary) const
2706 // correct the cursor position if impossible
2707 if (pos > par->Last()){
2708 LyXParagraph * tmppar = par->ParFromPos(pos);
2709 pos = par->PositionInParFromPos(pos);
2713 if (par->IsDummy() && par->previous &&
2714 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2715 while (par->previous &&
2716 ((par->previous->IsDummy() &&
2717 (par->previous->previous->footnoteflag ==
2718 LyXParagraph::CLOSED_FOOTNOTE)) ||
2719 (par->previous->footnoteflag ==
2720 LyXParagraph::CLOSED_FOOTNOTE))) {
2721 par = par->previous ;
2722 if (par->IsDummy() &&
2723 (par->previous->footnoteflag ==
2724 LyXParagraph::CLOSED_FOOTNOTE))
2725 pos += par->size() + 1;
2727 if (par->previous) {
2728 par = par->previous;
2730 pos += par->size() + 1;
2735 cur.boundary(boundary);
2737 /* get the cursor y position in text */
2739 Row * row = GetRow(par, pos, y);
2740 /* y is now the beginning of the cursor row */
2741 y += row->baseline();
2742 /* y is now the cursor baseline */
2745 /* now get the cursors x position */
2747 float fill_separator, fill_hfill, fill_label_hfill;
2748 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2750 LyXParagraph::size_type cursor_vpos = 0;
2751 LyXParagraph::size_type last = RowLastPrintable(row);
2753 if (pos > last + 1) // This shouldn't happen.
2755 else if (pos < row->pos())
2758 if (last < row->pos())
2759 cursor_vpos = row->pos();
2760 else if (pos > last && !boundary)
2761 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2762 ? row->pos() : last + 1;
2763 else if (pos > row->pos() &&
2764 (pos > last || boundary ||
2765 (row->par()->table && row->par()->IsNewline(pos))))
2766 /// Place cursor after char at (logical) position pos - 1
2767 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2768 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2770 /// Place cursor before char at (logical) position pos
2771 cursor_vpos = (bidi_level(pos) % 2 == 0)
2772 ? log2vis(pos) : log2vis(pos) + 1;
2775 /* table stuff -- begin*/
2776 if (row->par()->table) {
2777 int cell = NumberOfCell(row->par(), row->pos());
2779 x += row->par()->table->GetBeginningOfTextInCell(cell);
2780 for (LyXParagraph::size_type vpos = row->pos();
2781 vpos < cursor_vpos; ++vpos) {
2782 pos = vis2log(vpos);
2783 if (row->par()->IsNewline(pos)) {
2784 x = x_old + row->par()->table->WidthOfColumn(cell);
2787 x += row->par()->table->GetBeginningOfTextInCell(cell);
2789 x += SingleWidth(bview, row->par(), pos);
2793 /* table stuff -- end*/
2795 LyXParagraph::size_type main_body =
2796 BeginningOfMainBody(bview->buffer(), row->par());
2797 if ((main_body > 0) &&
2798 ((main_body-1 > last) ||
2799 !row->par()->IsLineSeparator(main_body-1)))
2802 for (LyXParagraph::size_type vpos = row->pos();
2803 vpos < cursor_vpos; ++vpos) {
2804 pos = vis2log(vpos);
2805 if (main_body > 0 && pos == main_body-1) {
2806 x += fill_label_hfill +
2807 lyxfont::width(textclasslist.Style(
2808 bview->buffer()->params.textclass,
2809 row->par()->GetLayout())
2811 GetFont(bview->buffer(), row->par(), -2));
2812 if (row->par()->IsLineSeparator(main_body-1))
2813 x -= SingleWidth(bview, row->par(),main_body-1);
2815 if (HfillExpansion(bview->buffer(), row, pos)) {
2816 x += SingleWidth(bview, row->par(), pos);
2817 if (pos >= main_body)
2820 x += fill_label_hfill;
2821 } else if (row->par()->IsSeparator(pos)) {
2822 x += SingleWidth(bview, row->par(), pos);
2823 if (pos >= main_body)
2824 x += fill_separator;
2826 x += SingleWidth(bview, row->par(), pos);
2838 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2839 LyXParagraph::size_type pos,
2840 bool setfont, bool boundary) const
2842 SetCursor(bview, cursor, par, pos, boundary);
2844 SetCurrentFont(bview);
2847 void LyXText::SetCurrentFont(BufferView * bview) const
2849 LyXParagraph::size_type pos = cursor.pos();
2850 if (cursor.boundary() && pos > 0)
2854 if (pos == cursor.par()->Last() ||
2855 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2857 else if (cursor.par()->IsSeparator(pos)) {
2858 if (pos > cursor.row()->pos() &&
2859 bidi_level(pos) % 2 ==
2860 bidi_level(pos - 1) % 2)
2862 else if (pos + 1 < cursor.par()->Last())
2868 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2869 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2873 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2875 LyXCursor old_cursor = cursor;
2877 /* get the row first */
2879 Row * row = GetRowNearY(y);
2880 cursor.par(row->par());
2883 int column = GetColumnNearX(bview, row, x, bound);
2884 cursor.pos(row->pos() + column);
2886 cursor.y(y + row->baseline());
2888 cursor.boundary(bound);
2889 SetCurrentFont(bview);
2890 DeleteEmptyParagraphMechanism(bview, old_cursor);
2894 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2895 int x, long y) const
2897 /* get the row first */
2899 Row * row = GetRowNearY(y);
2901 int column = GetColumnNearX(bview, row, x, bound);
2903 cur.par(row->par());
2904 cur.pos(row->pos() + column);
2906 cur.y(y + row->baseline());
2908 cur.boundary(bound);
2912 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2914 CursorLeftIntern(bview, internal);
2916 if (cursor.par()->table) {
2917 int cell = NumberOfCell(cursor.par(), cursor.pos());
2918 if (cursor.par()->table->IsContRow(cell)
2919 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2927 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2929 if (cursor.pos() > 0) {
2930 bool boundary = cursor.boundary();
2931 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2932 if (!internal && !boundary &&
2933 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2934 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2935 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2936 LyXParagraph * par = cursor.par()->Previous();
2937 LyXParagraph::size_type pos = par->Last();
2938 SetCursor(bview, par, pos);
2939 if (IsBoundary(bview->buffer(), par, pos))
2940 SetCursor(bview, par, pos, false, true);
2945 void LyXText::CursorRight(BufferView * bview, bool internal) const
2947 CursorRightIntern(bview, internal);
2949 if (cursor.par()->table) {
2950 int cell = NumberOfCell(cursor.par(), cursor.pos());
2951 if (cursor.par()->table->IsContRow(cell) &&
2952 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2960 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
2962 if (cursor.pos() < cursor.par()->Last()) {
2963 if (!internal && cursor.boundary() &&
2964 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
2965 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2967 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2968 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2969 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2971 } else if (cursor.par()->Next())
2972 SetCursor(bview, cursor.par()->Next(), 0);
2976 void LyXText::CursorUp(BufferView * bview) const
2978 SetCursorFromCoordinates(bview, cursor.x_fix(),
2979 cursor.y() - cursor.row()->baseline() - 1);
2981 if (cursor.par()->table) {
2982 int cell = NumberOfCell(cursor.par(), cursor.pos());
2983 if (cursor.par()->table->IsContRow(cell) &&
2984 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2992 void LyXText::CursorDown(BufferView * bview) const
2995 if (cursor.par()->table &&
2996 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
2997 !cursor.par()->next)
3001 SetCursorFromCoordinates(bview, cursor.x_fix(),
3002 cursor.y() - cursor.row()->baseline()
3003 + cursor.row()->height() + 1);
3005 if (cursor.par()->table) {
3006 int cell = NumberOfCell(cursor.par(), cursor.pos());
3007 int cell_above = cursor.par()->table->GetCellAbove(cell);
3008 while(cursor.par()->table &&
3009 cursor.par()->table->IsContRow(cell) &&
3010 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3011 SetCursorFromCoordinates(bview, cursor.x_fix(),
3012 cursor.y() - cursor.row()->baseline()
3013 + cursor.row()->height() + 1);
3014 if (cursor.par()->table) {
3015 cell = NumberOfCell(cursor.par(), cursor.pos());
3016 cell_above = cursor.par()->table->GetCellAbove(cell);
3024 void LyXText::CursorUpParagraph(BufferView * bview) const
3026 if (cursor.pos() > 0) {
3027 SetCursor(bview, cursor.par(), 0);
3029 else if (cursor.par()->Previous()) {
3030 SetCursor(bview, cursor.par()->Previous(), 0);
3035 void LyXText::CursorDownParagraph(BufferView * bview) const
3037 if (cursor.par()->Next()) {
3038 SetCursor(bview, cursor.par()->Next(), 0);
3040 SetCursor(bview, cursor.par(), cursor.par()->Last());
3045 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3046 LyXCursor const & old_cursor) const
3048 // Would be wrong to delete anything if we have a selection.
3049 if (selection) return;
3051 // We allow all kinds of "mumbo-jumbo" when freespacing.
3052 if (textclasslist.Style(bview->buffer()->params.textclass,
3053 old_cursor.par()->GetLayout()).free_spacing)
3056 bool deleted = false;
3058 /* Ok I'll put some comments here about what is missing.
3059 I have fixed BackSpace (and thus Delete) to not delete
3060 double-spaces automagically. I have also changed Cut,
3061 Copy and Paste to hopefully do some sensible things.
3062 There are still some small problems that can lead to
3063 double spaces stored in the document file or space at
3064 the beginning of paragraphs. This happens if you have
3065 the cursor betwenn to spaces and then save. Or if you
3066 cut and paste and the selection have a space at the
3067 beginning and then save right after the paste. I am
3068 sure none of these are very hard to fix, but I will
3069 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3070 that I can get some feedback. (Lgb)
3073 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3074 // delete the LineSeparator.
3077 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3078 // delete the LineSeparator.
3081 // If the pos around the old_cursor were spaces, delete one of them.
3082 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3083 // Only if the cursor has really moved
3085 if (old_cursor.pos() > 0
3086 && old_cursor.pos() < old_cursor.par()->Last()
3087 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3088 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3089 old_cursor.par()->Erase(old_cursor.pos() - 1);
3090 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3092 if (old_cursor.par() == cursor.par() &&
3093 cursor.pos() > old_cursor.pos()) {
3094 SetCursorIntern(bview, cursor.par(),
3097 SetCursorIntern(bview, cursor.par(),
3103 // Do not delete empty paragraphs with keepempty set.
3104 if ((textclasslist.Style(bview->buffer()->params.textclass,
3105 old_cursor.par()->GetLayout())).keepempty)
3108 LyXCursor tmpcursor;
3110 if (old_cursor.par() != cursor.par()) {
3111 if ( (old_cursor.par()->Last() == 0
3112 || (old_cursor.par()->Last() == 1
3113 && old_cursor.par()->IsLineSeparator(0)))
3114 && old_cursor.par()->FirstPhysicalPar()
3115 == old_cursor.par()->LastPhysicalPar()) {
3116 // ok, we will delete anything
3118 // make sure that you do not delete any environments
3119 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3120 !(old_cursor.row()->previous()
3121 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3122 && !(old_cursor.row()->next()
3123 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3124 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3125 && ((old_cursor.row()->previous()
3126 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3127 || (old_cursor.row()->next()
3128 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3130 status = LyXText::NEED_MORE_REFRESH;
3133 if (old_cursor.row()->previous()) {
3134 refresh_row = old_cursor.row()->previous();
3135 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3137 cursor = old_cursor; // that undo can restore the right cursor position
3138 LyXParagraph * endpar = old_cursor.par()->next;
3139 if (endpar && endpar->GetDepth()) {
3140 while (endpar && endpar->GetDepth()) {
3141 endpar = endpar->LastPhysicalPar()->Next();
3144 SetUndo(bview->buffer(), Undo::DELETE,
3145 old_cursor.par()->previous,
3150 RemoveRow(old_cursor.row());
3151 if (OwnerParagraph() == old_cursor.par()) {
3152 OwnerParagraph(OwnerParagraph()->next);
3155 delete old_cursor.par();
3157 /* Breakagain the next par. Needed
3158 * because of the parindent that
3159 * can occur or dissappear. The
3160 * next row can change its height,
3161 * if there is another layout before */
3162 if (refresh_row->next()) {
3163 BreakAgain(bview, refresh_row->next());
3164 UpdateCounters(bview, refresh_row);
3166 SetHeightOfRow(bview, refresh_row);
3168 refresh_row = old_cursor.row()->next();
3169 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3172 cursor = old_cursor; // that undo can restore the right cursor position
3173 LyXParagraph * endpar = old_cursor.par()->next;
3174 if (endpar && endpar->GetDepth()) {
3175 while (endpar && endpar->GetDepth()) {
3176 endpar = endpar->LastPhysicalPar()->Next();
3179 SetUndo(bview->buffer(), Undo::DELETE,
3180 old_cursor.par()->previous,
3185 RemoveRow(old_cursor.row());
3187 if (OwnerParagraph() == old_cursor.par()) {
3188 OwnerParagraph(OwnerParagraph()->next);
3190 delete old_cursor.par();
3192 /* Breakagain the next par. Needed
3193 because of the parindent that can
3194 occur or dissappear.
3195 The next row can change its height,
3196 if there is another layout before
3199 BreakAgain(bview, refresh_row);
3200 UpdateCounters(bview, refresh_row->previous());
3206 SetCursorIntern(bview, cursor.par(), cursor.pos());
3208 if (sel_cursor.par() == old_cursor.par()
3209 && sel_cursor.pos() == sel_cursor.pos()) {
3210 // correct selection
3211 sel_cursor = cursor;
3216 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3217 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3219 SetCursorIntern(bview, cursor.par(), cursor.pos());
3220 sel_cursor = cursor;
3227 LyXParagraph * LyXText::GetParFromID(int id)
3229 LyXParagraph * result = FirstParagraph();
3230 while (result && result->id() != id)
3231 result = result->next;
3237 bool LyXText::TextUndo(BufferView * bview)
3241 // returns false if no undo possible
3242 Undo * undo = bview->buffer()->undostack.pop();
3246 bview->buffer()->redostack
3247 .push(CreateUndo(bview->buffer(), undo->kind,
3248 GetParFromID(undo->number_of_before_par),
3249 GetParFromID(undo->number_of_behind_par)));
3251 return TextHandleUndo(bview, undo);
3255 bool LyXText::TextRedo(BufferView * bview)
3259 // returns false if no redo possible
3260 Undo * undo = bview->buffer()->redostack.pop();
3264 bview->buffer()->undostack
3265 .push(CreateUndo(bview->buffer(), undo->kind,
3266 GetParFromID(undo->number_of_before_par),
3267 GetParFromID(undo->number_of_behind_par)));
3269 return TextHandleUndo(bview, undo);
3273 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3277 // returns false if no undo possible
3278 bool result = false;
3280 LyXParagraph * before =
3281 GetParFromID(undo->number_of_before_par);
3282 LyXParagraph * behind =
3283 GetParFromID(undo->number_of_behind_par);
3284 LyXParagraph * tmppar;
3285 LyXParagraph * tmppar2;
3286 LyXParagraph * endpar;
3287 LyXParagraph * tmppar5;
3289 // if there's no before take the beginning
3290 // of the document for redoing
3292 SetCursorIntern(bview, FirstParagraph(), 0);
3294 // replace the paragraphs with the undo informations
3296 LyXParagraph * tmppar3 = undo->par;
3297 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3298 LyXParagraph * tmppar4 = tmppar3;
3300 while (tmppar4->next)
3301 tmppar4 = tmppar4->next;
3302 } // get last undo par
3304 // now remove the old text if there is any
3305 if (before != behind || (!behind && !before)){
3307 tmppar5 = before->next;
3309 tmppar5 = OwnerParagraph();
3311 while (tmppar5 && tmppar5 != behind){
3313 tmppar5 = tmppar5->next;
3314 // a memory optimization for edit: Only layout information
3315 // is stored in the undo. So restore the text informations.
3316 if (undo->kind == Undo::EDIT) {
3317 tmppar2->setContentsFromPar(tmppar);
3318 tmppar->clearContents();
3319 tmppar2 = tmppar2->next;
3324 // put the new stuff in the list if there is one
3327 before->next = tmppar3;
3329 OwnerParagraph(tmppar3);
3330 tmppar3->previous = before;
3334 OwnerParagraph(behind);
3337 tmppar4->next = behind;
3339 behind->previous = tmppar4;
3343 // Set the cursor for redoing
3345 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3346 // check wether before points to a closed float and open it if necessary
3347 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3348 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3350 while (tmppar4->previous &&
3351 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3352 tmppar4 = tmppar4->previous;
3353 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3354 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3355 tmppar4 = tmppar4->next;
3360 // open a cosed footnote at the end if necessary
3361 if (behind && behind->previous &&
3362 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3363 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3364 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3365 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3366 behind = behind->next;
3370 // calculate the endpar for redoing the paragraphs.
3372 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3373 endpar = behind->LastPhysicalPar()->Next();
3375 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3379 tmppar = GetParFromID(undo->number_of_cursor_par);
3380 RedoParagraphs(bview, cursor, endpar);
3382 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3383 UpdateCounters(bview, cursor.row());
3393 void LyXText::FinishUndo()
3397 // makes sure the next operation will be stored
3398 undo_finished = true;
3402 void LyXText::FreezeUndo()
3406 // this is dangerous and for internal use only
3411 void LyXText::UnFreezeUndo()
3415 // this is dangerous and for internal use only
3416 undo_frozen = false;
3420 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3421 LyXParagraph const * before,
3422 LyXParagraph const * behind) const
3427 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3428 buf->redostack.clear();
3432 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3433 LyXParagraph const * before, LyXParagraph const * behind)
3437 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3441 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3442 LyXParagraph const * before,
3443 LyXParagraph const * behind) const
3448 int before_number = -1;
3449 int behind_number = -1;
3451 before_number = before->id();
3453 behind_number = behind->id();
3454 // Undo::EDIT and Undo::FINISH are
3455 // always finished. (no overlapping there)
3456 // overlapping only with insert and delete inside one paragraph:
3457 // Nobody wants all removed character
3458 // appear one by one when undoing.
3459 // EDIT is special since only layout information, not the
3460 // contents of a paragaph are stored.
3461 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3462 // check wether storing is needed
3463 if (!buf->undostack.empty() &&
3464 buf->undostack.top()->kind == kind &&
3465 buf->undostack.top()->number_of_before_par == before_number &&
3466 buf->undostack.top()->number_of_behind_par == behind_number ){
3471 // create a new Undo
3472 LyXParagraph * undopar;
3473 LyXParagraph * tmppar;
3474 LyXParagraph * tmppar2;
3476 LyXParagraph * start = 0;
3477 LyXParagraph * end = 0;
3480 start = before->next;
3482 start = FirstParagraph();
3484 end = behind->previous;
3486 end = FirstParagraph();
3492 && start != end->next
3493 && (before != behind || (!before && !behind))) {
3495 tmppar2 = tmppar->Clone();
3496 tmppar2->id(tmppar->id());
3498 // a memory optimization: Just store the layout information
3500 if (kind == Undo::EDIT){
3501 //tmppar2->text.clear();
3502 tmppar2->clearContents();
3507 while (tmppar != end && tmppar->next) {
3508 tmppar = tmppar->next;
3509 tmppar2->next = tmppar->Clone();
3510 tmppar2->next->id(tmppar->id());
3511 // a memory optimization: Just store the layout
3512 // information when only edit
3513 if (kind == Undo::EDIT){
3514 //tmppar2->next->text.clear();
3515 tmppar2->clearContents();
3517 tmppar2->next->previous = tmppar2;
3518 tmppar2 = tmppar2->next;
3522 undopar = 0; // nothing to replace (undo of delete maybe)
3524 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3525 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3527 Undo * undo = new Undo(kind,
3528 before_number, behind_number,
3529 cursor_par, cursor_pos,
3532 undo_finished = false;
3537 void LyXText::SetCursorParUndo(Buffer * buf)
3541 SetUndo(buf, Undo::FINISH,
3542 cursor.par()->ParFromPos(cursor.pos())->previous,
3543 cursor.par()->ParFromPos(cursor.pos())->next);
3548 void LyXText::RemoveTableRow(LyXCursor & cur) const
3554 // move to the previous row
3555 int cell_act = NumberOfCell(cur.par(), cur.pos());
3558 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3559 cur.pos(cur.pos() - 1);
3561 !cur.par()->table->IsFirstCell(cell_act)) {
3562 cur.pos(cur.pos() - 1);
3563 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3564 cur.pos(cur.pos() - 1);
3568 // now we have to pay attention if the actual table is the
3569 // main row of TableContRows and if yes to delete all of them
3574 // delete up to the next row
3575 while (cur.pos() < cur.par()->Last() &&
3577 || !cur.par()->table->IsFirstCell(cell_act))) {
3578 while (cur.pos() < cur.par()->Last() &&
3579 !cur.par()->IsNewline(cur.pos()))
3580 cur.par()->Erase(cur.pos());
3583 if (cur.pos() < cur.par()->Last())
3584 cur.par()->Erase(cur.pos());
3586 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3587 cur.pos(cur.pos() - 1);
3588 cur.par()->Erase(cur.pos()); // no newline at very end!
3590 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3591 !cur.par()->table->IsContRow(cell_org) &&
3592 cur.par()->table->IsContRow(cell));
3593 cur.par()->table->DeleteRow(cell_org);
3600 bool LyXText::IsEmptyTableCell() const
3602 LyXParagraph::size_type pos = cursor.pos() - 1;
3603 while (pos >= 0 && pos < cursor.par()->Last()
3604 && !cursor.par()->IsNewline(pos))
3606 return cursor.par()->IsNewline(pos + 1);
3611 void LyXText::toggleAppendix(BufferView * bview)
3613 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3614 bool start = !par->start_of_appendix;
3616 // ensure that we have only one start_of_appendix in this document
3617 LyXParagraph * tmp = FirstParagraph();
3618 for (; tmp; tmp = tmp->next)
3619 tmp->start_of_appendix = 0;
3620 par->start_of_appendix = start;
3622 // we can set the refreshing parameters now
3623 status = LyXText::NEED_MORE_REFRESH;
3625 refresh_row = 0; // not needed for full update
3626 UpdateCounters(bview, 0);
3627 SetCursor(bview, cursor.par(), cursor.pos());
3630 LyXParagraph * LyXText::OwnerParagraph() const
3633 return inset_owner->par;
3635 return bv_owner->buffer()->paragraph;
3639 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3642 inset_owner->par = p;
3644 bv_owner->buffer()->paragraph = p;