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);
136 // Dump all rowinformation:
137 Row * tmprow = firstrow;
138 lyxerr << "Width = " << width << endl;
139 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
141 lyxerr << tmprow->baseline() << '\t'
142 << tmprow->par() << '\t'
143 << tmprow->pos() << '\t'
144 << tmprow->height() << '\t'
145 << tmprow->ascent_of_text() << '\t'
146 << tmprow->fill() << '\n';
147 tmprow = tmprow->next();
155 // Delete all rows, this does not touch the paragraphs!
156 Row * tmprow = firstrow;
158 tmprow = firstrow->next();
165 // Gets the fully instantiated font at a given position in a paragraph
166 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
167 // The difference is that this one is used for displaying, and thus we
168 // are allowed to make cosmetic improvements. For instance make footnotes
170 // If position is -1, we get the layout font of the paragraph.
171 // If position is -2, we get the font of the manual label of the paragraph.
172 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
173 LyXParagraph::size_type pos) const
175 LyXLayout const & layout =
176 textclasslist.Style(buf->params.textclass, par->GetLayout());
178 char par_depth = par->GetDepth();
179 // We specialize the 95% common case:
180 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
183 if (layout.labeltype == LABEL_MANUAL
184 && pos < BeginningOfMainBody(buf, par)) {
186 return par->GetFontSettings(buf->params, pos).
187 realize(layout.reslabelfont);
189 return par->GetFontSettings(buf->params, pos).
190 realize(layout.resfont);
193 // process layoutfont for pos == -1 and labelfont for pos < -1
195 return layout.resfont;
197 return layout.reslabelfont;
201 // The uncommon case need not be optimized as much
203 LyXFont layoutfont, tmpfont;
207 if (pos < BeginningOfMainBody(buf, par)) {
209 layoutfont = layout.labelfont;
212 layoutfont = layout.font;
214 tmpfont = par->GetFontSettings(buf->params, pos);
215 tmpfont.realize(layoutfont);
218 // process layoutfont for pos == -1 and labelfont for pos < -1
220 tmpfont = layout.font;
222 tmpfont = layout.labelfont;
225 // Resolve against environment font information
226 while (par && par_depth && !tmpfont.resolved()) {
227 par = par->DepthHook(par_depth - 1);
229 tmpfont.realize(textclasslist.
230 Style(buf->params.textclass,
231 par->GetLayout()).font);
232 par_depth = par->GetDepth();
236 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
239 // Cosmetic improvement: If this is an open footnote, make the font
241 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
242 && par->footnotekind == LyXParagraph::FOOTNOTE) {
250 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
251 LyXParagraph::size_type pos,
255 // Let the insets convert their font
256 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
257 if (par->GetInset(pos))
258 font = par->GetInset(pos)->ConvertFont(font);
261 LyXLayout const & layout =
262 textclasslist.Style(buf->params.textclass,
265 // Get concrete layout font to reduce against
268 if (pos < BeginningOfMainBody(buf, par))
269 layoutfont = layout.labelfont;
271 layoutfont = layout.font;
273 // Realize against environment font information
274 if (par->GetDepth()){
275 LyXParagraph * tp = par;
276 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
277 tp = tp->DepthHook(tp->GetDepth()-1);
279 layoutfont.realize(textclasslist.
280 Style(buf->params.textclass,
281 tp->GetLayout()).font);
285 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
288 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
289 && par->footnotekind == LyXParagraph::FOOTNOTE) {
290 layoutfont.decSize();
293 // Now, reduce font against full layout font
294 font.reduce(layoutfont);
296 par->SetFont(pos, font);
300 /* inserts a new row behind the specified row, increments
301 * the touched counters */
302 void LyXText::InsertRow(Row * row, LyXParagraph * par,
303 LyXParagraph::size_type pos) const
305 Row * tmprow = new Row;
308 tmprow->next(firstrow);
311 tmprow->previous(row);
312 tmprow->next(row->next());
317 tmprow->next()->previous(tmprow);
319 if (tmprow->previous())
320 tmprow->previous()->next(tmprow);
328 ++number_of_rows; // one more row
332 // removes the row and reset the touched counters
333 void LyXText::RemoveRow(Row * row) const
335 /* this must not happen before the currentrow for clear reasons.
336 so the trick is just to set the current row onto the previous
339 GetRow(row->par(), row->pos(), unused_y);
342 row->next()->previous(row->previous());
343 if (!row->previous()) {
344 firstrow = row->next();
346 row->previous()->next(row->next());
349 lastrow = row->previous();
351 height -= row->height(); // the text becomes smaller
354 --number_of_rows; // one row less
358 // remove all following rows of the paragraph of the specified row.
359 void LyXText::RemoveParagraph(Row * row) const
361 LyXParagraph * tmppar = row->par();
365 while (row && row->par() == tmppar) {
366 tmprow = row->next();
373 // insert the specified paragraph behind the specified row
374 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
377 InsertRow(row, par, 0); /* insert a new row, starting
380 SetCounter(bview->buffer(), par); // set the counters
382 // and now append the whole paragraph behind the new row
385 AppendParagraph(bview, firstrow);
387 row->next()->height(0);
388 AppendParagraph(bview, row->next());
394 void LyXText::ToggleFootnote(BufferView * bview)
396 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
398 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
400 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
402 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
403 CloseFootnote(bview);
409 void LyXText::OpenStuff(BufferView * bview)
411 if (cursor.pos() == 0 && cursor.par()->bibkey){
412 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
414 else if (cursor.pos() < cursor.par()->Last()
415 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
416 && cursor.par()->GetInset(cursor.pos())->Editable()) {
417 bview->owner()->getMiniBuffer()
418 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
419 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
420 SetCursorParUndo(bview->buffer());
421 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
423 ToggleFootnote(bview);
429 void LyXText::CloseFootnote(BufferView * bview)
431 LyXParagraph * tmppar;
432 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
434 // if the cursor is not in an open footnote, or
435 // there is no open footnote in this paragraph, just return.
436 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
439 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
440 bview->owner()->getMiniBuffer()
441 ->Set(_("Nothing to do"));
445 // ok, move the cursor right before the footnote
446 // just a little faster than using CursorRight()
448 cursor.par()->ParFromPos(cursor.pos()) != par;) {
449 cursor.pos(cursor.pos() + 1);
452 // now the cursor is at the beginning of the physical par
453 SetCursor(bview, cursor.par(),
455 cursor.par()->ParFromPos(cursor.pos())->size());
457 /* we are in a footnote, so let us move at the beginning */
458 /* this is just faster than using just CursorLeft() */
460 tmppar = cursor.par();
461 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
462 // just a little bit faster than movin the cursor
463 tmppar = tmppar->Previous();
465 SetCursor(bview, tmppar, tmppar->Last());
468 // the cursor must be exactly before the footnote
469 par = cursor.par()->ParFromPos(cursor.pos());
471 status = LyXText::NEED_MORE_REFRESH;
472 refresh_row = cursor.row();
473 refresh_y = cursor.y() - cursor.row()->baseline();
475 tmppar = cursor.par();
476 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
477 Row * row = cursor.row();
479 tmppar->CloseFootnote(cursor.pos());
481 while (tmppar != endpar) {
482 RemoveRow(row->next());
484 tmppar = row->next()->par();
489 AppendParagraph(bview, cursor.row());
491 SetCursor(bview, cursor.par(), cursor.pos());
495 if (cursor.row()->next())
496 SetHeightOfRow(bview, cursor.row()->next());
501 /* used in setlayout */
502 // Asger is not sure we want to do this...
503 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
507 LyXLayout const & layout =
508 textclasslist.Style(buf->params.textclass, par->GetLayout());
510 LyXFont layoutfont, tmpfont;
511 for (LyXParagraph::size_type pos = 0;
512 pos < par->Last(); ++pos) {
513 if (pos < BeginningOfMainBody(buf, par))
514 layoutfont = layout.labelfont;
516 layoutfont = layout.font;
518 tmpfont = par->GetFontSettings(buf->params, pos);
519 tmpfont.reduce(layoutfont);
520 par->SetFont(pos, tmpfont);
525 LyXParagraph * LyXText::SetLayout(BufferView * bview,
526 LyXCursor & cur, LyXCursor & sstart_cur,
527 LyXCursor & send_cur,
528 LyXTextClass::size_type layout)
530 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
531 LyXParagraph * undoendpar = endpar;
533 if (endpar && endpar->GetDepth()) {
534 while (endpar && endpar->GetDepth()) {
535 endpar = endpar->LastPhysicalPar()->Next();
539 endpar = endpar->Next(); // because of parindents etc.
542 SetUndo(bview->buffer(), Undo::EDIT,
543 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
546 /* ok we have a selection. This is always between sstart_cur
547 * and sel_end cursor */
550 LyXLayout const & lyxlayout =
551 textclasslist.Style(bview->buffer()->params.textclass, layout);
553 while (cur.par() != send_cur.par()) {
554 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
555 cur.par()->SetLayout(bview->buffer()->params, layout);
556 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
557 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
558 fppar->added_space_top = lyxlayout.fill_top ?
559 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
560 fppar->added_space_bottom = lyxlayout.fill_bottom ?
561 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
562 if (lyxlayout.margintype == MARGIN_MANUAL)
563 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
564 if (lyxlayout.labeltype != LABEL_BIBLIO
566 delete fppar->bibkey;
570 cur.par(cur.par()->Next());
572 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
573 cur.par()->SetLayout(bview->buffer()->params, layout);
574 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
575 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
576 fppar->added_space_top = lyxlayout.fill_top ?
577 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
578 fppar->added_space_bottom = lyxlayout.fill_bottom ?
579 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
580 if (lyxlayout.margintype == MARGIN_MANUAL)
581 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
582 if (lyxlayout.labeltype != LABEL_BIBLIO
584 delete fppar->bibkey;
591 // set layout over selection and make a total rebreak of those paragraphs
592 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
595 tmpcursor = cursor; /* store the current cursor */
597 #ifdef USE_OLD_SET_LAYOUT
598 // if there is no selection just set the layout
599 // of the current paragraph */
601 sel_start_cursor = cursor; // dummy selection
602 sel_end_cursor = cursor;
605 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
606 LyXParagraph * undoendpar = endpar;
608 if (endpar && endpar->GetDepth()) {
609 while (endpar && endpar->GetDepth()) {
610 endpar = endpar->LastPhysicalPar()->Next();
615 endpar = endpar->Next(); // because of parindents etc.
619 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
622 /* ok we have a selection. This is always between sel_start_cursor
623 * and sel_end cursor */
624 cursor = sel_start_cursor;
626 LyXLayout const & lyxlayout =
627 textclasslist.Style(bview->buffer()->params.textclass, layout);
629 while (cursor.par() != sel_end_cursor.par()) {
630 if (cursor.par()->footnoteflag ==
631 sel_start_cursor.par()->footnoteflag) {
632 cursor.par()->SetLayout(layout);
633 MakeFontEntriesLayoutSpecific(cursor.par());
634 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
635 fppar->added_space_top = lyxlayout.fill_top ?
636 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
637 fppar->added_space_bottom = lyxlayout.fill_bottom ?
638 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
639 if (lyxlayout.margintype == MARGIN_MANUAL)
640 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
641 if (lyxlayout.labeltype != LABEL_BIBLIO
643 delete fppar->bibkey;
647 cursor.par() = cursor.par()->Next();
649 if (cursor.par()->footnoteflag ==
650 sel_start_cursor.par()->footnoteflag) {
651 cursor.par()->SetLayout(layout);
652 MakeFontEntriesLayoutSpecific(cursor.par());
653 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
654 fppar->added_space_top = lyxlayout.fill_top ?
655 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
656 fppar->added_space_bottom = lyxlayout.fill_bottom ?
657 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
658 if (lyxlayout.margintype == MARGIN_MANUAL)
659 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
660 if (lyxlayout.labeltype != LABEL_BIBLIO
662 delete fppar->bibkey;
667 // if there is no selection just set the layout
668 // of the current paragraph */
670 sel_start_cursor = cursor; // dummy selection
671 sel_end_cursor = cursor;
674 endpar = SetLayout(bview, cursor, sel_start_cursor,
675 sel_end_cursor, layout);
677 RedoParagraphs(bview, sel_start_cursor, endpar);
679 // we have to reset the selection, because the
680 // geometry could have changed */
681 SetCursor(bview, sel_start_cursor.par(),
682 sel_start_cursor.pos(), false);
684 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
686 UpdateCounters(bview, cursor.row());
689 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
693 // increment depth over selection and
694 // make a total rebreak of those paragraphs
695 void LyXText::IncDepth(BufferView * bview)
697 // If there is no selection, just use the current paragraph
699 sel_start_cursor = cursor; // dummy selection
700 sel_end_cursor = cursor;
703 // We end at the next paragraph with depth 0
704 LyXParagraph * endpar =
705 sel_end_cursor.par()->LastPhysicalPar()->Next();
706 LyXParagraph * undoendpar = endpar;
708 if (endpar && endpar->GetDepth()) {
709 while (endpar && endpar->GetDepth()) {
710 endpar = endpar->LastPhysicalPar()->Next();
715 endpar = endpar->Next(); // because of parindents etc.
718 SetUndo(bview->buffer(), Undo::EDIT,
720 .par()->ParFromPos(sel_start_cursor.pos())->previous,
723 LyXCursor tmpcursor = cursor; // store the current cursor
725 // ok we have a selection. This is always between sel_start_cursor
726 // and sel_end cursor
727 cursor = sel_start_cursor;
729 bool anything_changed = false;
732 // NOTE: you can't change the depth of a bibliography entry
733 if (cursor.par()->footnoteflag ==
734 sel_start_cursor.par()->footnoteflag
735 && textclasslist.Style(bview->buffer()->params.textclass,
736 cursor.par()->GetLayout()
737 ).labeltype != LABEL_BIBLIO) {
738 LyXParagraph * prev =
739 cursor.par()->FirstPhysicalPar()->Previous();
741 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
742 || (prev->GetDepth() == cursor.par()->GetDepth()
743 && textclasslist.Style(bview->buffer()->params.textclass,
744 prev->GetLayout()).isEnvironment()))) {
745 cursor.par()->FirstPhysicalPar()->depth++;
746 anything_changed = true;
749 if (cursor.par() == sel_end_cursor.par())
751 cursor.par(cursor.par()->Next());
754 // if nothing changed set all depth to 0
755 if (!anything_changed) {
756 cursor = sel_start_cursor;
757 while (cursor.par() != sel_end_cursor.par()) {
758 cursor.par()->FirstPhysicalPar()->depth = 0;
759 cursor.par(cursor.par()->Next());
761 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
762 cursor.par()->FirstPhysicalPar()->depth = 0;
765 RedoParagraphs(bview, sel_start_cursor, endpar);
767 // we have to reset the selection, because the
768 // geometry could have changed
769 SetCursor(bview, sel_start_cursor.par(),
770 sel_start_cursor.pos());
772 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
773 UpdateCounters(bview, cursor.row());
776 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
780 // decrement depth over selection and
781 // make a total rebreak of those paragraphs
782 void LyXText::DecDepth(BufferView * bview)
784 // if there is no selection just set the layout
785 // of the current paragraph
787 sel_start_cursor = cursor; // dummy selection
788 sel_end_cursor = cursor;
791 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
792 LyXParagraph * undoendpar = endpar;
794 if (endpar && endpar->GetDepth()) {
795 while (endpar && endpar->GetDepth()) {
796 endpar = endpar->LastPhysicalPar()->Next();
801 endpar = endpar->Next(); // because of parindents etc.
804 SetUndo(bview->buffer(), Undo::EDIT,
806 .par()->ParFromPos(sel_start_cursor.pos())->previous,
809 LyXCursor tmpcursor = cursor; // store the current cursor
811 // ok we have a selection. This is always between sel_start_cursor
812 // and sel_end cursor
813 cursor = sel_start_cursor;
816 if (cursor.par()->footnoteflag ==
817 sel_start_cursor.par()->footnoteflag) {
818 if (cursor.par()->FirstPhysicalPar()->depth)
819 cursor.par()->FirstPhysicalPar()->depth--;
821 if (cursor.par() == sel_end_cursor.par())
823 cursor.par(cursor.par()->Next());
826 RedoParagraphs(bview, sel_start_cursor, endpar);
828 // we have to reset the selection, because the
829 // geometry could have changed
830 SetCursor(bview, sel_start_cursor.par(),
831 sel_start_cursor.pos());
833 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
834 UpdateCounters(bview, cursor.row());
837 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
841 // set font over selection and make a total rebreak of those paragraphs
842 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
844 // if there is no selection just set the current_font
846 // Determine basis font
848 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
850 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
852 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
853 // Update current font
854 real_current_font.update(font,
855 bview->buffer()->params.language_info,
858 // Reduce to implicit settings
859 current_font = real_current_font;
860 current_font.reduce(layoutfont);
861 // And resolve it completely
862 real_current_font.realize(layoutfont);
866 LyXCursor tmpcursor = cursor; // store the current cursor
868 // ok we have a selection. This is always between sel_start_cursor
869 // and sel_end cursor
871 SetUndo(bview->buffer(), Undo::EDIT,
872 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
873 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
874 cursor = sel_start_cursor;
875 while (cursor.par() != sel_end_cursor.par() ||
876 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
877 && cursor.pos() < sel_end_cursor.pos()))
879 if (cursor.pos() < cursor.par()->Last()
880 && cursor.par()->footnoteflag
881 == sel_start_cursor.par()->footnoteflag) {
882 // an open footnote should behave
884 LyXFont newfont = GetFont(bview->buffer(),
885 cursor.par(), cursor.pos());
887 bview->buffer()->params.language_info,
889 SetCharFont(bview->buffer(),
890 cursor.par(), cursor.pos(), newfont);
891 cursor.pos(cursor.pos() + 1);
894 cursor.par(cursor.par()->Next());
898 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
900 // we have to reset the selection, because the
901 // geometry could have changed
902 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
904 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
907 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
908 tmpcursor.boundary());
912 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
914 Row * tmprow = cur.row();
915 long y = cur.y() - tmprow->baseline();
917 SetHeightOfRow(bview, tmprow);
918 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
919 // find the first row of the paragraph
920 if (first_phys_par != tmprow->par())
921 while (tmprow->previous()
922 && tmprow->previous()->par() != first_phys_par) {
923 tmprow = tmprow->previous();
924 y -= tmprow->height();
925 SetHeightOfRow(bview, tmprow);
927 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
928 tmprow = tmprow->previous();
929 y -= tmprow->height();
930 SetHeightOfRow(bview, tmprow);
933 // we can set the refreshing parameters now
934 status = LyXText::NEED_MORE_REFRESH;
936 refresh_row = tmprow;
937 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
941 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
943 Row * tmprow = cur.row();
945 long y = cur.y() - tmprow->baseline();
946 SetHeightOfRow(bview, tmprow);
947 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
948 // find the first row of the paragraph
949 if (first_phys_par != tmprow->par())
950 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
951 tmprow = tmprow->previous();
952 y -= tmprow->height();
954 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
955 tmprow = tmprow->previous();
956 y -= tmprow->height();
959 // we can set the refreshing parameters now
960 if (status == LyXText::UNCHANGED || y < refresh_y) {
962 refresh_row = tmprow;
964 status = LyXText::NEED_MORE_REFRESH;
965 SetCursor(bview, cur.par(), cur.pos());
969 /* deletes and inserts again all paragaphs between the cursor
970 * and the specified par
971 * This function is needed after SetLayout and SetFont etc. */
972 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
973 LyXParagraph const * endpar) const
976 LyXParagraph * tmppar = 0, * first_phys_par = 0;
978 Row * tmprow = cur.row();
980 long y = cur.y() - tmprow->baseline();
982 if (!tmprow->previous()){
983 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
985 first_phys_par = tmprow->par()->FirstPhysicalPar();
986 // find the first row of the paragraph
987 if (first_phys_par != tmprow->par())
988 while (tmprow->previous() &&
989 (tmprow->previous()->par() != first_phys_par)) {
990 tmprow = tmprow->previous();
991 y -= tmprow->height();
993 while (tmprow->previous()
994 && tmprow->previous()->par() == first_phys_par) {
995 tmprow = tmprow->previous();
996 y -= tmprow->height();
1000 // we can set the refreshing parameters now
1001 status = LyXText::NEED_MORE_REFRESH;
1003 refresh_row = tmprow->previous(); /* the real refresh row will
1004 be deleted, so I store
1005 the previous here */
1008 tmppar = tmprow->next()->par();
1011 while (tmppar != endpar) {
1012 RemoveRow(tmprow->next());
1014 tmppar = tmprow->next()->par();
1019 // remove the first one
1020 tmprow2 = tmprow; /* this is because tmprow->previous()
1022 tmprow = tmprow->previous();
1025 tmppar = first_phys_par;
1029 InsertParagraph(bview, tmppar, tmprow);
1032 while (tmprow->next() && tmprow->next()->par() == tmppar)
1033 tmprow = tmprow->next();
1034 tmppar = tmppar->Next();
1036 } while (tmppar != endpar);
1038 // this is because of layout changes
1040 refresh_y -= refresh_row->height();
1041 SetHeightOfRow(bview, refresh_row);
1043 refresh_row = firstrow;
1045 SetHeightOfRow(bview, refresh_row);
1048 if (tmprow && tmprow->next())
1049 SetHeightOfRow(bview, tmprow->next());
1053 bool LyXText::FullRebreak(BufferView * bview)
1059 if (need_break_row) {
1060 BreakAgain(bview, need_break_row);
1068 /* important for the screen */
1071 /* the cursor set functions have a special mechanism. When they
1072 * realize, that you left an empty paragraph, they will delete it.
1073 * They also delete the corresponding row */
1075 // need the selection cursor:
1076 void LyXText::SetSelection()
1079 last_sel_cursor = sel_cursor;
1080 sel_start_cursor = sel_cursor;
1081 sel_end_cursor = sel_cursor;
1086 // first the toggling area
1087 if (cursor.y() < last_sel_cursor.y()
1088 || (cursor.y() == last_sel_cursor.y()
1089 && cursor.x() < last_sel_cursor.x())) {
1090 toggle_end_cursor = last_sel_cursor;
1091 toggle_cursor = cursor;
1093 toggle_end_cursor = cursor;
1094 toggle_cursor = last_sel_cursor;
1097 last_sel_cursor = cursor;
1099 // and now the whole selection
1101 if (sel_cursor.par() == cursor.par())
1102 if (sel_cursor.pos() < cursor.pos()) {
1103 sel_end_cursor = cursor;
1104 sel_start_cursor = sel_cursor;
1106 sel_end_cursor = sel_cursor;
1107 sel_start_cursor = cursor;
1109 else if (sel_cursor.y() < cursor.y() ||
1110 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1111 sel_end_cursor = cursor;
1112 sel_start_cursor = sel_cursor;
1115 sel_end_cursor = sel_cursor;
1116 sel_start_cursor = cursor;
1119 // a selection with no contents is not a selection
1120 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1121 sel_start_cursor.pos() == sel_end_cursor.pos())
1126 string LyXText::selectionAsString(Buffer const * buffer) const
1128 if (!selection) return string();
1131 // Special handling if the whole selection is within one paragraph
1132 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1133 result += sel_start_cursor.par()->String(buffer,
1134 sel_start_cursor.pos(),
1135 sel_end_cursor.pos());
1139 // The selection spans more than one paragraph
1141 // First paragraph in selection
1142 result += sel_start_cursor.par()->String(buffer,
1143 sel_start_cursor.pos(),
1144 sel_start_cursor.par()->Last())
1147 // The paragraphs in between (if any)
1148 LyXCursor tmpcur(sel_start_cursor);
1149 tmpcur.par(tmpcur.par()->Next());
1150 while (tmpcur.par() != sel_end_cursor.par()) {
1151 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1152 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1155 // Last paragraph in selection
1156 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1162 void LyXText::ClearSelection() const
1169 void LyXText::CursorHome(BufferView * bview) const
1171 SetCursor(bview, cursor.par(), cursor.row()->pos());
1175 void LyXText::CursorEnd(BufferView * bview) const
1177 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1178 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1180 if (cursor.par()->Last() &&
1181 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1182 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1183 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1185 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1188 if (cursor.par()->table) {
1189 int cell = NumberOfCell(cursor.par(), cursor.pos());
1190 if (cursor.par()->table->RowHasContRow(cell) &&
1191 cursor.par()->table->CellHasContRow(cell)<0) {
1192 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1193 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1195 if (cursor.par()->Last() &&
1196 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1197 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1198 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1200 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1208 void LyXText::CursorTop(BufferView * bview) const
1210 while (cursor.par()->Previous())
1211 cursor.par(cursor.par()->Previous());
1212 SetCursor(bview, cursor.par(), 0);
1216 void LyXText::CursorBottom(BufferView * bview) const
1218 while (cursor.par()->Next())
1219 cursor.par(cursor.par()->Next());
1220 SetCursor(bview, cursor.par(), cursor.par()->Last());
1224 /* returns a pointer to the row near the specified y-coordinate
1225 * (relative to the whole text). y is set to the real beginning
1227 Row * LyXText::GetRowNearY(long & y) const
1229 Row * tmprow = firstrow;
1232 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1233 tmpy += tmprow->height();
1234 tmprow = tmprow->next();
1237 y = tmpy; // return the real y
1242 void LyXText::ToggleFree(BufferView * bview,
1243 LyXFont const & font, bool toggleall)
1245 // If the mask is completely neutral, tell user
1246 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1247 // Could only happen with user style
1248 bview->owner()->getMiniBuffer()
1249 ->Set(_("No font change defined. Use Character under"
1250 " the Layout menu to define font change."));
1254 // Try implicit word selection
1255 // If there is a change in the language the implicit word selection
1257 LyXCursor resetCursor = cursor;
1258 bool implicitSelection = (font.language() == ignore_language)
1259 ? SelectWordWhenUnderCursor(bview) : false;
1262 SetFont(bview, font, toggleall);
1264 /* Implicit selections are cleared afterwards and cursor is set to the
1265 original position. */
1266 if (implicitSelection) {
1268 cursor = resetCursor;
1269 SetCursor(bview, cursor.par(), cursor.pos());
1270 sel_cursor = cursor;
1275 LyXParagraph::size_type
1276 LyXText::BeginningOfMainBody(Buffer const * buf,
1277 LyXParagraph const * par) const
1279 if (textclasslist.Style(buf->params.textclass,
1280 par->GetLayout()).labeltype != LABEL_MANUAL)
1283 return par->BeginningOfMainBody();
1288 /* if there is a selection, reset every environment you can find
1289 * in the selection, otherwise just the environment you are in */
1290 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1292 LyXParagraph * tmppar, * firsttmppar;
1296 /* is is only allowed, if the cursor is IN an open footnote.
1297 * Otherwise it is too dangerous */
1298 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1301 SetUndo(bview->buffer(), Undo::FINISH,
1302 cursor.par()->PreviousBeforeFootnote()->previous,
1303 cursor.par()->NextAfterFootnote()->next);
1305 /* ok, move to the beginning of the footnote. */
1306 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1307 cursor.par(cursor.par()->Previous());
1309 SetCursor(bview, cursor.par(), cursor.par()->Last());
1310 /* this is just faster than using CursorLeft(); */
1312 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1313 tmppar = firsttmppar;
1314 /* tmppar is now the paragraph right before the footnote */
1316 bool first_footnote_par_is_not_empty = tmppar->next->size();
1319 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1320 tmppar = tmppar->next; /* I use next instead of Next(),
1321 * because there cannot be any
1322 * footnotes in a footnote
1324 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1326 /* remember the captions and empty paragraphs */
1327 if ((textclasslist.Style(bview->buffer()->params.textclass,
1328 tmppar->GetLayout())
1329 .labeltype == LABEL_SENSITIVE)
1331 tmppar->SetLayout(bview->buffer()->params, 0);
1334 // now we will paste the ex-footnote, if the layouts allow it
1335 // first restore the layout of the paragraph right behind
1338 tmppar->next->MakeSameLayout(cursor.par());
1341 if ((!tmppar->GetLayout() && !tmppar->table)
1343 && (!tmppar->Next()->Last()
1344 || tmppar->Next()->HasSameLayout(tmppar)))) {
1345 if (tmppar->Next()->Last()
1346 && tmppar->Next()->IsLineSeparator(0))
1347 tmppar->Next()->Erase(0);
1348 tmppar->PasteParagraph(bview->buffer()->params);
1351 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1352 * by the pasting of the beginning */
1354 /* then the beginning */
1355 /* if there is no space between the text and the footnote, so we insert
1357 * (only if the previous par and the footnotepar are not empty!) */
1358 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1359 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1360 if (firsttmppar->size()
1361 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1362 && first_footnote_par_is_not_empty) {
1363 firsttmppar->next->InsertChar(0, ' ');
1365 firsttmppar->PasteParagraph(bview->buffer()->params);
1368 /* now redo the paragaphs */
1369 RedoParagraphs(bview, cursor, tmppar);
1371 SetCursor(bview, cursor.par(), cursor.pos());
1373 /* sometimes it can happen, that there is a counter change */
1374 Row * row = cursor.row();
1375 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1377 UpdateCounters(bview, row);
1385 /* the DTP switches for paragraphs. LyX will store them in the
1386 * first physicla paragraph. When a paragraph is broken, the top settings
1387 * rest, the bottom settings are given to the new one. So I can make shure,
1388 * they do not duplicate themself and you cannnot make dirty things with
1391 void LyXText::SetParagraph(BufferView * bview,
1392 bool line_top, bool line_bottom,
1393 bool pagebreak_top, bool pagebreak_bottom,
1394 VSpace const & space_top,
1395 VSpace const & space_bottom,
1397 string labelwidthstring,
1400 LyXCursor tmpcursor = cursor;
1402 sel_start_cursor = cursor;
1403 sel_end_cursor = cursor;
1406 // make sure that the depth behind the selection are restored, too
1407 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1408 LyXParagraph * undoendpar = endpar;
1410 if (endpar && endpar->GetDepth()) {
1411 while (endpar && endpar->GetDepth()) {
1412 endpar = endpar->LastPhysicalPar()->Next();
1413 undoendpar = endpar;
1417 endpar = endpar->Next(); // because of parindents etc.
1420 SetUndo(bview->buffer(), Undo::EDIT,
1422 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1426 LyXParagraph * tmppar = sel_end_cursor.par();
1427 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1428 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1429 status = LyXText::NEED_MORE_REFRESH;
1430 refresh_row = cursor.row();
1431 refresh_y = cursor.y() - cursor.row()->baseline();
1432 if (cursor.par()->footnoteflag ==
1433 sel_start_cursor.par()->footnoteflag) {
1434 cursor.par()->line_top = line_top;
1435 cursor.par()->line_bottom = line_bottom;
1436 cursor.par()->pagebreak_top = pagebreak_top;
1437 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1438 cursor.par()->added_space_top = space_top;
1439 cursor.par()->added_space_bottom = space_bottom;
1440 // does the layout allow the new alignment?
1441 if (align == LYX_ALIGN_LAYOUT)
1442 align = textclasslist
1443 .Style(bview->buffer()->params.textclass,
1444 cursor.par()->GetLayout()).align;
1445 if (align & textclasslist
1446 .Style(bview->buffer()->params.textclass,
1447 cursor.par()->GetLayout()).alignpossible) {
1448 if (align == textclasslist
1449 .Style(bview->buffer()->params.textclass,
1450 cursor.par()->GetLayout()).align)
1451 cursor.par()->align = LYX_ALIGN_LAYOUT;
1453 cursor.par()->align = align;
1455 cursor.par()->SetLabelWidthString(labelwidthstring);
1456 cursor.par()->noindent = noindent;
1459 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1462 RedoParagraphs(bview, sel_start_cursor, endpar);
1465 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1466 sel_cursor = cursor;
1467 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1469 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1473 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1475 char const * widthp,
1476 int alignment, bool hfill,
1477 bool start_minipage)
1479 LyXCursor tmpcursor = cursor;
1480 LyXParagraph * tmppar;
1482 sel_start_cursor = cursor;
1483 sel_end_cursor = cursor;
1486 // make sure that the depth behind the selection are restored, too
1487 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1488 LyXParagraph * undoendpar = endpar;
1490 if (endpar && endpar->GetDepth()) {
1491 while (endpar && endpar->GetDepth()) {
1492 endpar = endpar->LastPhysicalPar()->Next();
1493 undoendpar = endpar;
1497 endpar = endpar->Next(); // because of parindents etc.
1500 SetUndo(bview->buffer(), Undo::EDIT,
1502 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1505 tmppar = sel_end_cursor.par();
1506 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1507 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1508 status = LyXText::NEED_MORE_REFRESH;
1509 refresh_row = cursor.row();
1510 refresh_y = cursor.y() - cursor.row()->baseline();
1511 if (cursor.par()->footnoteflag ==
1512 sel_start_cursor.par()->footnoteflag) {
1513 if (type == LyXParagraph::PEXTRA_NONE) {
1514 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1515 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1516 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1519 cursor.par()->SetPExtraType(bview->buffer()->params,
1520 type, width, widthp);
1521 cursor.par()->pextra_hfill = hfill;
1522 cursor.par()->pextra_start_minipage = start_minipage;
1523 cursor.par()->pextra_alignment = alignment;
1526 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1528 RedoParagraphs(bview, sel_start_cursor, endpar);
1530 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1531 sel_cursor = cursor;
1532 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1534 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1538 char loweralphaCounter(int n)
1540 if (n < 1 || n > 26)
1546 char alphaCounter(int n)
1548 if (n < 1 || n > 26)
1554 char hebrewCounter(int n)
1556 static const char hebrew[22] = {
1557 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1558 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1559 '÷', 'ø', 'ù', 'ú'
1561 if (n < 1 || n > 22)
1567 static char const * romanCounter(int n)
1569 static char const * roman[20] = {
1570 "i", "ii", "iii", "iv", "v",
1571 "vi", "vii", "viii", "ix", "x",
1572 "xi", "xii", "xiii", "xiv", "xv",
1573 "xvi", "xvii", "xviii", "xix", "xx"
1575 if (n < 1 || n > 20)
1581 // set the counter of a paragraph. This includes the labels
1582 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1584 // this is only relevant for the beginning of paragraph
1585 par = par->FirstPhysicalPar();
1587 LyXLayout const & layout =
1588 textclasslist.Style(buf->params.textclass,
1591 LyXTextClass const & textclass =
1592 textclasslist.TextClass(buf->params.textclass);
1594 /* copy the prev-counters to this one, unless this is the start of a
1595 footnote or of a bibliography or the very first paragraph */
1597 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1598 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1599 && par->footnotekind == LyXParagraph::FOOTNOTE)
1600 && !(textclasslist.Style(buf->params.textclass,
1601 par->Previous()->GetLayout()
1602 ).labeltype != LABEL_BIBLIO
1603 && layout.labeltype == LABEL_BIBLIO)) {
1604 for (int i = 0; i < 10; ++i) {
1605 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1607 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1608 if (!par->appendix && par->start_of_appendix){
1609 par->appendix = true;
1610 for (int i = 0; i < 10; ++i) {
1611 par->setCounter(i, 0);
1614 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1615 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1618 for (int i = 0; i < 10; ++i) {
1619 par->setCounter(i, 0);
1621 par->appendix = par->start_of_appendix;
1627 // if this is an open marginnote and this is the first
1628 // entry in the marginnote and the enclosing
1629 // environment is an enum/item then correct for the
1630 // LaTeX behaviour (ARRae)
1631 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1632 && par->footnotekind == LyXParagraph::MARGIN
1634 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1635 && (par->PreviousBeforeFootnote()
1636 && textclasslist.Style(buf->params.textclass,
1637 par->PreviousBeforeFootnote()->GetLayout()
1638 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1639 // Any itemize or enumerate environment in a marginnote
1640 // that is embedded in an itemize or enumerate
1641 // paragraph is seen by LaTeX as being at a deeper
1642 // level within that enclosing itemization/enumeration
1643 // even if there is a "standard" layout at the start of
1649 /* Maybe we have to increment the enumeration depth.
1650 * BUT, enumeration in a footnote is considered in isolation from its
1651 * surrounding paragraph so don't increment if this is the
1652 * first line of the footnote
1653 * AND, bibliographies can't have their depth changed ie. they
1654 * are always of depth 0
1657 && par->Previous()->GetDepth() < par->GetDepth()
1658 && textclasslist.Style(buf->params.textclass,
1659 par->Previous()->GetLayout()
1660 ).labeltype == LABEL_COUNTER_ENUMI
1661 && par->enumdepth < 3
1662 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1663 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1664 && par->footnotekind == LyXParagraph::FOOTNOTE)
1665 && layout.labeltype != LABEL_BIBLIO) {
1669 /* Maybe we have to decrement the enumeration depth, see note above */
1671 && par->Previous()->GetDepth() > par->GetDepth()
1672 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1673 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1674 && par->footnotekind == LyXParagraph::FOOTNOTE)
1675 && layout.labeltype != LABEL_BIBLIO) {
1676 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1677 par->setCounter(6 + par->enumdepth,
1678 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1679 /* reset the counters.
1680 * A depth change is like a breaking layout
1682 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1683 par->setCounter(i, 0);
1686 if (!par->labelstring.empty()) {
1687 par->labelstring.erase();
1690 if (layout.margintype == MARGIN_MANUAL) {
1691 if (par->labelwidthstring.empty()) {
1692 par->SetLabelWidthString(layout.labelstring());
1695 par->SetLabelWidthString(string());
1698 /* is it a layout that has an automatic label ? */
1699 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1701 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1702 if (i >= 0 && i<= buf->params.secnumdepth) {
1703 par->incCounter(i); // increment the counter
1705 // Is there a label? Useful for Chapter layout
1706 if (!par->appendix){
1707 if (!layout.labelstring().empty())
1708 par->labelstring = layout.labelstring();
1710 par->labelstring.erase();
1712 if (!layout.labelstring_appendix().empty())
1713 par->labelstring = layout.labelstring_appendix();
1715 par->labelstring.erase();
1719 std::ostringstream s;
1723 if (!par->appendix) {
1724 switch (2 * LABEL_FIRST_COUNTER -
1725 textclass.maxcounter() + i) {
1726 case LABEL_COUNTER_CHAPTER:
1727 s << par->getCounter(i);
1729 case LABEL_COUNTER_SECTION:
1730 s << par->getCounter(i - 1) << '.'
1731 << par->getCounter(i);
1733 case LABEL_COUNTER_SUBSECTION:
1734 s << par->getCounter(i - 2) << '.'
1735 << par->getCounter(i - 1) << '.'
1736 << par->getCounter(i);
1738 case LABEL_COUNTER_SUBSUBSECTION:
1739 s << par->getCounter(i - 3) << '.'
1740 << par->getCounter(i - 2) << '.'
1741 << par->getCounter(i - 1) << '.'
1742 << par->getCounter(i);
1745 case LABEL_COUNTER_PARAGRAPH:
1746 s << par->getCounter(i - 4) << '.'
1747 << par->getCounter(i - 3) << '.'
1748 << par->getCounter(i - 2) << '.'
1749 << par->getCounter(i - 1) << '.'
1750 << par->getCounter(i);
1752 case LABEL_COUNTER_SUBPARAGRAPH:
1753 s << par->getCounter(i - 5) << '.'
1754 << par->getCounter(i - 4) << '.'
1755 << par->getCounter(i - 3) << '.'
1756 << par->getCounter(i - 2) << '.'
1757 << par->getCounter(i - 1) << '.'
1758 << par->getCounter(i);
1762 s << par->getCounter(i) << '.';
1765 } else { // appendix
1766 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1767 case LABEL_COUNTER_CHAPTER:
1768 if (par->isRightToLeftPar(buf->params))
1769 s << hebrewCounter(par->getCounter(i));
1771 s << alphaCounter(par->getCounter(i));
1773 case LABEL_COUNTER_SECTION:
1774 if (par->isRightToLeftPar(buf->params))
1775 s << hebrewCounter(par->getCounter(i - 1));
1777 s << alphaCounter(par->getCounter(i - 1));
1780 << par->getCounter(i);
1783 case LABEL_COUNTER_SUBSECTION:
1784 if (par->isRightToLeftPar(buf->params))
1785 s << hebrewCounter(par->getCounter(i - 2));
1787 s << alphaCounter(par->getCounter(i - 2));
1790 << par->getCounter(i-1) << '.'
1791 << par->getCounter(i);
1794 case LABEL_COUNTER_SUBSUBSECTION:
1795 if (par->isRightToLeftPar(buf->params))
1796 s << hebrewCounter(par->getCounter(i-3));
1798 s << alphaCounter(par->getCounter(i-3));
1801 << par->getCounter(i-2) << '.'
1802 << par->getCounter(i-1) << '.'
1803 << par->getCounter(i);
1806 case LABEL_COUNTER_PARAGRAPH:
1807 if (par->isRightToLeftPar(buf->params))
1808 s << hebrewCounter(par->getCounter(i-4));
1810 s << alphaCounter(par->getCounter(i-4));
1813 << par->getCounter(i-3) << '.'
1814 << par->getCounter(i-2) << '.'
1815 << par->getCounter(i-1) << '.'
1816 << par->getCounter(i);
1819 case LABEL_COUNTER_SUBPARAGRAPH:
1820 if (par->isRightToLeftPar(buf->params))
1821 s << hebrewCounter(par->getCounter(i-5));
1823 s << alphaCounter(par->getCounter(i-5));
1826 << par->getCounter(i-4) << '.'
1827 << par->getCounter(i-3) << '.'
1828 << par->getCounter(i-2) << '.'
1829 << par->getCounter(i-1) << '.'
1830 << par->getCounter(i);
1834 // Can this ever be reached? And in the
1835 // case it is, how can this be correct?
1837 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1843 par->labelstring += s.str().c_str();
1844 // We really want to remove the c_str as soon as
1848 char * tmps = s.str();
1849 par->labelstring += tmps;
1853 for (i++; i < 10; ++i) {
1854 // reset the following counters
1855 par->setCounter(i, 0);
1857 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1858 for (i++; i < 10; ++i) {
1859 // reset the following counters
1860 par->setCounter(i, 0);
1862 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1863 par->incCounter(i + par->enumdepth);
1864 int number = par->getCounter(i + par->enumdepth);
1867 std::ostringstream s;
1871 switch (par->enumdepth) {
1873 if (par->isRightToLeftPar(buf->params))
1875 << hebrewCounter(number)
1879 << loweralphaCounter(number)
1883 if (par->isRightToLeftPar(buf->params))
1884 s << '.' << romanCounter(number);
1886 s << romanCounter(number) << '.';
1889 if (par->isRightToLeftPar(buf->params))
1891 << alphaCounter(number);
1893 s << alphaCounter(number)
1897 if (par->isRightToLeftPar(buf->params))
1904 par->labelstring = s.str().c_str();
1905 // we really want to get rid of that c_str()
1908 char * tmps = s.str();
1909 par->labelstring = tmps;
1913 for (i += par->enumdepth + 1; i < 10; ++i)
1914 par->setCounter(i, 0); /* reset the following counters */
1917 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1918 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1920 int number = par->getCounter(i);
1922 par->bibkey = new InsetBibKey();
1923 par->bibkey->setCounter(number);
1924 par->labelstring = layout.labelstring();
1926 // In biblio should't be following counters but...
1928 string s = layout.labelstring();
1930 // the caption hack:
1932 if (layout.labeltype == LABEL_SENSITIVE) {
1933 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1934 && (par->footnotekind == LyXParagraph::FIG
1935 || par->footnotekind == LyXParagraph::WIDE_FIG))
1936 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1937 ? ":øåéà " : "Figure:";
1938 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1939 && (par->footnotekind == LyXParagraph::TAB
1940 || par->footnotekind == LyXParagraph::WIDE_TAB))
1941 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1942 ? ":äìáè" : "Table:";
1943 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1944 && par->footnotekind == LyXParagraph::ALGORITHM)
1945 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1946 ? ":Ãúéøåâìà " : "Algorithm:";
1948 /* par->SetLayout(0);
1949 s = layout->labelstring; */
1950 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1951 ? " :úåòîùî øñç" : "Senseless: ";
1954 par->labelstring = s;
1956 /* reset the enumeration counter. They are always resetted
1957 * when there is any other layout between */
1958 for (int i = 6 + par->enumdepth; i < 10; ++i)
1959 par->setCounter(i, 0);
1964 /* Updates all counters BEHIND the row. Changed paragraphs
1965 * with a dynamic left margin will be rebroken. */
1966 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1974 if (row->par()->next
1975 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1976 par = row->par()->LastPhysicalPar()->Next();
1978 par = row->par()->next;
1983 while (row->par() != par)
1986 SetCounter(bview->buffer(), par);
1988 /* now check for the headline layouts. remember that they
1989 * have a dynamic left margin */
1991 && ( textclasslist.Style(bview->buffer()->params.textclass,
1992 par->layout).margintype == MARGIN_DYNAMIC
1993 || textclasslist.Style(bview->buffer()->params.textclass,
1994 par->layout).labeltype == LABEL_SENSITIVE)
1997 /* Rebreak the paragraph */
1998 RemoveParagraph(row);
1999 AppendParagraph(bview, row);
2002 /* think about the damned open footnotes! */
2003 while (par->Next() &&
2004 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2005 || par->Next()->IsDummy())){
2007 if (par->IsDummy()) {
2008 while (row->par() != par)
2010 RemoveParagraph(row);
2011 AppendParagraph(bview, row);
2017 par = par->LastPhysicalPar()->Next();
2023 /* insets an inset. */
2024 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2026 if (!cursor.par()->InsertInsetAllowed(inset))
2028 SetUndo(bview->buffer(), Undo::INSERT,
2029 cursor.par()->ParFromPos(cursor.pos())->previous,
2030 cursor.par()->ParFromPos(cursor.pos())->next);
2031 cursor.par()->InsertInset(cursor.pos(), inset);
2032 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2033 * The character will not be inserted a
2038 void LyXText::copyEnvironmentType()
2040 copylayouttype = cursor.par()->GetLayout();
2044 void LyXText::pasteEnvironmentType(BufferView * bview)
2046 SetLayout(bview, copylayouttype);
2050 void LyXText::CutSelection(BufferView * bview, bool doclear)
2052 // Stuff what we got on the clipboard. Even if there is no selection.
2054 // There is a problem with having the stuffing here in that the
2055 // larger the selection the slower LyX will get. This can be
2056 // solved by running the line below only when the selection has
2057 // finished. The solution used currently just works, to make it
2058 // faster we need to be more clever and probably also have more
2059 // calls to stuffClipboard. (Lgb)
2060 bview->stuffClipboard(selectionAsString(bview->buffer()));
2062 // This doesn't make sense, if there is no selection
2066 // OK, we have a selection. This is always between sel_start_cursor
2067 // and sel_end cursor
2068 LyXParagraph * tmppar;
2071 // Check whether there are half footnotes in the selection
2072 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2073 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2074 tmppar = sel_start_cursor.par();
2075 while (tmppar != sel_end_cursor.par()){
2076 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2077 WriteAlert(_("Impossible operation"),
2078 _("Don't know what to do with half floats."),
2082 tmppar = tmppar->Next();
2087 /* table stuff -- begin */
2088 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2089 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2090 WriteAlert(_("Impossible operation"),
2091 _("Don't know what to do with half tables."),
2095 sel_start_cursor.par()->table->Reinit();
2097 /* table stuff -- end */
2099 // make sure that the depth behind the selection are restored, too
2100 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2101 LyXParagraph * undoendpar = endpar;
2103 if (endpar && endpar->GetDepth()) {
2104 while (endpar && endpar->GetDepth()) {
2105 endpar = endpar->LastPhysicalPar()->Next();
2106 undoendpar = endpar;
2108 } else if (endpar) {
2109 endpar = endpar->Next(); // because of parindents etc.
2112 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2113 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2117 // there are two cases: cut only within one paragraph or
2118 // more than one paragraph
2119 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2120 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2121 // only within one paragraph
2122 endpar = sel_start_cursor.par();
2123 int pos = sel_end_cursor.pos();
2124 cap.cutSelection(sel_start_cursor.par(), &endpar,
2125 sel_start_cursor.pos(), pos,
2126 bview->buffer()->params.textclass, doclear);
2127 sel_end_cursor.pos(pos);
2129 endpar = sel_end_cursor.par();
2131 int pos = sel_end_cursor.pos();
2132 cap.cutSelection(sel_start_cursor.par(), &endpar,
2133 sel_start_cursor.pos(), pos,
2134 bview->buffer()->params.textclass, doclear);
2136 sel_end_cursor.par(endpar);
2137 sel_end_cursor.pos(pos);
2138 cursor.pos(sel_end_cursor.pos());
2140 endpar = endpar->Next();
2142 // sometimes necessary
2144 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2146 RedoParagraphs(bview, sel_start_cursor, endpar);
2149 cursor = sel_start_cursor;
2150 SetCursor(bview, cursor.par(), cursor.pos());
2151 sel_cursor = cursor;
2152 UpdateCounters(bview, cursor.row());
2156 void LyXText::CopySelection(BufferView * bview)
2158 // Stuff what we got on the clipboard. Even if there is no selection.
2160 // There is a problem with having the stuffing here in that the
2161 // larger the selection the slower LyX will get. This can be
2162 // solved by running the line below only when the selection has
2163 // finished. The solution used currently just works, to make it
2164 // faster we need to be more clever and probably also have more
2165 // calls to stuffClipboard. (Lgb)
2166 bview->stuffClipboard(selectionAsString(bview->buffer()));
2168 // this doesnt make sense, if there is no selection
2172 // ok we have a selection. This is always between sel_start_cursor
2173 // and sel_end cursor
2174 LyXParagraph * tmppar;
2177 /* check wether there are half footnotes in the selection */
2178 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2179 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2180 tmppar = sel_start_cursor.par();
2181 while (tmppar != sel_end_cursor.par()) {
2182 if (tmppar->footnoteflag !=
2183 sel_end_cursor.par()->footnoteflag) {
2184 WriteAlert(_("Impossible operation"),
2185 _("Don't know what to do"
2186 " with half floats."),
2190 tmppar = tmppar->Next();
2195 /* table stuff -- begin */
2196 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2197 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2198 WriteAlert(_("Impossible operation"),
2199 _("Don't know what to do with half tables."),
2204 /* table stuff -- end */
2207 // copy behind a space if there is one
2208 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2209 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2210 && (sel_start_cursor.par() != sel_end_cursor.par()
2211 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2212 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2216 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2217 sel_start_cursor.pos(), sel_end_cursor.pos(),
2218 bview->buffer()->params.textclass);
2222 void LyXText::PasteSelection(BufferView * bview)
2226 // this does not make sense, if there is nothing to paste
2227 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2230 SetUndo(bview->buffer(), Undo::INSERT,
2231 cursor.par()->ParFromPos(cursor.pos())->previous,
2232 cursor.par()->ParFromPos(cursor.pos())->next);
2234 LyXParagraph * endpar;
2235 LyXParagraph * actpar = cursor.par();
2237 int pos = cursor.pos();
2238 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2240 RedoParagraphs(bview, cursor, endpar);
2242 SetCursor(bview, cursor.par(), cursor.pos());
2245 sel_cursor = cursor;
2246 SetCursor(bview, actpar, pos);
2248 UpdateCounters(bview, cursor.row());
2252 // returns a pointer to the very first LyXParagraph
2253 LyXParagraph * LyXText::FirstParagraph() const
2255 return OwnerParagraph();
2259 // returns true if the specified string is at the specified position
2260 bool LyXText::IsStringInText(LyXParagraph * par,
2261 LyXParagraph::size_type pos,
2262 char const * str) const
2266 while (pos + i < par->Last() && str[i] &&
2267 str[i] == par->GetChar(pos + i)) {
2277 // sets the selection over the number of characters of string, no check!!
2278 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2280 sel_cursor = cursor;
2281 for (int i = 0; string[i]; ++i)
2287 // simple replacing. The font of the first selected character is used
2288 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2290 SetCursorParUndo(bview->buffer());
2293 if (!selection) { // create a dummy selection
2294 sel_end_cursor = cursor;
2295 sel_start_cursor = cursor;
2298 // Get font setting before we cut
2299 LyXParagraph::size_type pos = sel_end_cursor.pos();
2300 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2301 sel_start_cursor.pos());
2303 // Insert the new string
2304 for (int i = 0; str[i]; ++i) {
2305 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2309 // Cut the selection
2310 CutSelection(bview);
2316 // if the string can be found: return true and set the cursor to
2318 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2320 LyXParagraph * par = cursor.par();
2321 LyXParagraph::size_type pos = cursor.pos();
2322 while (par && !IsStringInText(par, pos, str)) {
2323 if (pos < par->Last() - 1)
2331 SetCursor(bview, par, pos);
2339 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2341 LyXParagraph * par = cursor.par();
2342 int pos = cursor.pos();
2348 // We skip empty paragraphs (Asger)
2350 par = par->Previous();
2352 pos = par->Last() - 1;
2353 } while (par && pos < 0);
2355 } while (par && !IsStringInText(par, pos, string));
2358 SetCursor(bview, par, pos);
2365 // needed to insert the selection
2366 void LyXText::InsertStringA(BufferView * bview, string const & str)
2368 LyXParagraph * par = cursor.par();
2369 LyXParagraph::size_type pos = cursor.pos();
2370 LyXParagraph::size_type a = 0;
2372 LyXParagraph * endpar = cursor.par()->Next();
2374 SetCursorParUndo(bview->buffer());
2377 textclasslist.Style(bview->buffer()->params.textclass,
2378 cursor.par()->GetLayout()).isEnvironment();
2379 // only to be sure, should not be neccessary
2382 // insert the string, don't insert doublespace
2383 string::size_type i = 0;
2384 while (i < str.length()) {
2385 if (str[i] != '\n') {
2387 && i + 1 < str.length() && str[i + 1] != ' '
2388 && pos && par->GetChar(pos - 1)!= ' ') {
2389 par->InsertChar(pos, ' ', current_font);
2392 } else if (par->table) {
2393 if (str[i] == '\t') {
2394 while((pos < par->size()) &&
2395 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2397 if (pos < par->size())
2399 else // no more fields to fill skip the rest
2401 } else if ((str[i] != 13) &&
2402 ((str[i] & 127) >= ' ')) {
2403 par->InsertChar(pos, str[i],
2408 } else if (str[i] == ' ') {
2409 InsetSpecialChar * new_inset =
2410 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2411 if (par->InsertInsetAllowed(new_inset)) {
2412 par->InsertInset(pos, new_inset,
2418 } else if (str[i] == '\t') {
2419 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2420 InsetSpecialChar * new_inset =
2421 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2422 if (par->InsertInsetAllowed(new_inset)) {
2423 par->InsertInset(pos, new_inset,
2430 } else if (str[i] != 13 &&
2431 // Ignore unprintables
2432 (str[i] & 127) >= ' ') {
2433 par->InsertChar(pos, str[i], current_font);
2439 if ((i + 1) >= str.length()) {
2440 if (pos < par->size())
2444 while((pos < par->size()) &&
2445 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2448 cell = NumberOfCell(par, pos);
2449 while((pos < par->size()) &&
2450 !(par->table->IsFirstCell(cell))) {
2452 while((pos < par->size()) &&
2453 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2456 cell = NumberOfCell(par, pos);
2458 if (pos >= par->size())
2459 // no more fields to fill skip the rest
2463 if (!par->size()) { // par is empty
2464 InsetSpecialChar * new_inset =
2465 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2466 if (par->InsertInsetAllowed(new_inset)) {
2467 par->InsertInset(pos,
2475 par->BreakParagraph(bview->buffer()->params, pos, flag);
2485 RedoParagraphs(bview, cursor, endpar);
2486 SetCursor(bview, cursor.par(), cursor.pos());
2487 sel_cursor = cursor;
2488 SetCursor(bview, par, pos);
2493 /* turns double-CR to single CR, others where converted into one blank and 13s
2494 * that are ignored .Double spaces are also converted into one. Spaces at
2495 * the beginning of a paragraph are forbidden. tabs are converted into one
2496 * space. then InsertStringA is called */
2497 void LyXText::InsertStringB(BufferView * bview, string const & s)
2500 LyXParagraph * par = cursor.par();
2501 string::size_type i = 1;
2502 while (i < str.length()) {
2503 if (str[i] == '\t' && !par->table)
2505 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2507 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2508 if (str[i + 1] != '\n') {
2509 if (str[i - 1] != ' ')
2514 while (i + 1 < str.length()
2515 && (str[i + 1] == ' '
2516 || str[i + 1] == '\t'
2517 || str[i + 1] == '\n'
2518 || str[i + 1] == 13)) {
2525 InsertStringA(bview, str);
2529 bool LyXText::GotoNextError(BufferView * bview) const
2531 LyXCursor res = cursor;
2533 if (res.pos() < res.par()->Last() - 1) {
2534 res.pos(res.pos() + 1);
2536 res.par(res.par()->Next());
2540 } while (res.par() &&
2541 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2542 && res.par()->GetInset(res.pos())->AutoDelete()));
2545 SetCursor(bview, res.par(), res.pos());
2552 bool LyXText::GotoNextNote(BufferView * bview) const
2554 LyXCursor res = cursor;
2556 if (res.pos() < res.par()->Last() - 1) {
2557 res.pos(res.pos() + 1);
2559 res.par(res.par()->Next());
2563 } while (res.par() &&
2564 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2565 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2568 SetCursor(bview, res.par(), res.pos());
2575 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2576 LyXParagraph::size_type pos)
2578 LyXCursor tmpcursor;
2581 /* table stuff -- begin*/
2584 CheckParagraphInTable(bview, par, pos);
2588 /* table stuff -- end*/
2591 LyXParagraph::size_type z;
2592 Row * row = GetRow(par, pos, y);
2594 // is there a break one row above
2595 if (row->previous() && row->previous()->par() == row->par()) {
2596 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2597 if ( z >= row->pos()) {
2598 // set the dimensions of the row above
2599 y -= row->previous()->height();
2601 refresh_row = row->previous();
2602 status = LyXText::NEED_MORE_REFRESH;
2604 BreakAgain(bview, row->previous());
2606 // set the cursor again. Otherwise
2607 // dangling pointers are possible
2608 SetCursor(bview, cursor.par(), cursor.pos());
2609 sel_cursor = cursor;
2614 int tmpheight = row->height();
2615 LyXParagraph::size_type tmplast = RowLast(row);
2619 BreakAgain(bview, row);
2620 if (row->height() == tmpheight && RowLast(row) == tmplast)
2621 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2623 status = LyXText::NEED_MORE_REFRESH;
2625 // check the special right address boxes
2626 if (textclasslist.Style(bview->buffer()->params.textclass,
2627 par->GetLayout()).margintype
2628 == MARGIN_RIGHT_ADDRESS_BOX) {
2635 RedoDrawingOfParagraph(bview, tmpcursor);
2641 // set the cursor again. Otherwise dangling pointers are possible
2642 // also set the selection
2646 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2647 sel_cursor = cursor;
2648 SetCursorIntern(bview, sel_start_cursor.par(),
2649 sel_start_cursor.pos());
2650 sel_start_cursor = cursor;
2651 SetCursorIntern(bview, sel_end_cursor.par(),
2652 sel_end_cursor.pos());
2653 sel_end_cursor = cursor;
2654 SetCursorIntern(bview, last_sel_cursor.par(),
2655 last_sel_cursor.pos());
2656 last_sel_cursor = cursor;
2659 SetCursorIntern(bview, cursor.par(), cursor.pos());
2663 // returns false if inset wasn't found
2664 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2666 // first check the current paragraph
2667 int pos = cursor.par()->GetPositionOfInset(inset);
2669 CheckParagraph(bview, cursor.par(), pos);
2673 // check every paragraph
2675 LyXParagraph * par = FirstParagraph();
2677 // make sure the paragraph is open
2678 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2679 pos = par->GetPositionOfInset(inset);
2681 CheckParagraph(bview, par, pos);
2692 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2693 LyXParagraph::size_type pos,
2694 bool setfont, bool boundary) const
2696 LyXCursor old_cursor = cursor;
2697 SetCursorIntern(bview, par, pos, setfont, boundary);
2698 DeleteEmptyParagraphMechanism(bview, old_cursor);
2702 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2703 LyXParagraph::size_type pos, bool boundary) const
2705 // correct the cursor position if impossible
2706 if (pos > par->Last()){
2707 LyXParagraph * tmppar = par->ParFromPos(pos);
2708 pos = par->PositionInParFromPos(pos);
2712 if (par->IsDummy() && par->previous &&
2713 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2714 while (par->previous &&
2715 ((par->previous->IsDummy() &&
2716 (par->previous->previous->footnoteflag ==
2717 LyXParagraph::CLOSED_FOOTNOTE)) ||
2718 (par->previous->footnoteflag ==
2719 LyXParagraph::CLOSED_FOOTNOTE))) {
2720 par = par->previous ;
2721 if (par->IsDummy() &&
2722 (par->previous->footnoteflag ==
2723 LyXParagraph::CLOSED_FOOTNOTE))
2724 pos += par->size() + 1;
2726 if (par->previous) {
2727 par = par->previous;
2729 pos += par->size() + 1;
2734 cur.boundary(boundary);
2736 /* get the cursor y position in text */
2738 Row * row = GetRow(par, pos, y);
2739 /* y is now the beginning of the cursor row */
2740 y += row->baseline();
2741 /* y is now the cursor baseline */
2744 /* now get the cursors x position */
2746 float fill_separator, fill_hfill, fill_label_hfill;
2747 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2749 LyXParagraph::size_type cursor_vpos = 0;
2750 LyXParagraph::size_type last = RowLastPrintable(row);
2752 if (pos > last + 1) // This shouldn't happen.
2754 else if (pos < row->pos())
2757 if (last < row->pos())
2758 cursor_vpos = row->pos();
2759 else if (pos > last && !boundary)
2760 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2761 ? row->pos() : last + 1;
2762 else if (pos > row->pos() &&
2763 (pos > last || boundary ||
2764 (row->par()->table && row->par()->IsNewline(pos))))
2765 /// Place cursor after char at (logical) position pos - 1
2766 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2767 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2769 /// Place cursor before char at (logical) position pos
2770 cursor_vpos = (bidi_level(pos) % 2 == 0)
2771 ? log2vis(pos) : log2vis(pos) + 1;
2774 /* table stuff -- begin*/
2775 if (row->par()->table) {
2776 int cell = NumberOfCell(row->par(), row->pos());
2778 x += row->par()->table->GetBeginningOfTextInCell(cell);
2779 for (LyXParagraph::size_type vpos = row->pos();
2780 vpos < cursor_vpos; ++vpos) {
2781 pos = vis2log(vpos);
2782 if (row->par()->IsNewline(pos)) {
2783 x = x_old + row->par()->table->WidthOfColumn(cell);
2786 x += row->par()->table->GetBeginningOfTextInCell(cell);
2788 x += SingleWidth(bview, row->par(), pos);
2792 /* table stuff -- end*/
2794 LyXParagraph::size_type main_body =
2795 BeginningOfMainBody(bview->buffer(), row->par());
2796 if ((main_body > 0) &&
2797 ((main_body-1 > last) ||
2798 !row->par()->IsLineSeparator(main_body-1)))
2801 for (LyXParagraph::size_type vpos = row->pos();
2802 vpos < cursor_vpos; ++vpos) {
2803 pos = vis2log(vpos);
2804 if (main_body > 0 && pos == main_body-1) {
2805 x += fill_label_hfill +
2806 lyxfont::width(textclasslist.Style(
2807 bview->buffer()->params.textclass,
2808 row->par()->GetLayout())
2810 GetFont(bview->buffer(), row->par(), -2));
2811 if (row->par()->IsLineSeparator(main_body-1))
2812 x -= SingleWidth(bview, row->par(),main_body-1);
2814 if (HfillExpansion(bview->buffer(), row, pos)) {
2815 x += SingleWidth(bview, row->par(), pos);
2816 if (pos >= main_body)
2819 x += fill_label_hfill;
2820 } else if (row->par()->IsSeparator(pos)) {
2821 x += SingleWidth(bview, row->par(), pos);
2822 if (pos >= main_body)
2823 x += fill_separator;
2825 x += SingleWidth(bview, row->par(), pos);
2837 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2838 LyXParagraph::size_type pos,
2839 bool setfont, bool boundary) const
2841 SetCursor(bview, cursor, par, pos, boundary);
2843 SetCurrentFont(bview);
2846 void LyXText::SetCurrentFont(BufferView * bview) const
2848 LyXParagraph::size_type pos = cursor.pos();
2849 if (cursor.boundary() && pos > 0)
2853 if (pos == cursor.par()->Last() ||
2854 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2856 else if (cursor.par()->IsSeparator(pos)) {
2857 if (pos > cursor.row()->pos() &&
2858 bidi_level(pos) % 2 ==
2859 bidi_level(pos - 1) % 2)
2861 else if (pos + 1 < cursor.par()->Last())
2867 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2868 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2872 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2874 LyXCursor old_cursor = cursor;
2876 /* get the row first */
2878 Row * row = GetRowNearY(y);
2879 cursor.par(row->par());
2882 int column = GetColumnNearX(bview, row, x, bound);
2883 cursor.pos(row->pos() + column);
2885 cursor.y(y + row->baseline());
2887 cursor.boundary(bound);
2888 SetCurrentFont(bview);
2889 DeleteEmptyParagraphMechanism(bview, old_cursor);
2893 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2894 int x, long y) const
2896 /* get the row first */
2898 Row * row = GetRowNearY(y);
2900 int column = GetColumnNearX(bview, row, x, bound);
2902 cur.par(row->par());
2903 cur.pos(row->pos() + column);
2905 cur.y(y + row->baseline());
2907 cur.boundary(bound);
2911 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2913 CursorLeftIntern(bview, internal);
2915 if (cursor.par()->table) {
2916 int cell = NumberOfCell(cursor.par(), cursor.pos());
2917 if (cursor.par()->table->IsContRow(cell)
2918 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2926 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2928 if (cursor.pos() > 0) {
2929 bool boundary = cursor.boundary();
2930 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2931 if (!internal && !boundary &&
2932 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2933 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2934 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2935 LyXParagraph * par = cursor.par()->Previous();
2936 LyXParagraph::size_type pos = par->Last();
2937 SetCursor(bview, par, pos);
2938 if (IsBoundary(bview->buffer(), par, pos))
2939 SetCursor(bview, par, pos, false, true);
2944 void LyXText::CursorRight(BufferView * bview, bool internal) const
2946 CursorRightIntern(bview, internal);
2948 if (cursor.par()->table) {
2949 int cell = NumberOfCell(cursor.par(), cursor.pos());
2950 if (cursor.par()->table->IsContRow(cell) &&
2951 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2959 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
2961 if (cursor.pos() < cursor.par()->Last()) {
2962 if (!internal && cursor.boundary() &&
2963 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
2964 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2966 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2967 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2968 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2970 } else if (cursor.par()->Next())
2971 SetCursor(bview, cursor.par()->Next(), 0);
2975 void LyXText::CursorUp(BufferView * bview) const
2977 SetCursorFromCoordinates(bview, cursor.x_fix(),
2978 cursor.y() - cursor.row()->baseline() - 1);
2980 if (cursor.par()->table) {
2981 int cell = NumberOfCell(cursor.par(), cursor.pos());
2982 if (cursor.par()->table->IsContRow(cell) &&
2983 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
2991 void LyXText::CursorDown(BufferView * bview) const
2994 if (cursor.par()->table &&
2995 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
2996 !cursor.par()->next)
3000 SetCursorFromCoordinates(bview, cursor.x_fix(),
3001 cursor.y() - cursor.row()->baseline()
3002 + cursor.row()->height() + 1);
3004 if (cursor.par()->table) {
3005 int cell = NumberOfCell(cursor.par(), cursor.pos());
3006 int cell_above = cursor.par()->table->GetCellAbove(cell);
3007 while(cursor.par()->table &&
3008 cursor.par()->table->IsContRow(cell) &&
3009 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3010 SetCursorFromCoordinates(bview, cursor.x_fix(),
3011 cursor.y() - cursor.row()->baseline()
3012 + cursor.row()->height() + 1);
3013 if (cursor.par()->table) {
3014 cell = NumberOfCell(cursor.par(), cursor.pos());
3015 cell_above = cursor.par()->table->GetCellAbove(cell);
3023 void LyXText::CursorUpParagraph(BufferView * bview) const
3025 if (cursor.pos() > 0) {
3026 SetCursor(bview, cursor.par(), 0);
3028 else if (cursor.par()->Previous()) {
3029 SetCursor(bview, cursor.par()->Previous(), 0);
3034 void LyXText::CursorDownParagraph(BufferView * bview) const
3036 if (cursor.par()->Next()) {
3037 SetCursor(bview, cursor.par()->Next(), 0);
3039 SetCursor(bview, cursor.par(), cursor.par()->Last());
3044 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3045 LyXCursor const & old_cursor) const
3047 // Would be wrong to delete anything if we have a selection.
3048 if (selection) return;
3050 // We allow all kinds of "mumbo-jumbo" when freespacing.
3051 if (textclasslist.Style(bview->buffer()->params.textclass,
3052 old_cursor.par()->GetLayout()).free_spacing)
3055 bool deleted = false;
3057 /* Ok I'll put some comments here about what is missing.
3058 I have fixed BackSpace (and thus Delete) to not delete
3059 double-spaces automagically. I have also changed Cut,
3060 Copy and Paste to hopefully do some sensible things.
3061 There are still some small problems that can lead to
3062 double spaces stored in the document file or space at
3063 the beginning of paragraphs. This happens if you have
3064 the cursor betwenn to spaces and then save. Or if you
3065 cut and paste and the selection have a space at the
3066 beginning and then save right after the paste. I am
3067 sure none of these are very hard to fix, but I will
3068 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3069 that I can get some feedback. (Lgb)
3072 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3073 // delete the LineSeparator.
3076 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3077 // delete the LineSeparator.
3080 // If the pos around the old_cursor were spaces, delete one of them.
3081 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3082 // Only if the cursor has really moved
3084 if (old_cursor.pos() > 0
3085 && old_cursor.pos() < old_cursor.par()->Last()
3086 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3087 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3088 old_cursor.par()->Erase(old_cursor.pos() - 1);
3089 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3091 if (old_cursor.par() == cursor.par() &&
3092 cursor.pos() > old_cursor.pos()) {
3093 SetCursorIntern(bview, cursor.par(),
3096 SetCursorIntern(bview, cursor.par(),
3102 // Do not delete empty paragraphs with keepempty set.
3103 if ((textclasslist.Style(bview->buffer()->params.textclass,
3104 old_cursor.par()->GetLayout())).keepempty)
3107 LyXCursor tmpcursor;
3109 if (old_cursor.par() != cursor.par()) {
3110 if ( (old_cursor.par()->Last() == 0
3111 || (old_cursor.par()->Last() == 1
3112 && old_cursor.par()->IsLineSeparator(0)))
3113 && old_cursor.par()->FirstPhysicalPar()
3114 == old_cursor.par()->LastPhysicalPar()) {
3115 // ok, we will delete anything
3117 // make sure that you do not delete any environments
3118 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3119 !(old_cursor.row()->previous()
3120 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3121 && !(old_cursor.row()->next()
3122 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3123 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3124 && ((old_cursor.row()->previous()
3125 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3126 || (old_cursor.row()->next()
3127 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3129 status = LyXText::NEED_MORE_REFRESH;
3132 if (old_cursor.row()->previous()) {
3133 refresh_row = old_cursor.row()->previous();
3134 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3136 cursor = old_cursor; // that undo can restore the right cursor position
3137 LyXParagraph * endpar = old_cursor.par()->next;
3138 if (endpar && endpar->GetDepth()) {
3139 while (endpar && endpar->GetDepth()) {
3140 endpar = endpar->LastPhysicalPar()->Next();
3143 SetUndo(bview->buffer(), Undo::DELETE,
3144 old_cursor.par()->previous,
3149 RemoveRow(old_cursor.row());
3150 if (OwnerParagraph() == old_cursor.par()) {
3151 OwnerParagraph(OwnerParagraph()->next);
3154 delete old_cursor.par();
3156 /* Breakagain the next par. Needed
3157 * because of the parindent that
3158 * can occur or dissappear. The
3159 * next row can change its height,
3160 * if there is another layout before */
3161 if (refresh_row->next()) {
3162 BreakAgain(bview, refresh_row->next());
3163 UpdateCounters(bview, refresh_row);
3165 SetHeightOfRow(bview, refresh_row);
3167 refresh_row = old_cursor.row()->next();
3168 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3171 cursor = old_cursor; // that undo can restore the right cursor position
3172 LyXParagraph * endpar = old_cursor.par()->next;
3173 if (endpar && endpar->GetDepth()) {
3174 while (endpar && endpar->GetDepth()) {
3175 endpar = endpar->LastPhysicalPar()->Next();
3178 SetUndo(bview->buffer(), Undo::DELETE,
3179 old_cursor.par()->previous,
3184 RemoveRow(old_cursor.row());
3186 if (OwnerParagraph() == old_cursor.par()) {
3187 OwnerParagraph(OwnerParagraph()->next);
3189 delete old_cursor.par();
3191 /* Breakagain the next par. Needed
3192 because of the parindent that can
3193 occur or dissappear.
3194 The next row can change its height,
3195 if there is another layout before
3198 BreakAgain(bview, refresh_row);
3199 UpdateCounters(bview, refresh_row->previous());
3205 SetCursorIntern(bview, cursor.par(), cursor.pos());
3207 if (sel_cursor.par() == old_cursor.par()
3208 && sel_cursor.pos() == sel_cursor.pos()) {
3209 // correct selection
3210 sel_cursor = cursor;
3215 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3216 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3218 SetCursorIntern(bview, cursor.par(), cursor.pos());
3219 sel_cursor = cursor;
3226 LyXParagraph * LyXText::GetParFromID(int id)
3228 LyXParagraph * result = FirstParagraph();
3229 while (result && result->id() != id)
3230 result = result->next;
3236 bool LyXText::TextUndo(BufferView * bview)
3240 // returns false if no undo possible
3241 Undo * undo = bview->buffer()->undostack.pop();
3245 bview->buffer()->redostack
3246 .push(CreateUndo(bview->buffer(), undo->kind,
3247 GetParFromID(undo->number_of_before_par),
3248 GetParFromID(undo->number_of_behind_par)));
3250 return TextHandleUndo(bview, undo);
3254 bool LyXText::TextRedo(BufferView * bview)
3258 // returns false if no redo possible
3259 Undo * undo = bview->buffer()->redostack.pop();
3263 bview->buffer()->undostack
3264 .push(CreateUndo(bview->buffer(), undo->kind,
3265 GetParFromID(undo->number_of_before_par),
3266 GetParFromID(undo->number_of_behind_par)));
3268 return TextHandleUndo(bview, undo);
3272 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3276 // returns false if no undo possible
3277 bool result = false;
3279 LyXParagraph * before =
3280 GetParFromID(undo->number_of_before_par);
3281 LyXParagraph * behind =
3282 GetParFromID(undo->number_of_behind_par);
3283 LyXParagraph * tmppar;
3284 LyXParagraph * tmppar2;
3285 LyXParagraph * endpar;
3286 LyXParagraph * tmppar5;
3288 // if there's no before take the beginning
3289 // of the document for redoing
3291 SetCursorIntern(bview, FirstParagraph(), 0);
3293 // replace the paragraphs with the undo informations
3295 LyXParagraph * tmppar3 = undo->par;
3296 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3297 LyXParagraph * tmppar4 = tmppar3;
3299 while (tmppar4->next)
3300 tmppar4 = tmppar4->next;
3301 } // get last undo par
3303 // now remove the old text if there is any
3304 if (before != behind || (!behind && !before)){
3306 tmppar5 = before->next;
3308 tmppar5 = OwnerParagraph();
3310 while (tmppar5 && tmppar5 != behind){
3312 tmppar5 = tmppar5->next;
3313 // a memory optimization for edit: Only layout information
3314 // is stored in the undo. So restore the text informations.
3315 if (undo->kind == Undo::EDIT) {
3316 tmppar2->setContentsFromPar(tmppar);
3317 tmppar->clearContents();
3318 tmppar2 = tmppar2->next;
3323 // put the new stuff in the list if there is one
3326 before->next = tmppar3;
3328 OwnerParagraph(tmppar3);
3329 tmppar3->previous = before;
3333 OwnerParagraph(behind);
3336 tmppar4->next = behind;
3338 behind->previous = tmppar4;
3342 // Set the cursor for redoing
3344 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3345 // check wether before points to a closed float and open it if necessary
3346 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3347 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3349 while (tmppar4->previous &&
3350 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3351 tmppar4 = tmppar4->previous;
3352 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3353 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3354 tmppar4 = tmppar4->next;
3359 // open a cosed footnote at the end if necessary
3360 if (behind && behind->previous &&
3361 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3362 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3363 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3364 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3365 behind = behind->next;
3369 // calculate the endpar for redoing the paragraphs.
3371 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3372 endpar = behind->LastPhysicalPar()->Next();
3374 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3378 tmppar = GetParFromID(undo->number_of_cursor_par);
3379 RedoParagraphs(bview, cursor, endpar);
3381 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3382 UpdateCounters(bview, cursor.row());
3392 void LyXText::FinishUndo()
3396 // makes sure the next operation will be stored
3397 undo_finished = true;
3401 void LyXText::FreezeUndo()
3405 // this is dangerous and for internal use only
3410 void LyXText::UnFreezeUndo()
3414 // this is dangerous and for internal use only
3415 undo_frozen = false;
3419 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3420 LyXParagraph const * before,
3421 LyXParagraph const * behind) const
3426 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3427 buf->redostack.clear();
3431 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3432 LyXParagraph const * before, LyXParagraph const * behind)
3436 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3440 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3441 LyXParagraph const * before,
3442 LyXParagraph const * behind) const
3447 int before_number = -1;
3448 int behind_number = -1;
3450 before_number = before->id();
3452 behind_number = behind->id();
3453 // Undo::EDIT and Undo::FINISH are
3454 // always finished. (no overlapping there)
3455 // overlapping only with insert and delete inside one paragraph:
3456 // Nobody wants all removed character
3457 // appear one by one when undoing.
3458 // EDIT is special since only layout information, not the
3459 // contents of a paragaph are stored.
3460 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3461 // check wether storing is needed
3462 if (!buf->undostack.empty() &&
3463 buf->undostack.top()->kind == kind &&
3464 buf->undostack.top()->number_of_before_par == before_number &&
3465 buf->undostack.top()->number_of_behind_par == behind_number ){
3470 // create a new Undo
3471 LyXParagraph * undopar;
3472 LyXParagraph * tmppar;
3473 LyXParagraph * tmppar2;
3475 LyXParagraph * start = 0;
3476 LyXParagraph * end = 0;
3479 start = before->next;
3481 start = FirstParagraph();
3483 end = behind->previous;
3485 end = FirstParagraph();
3491 && start != end->next
3492 && (before != behind || (!before && !behind))) {
3494 tmppar2 = tmppar->Clone();
3495 tmppar2->id(tmppar->id());
3497 // a memory optimization: Just store the layout information
3499 if (kind == Undo::EDIT){
3500 //tmppar2->text.clear();
3501 tmppar2->clearContents();
3506 while (tmppar != end && tmppar->next) {
3507 tmppar = tmppar->next;
3508 tmppar2->next = tmppar->Clone();
3509 tmppar2->next->id(tmppar->id());
3510 // a memory optimization: Just store the layout
3511 // information when only edit
3512 if (kind == Undo::EDIT){
3513 //tmppar2->next->text.clear();
3514 tmppar2->clearContents();
3516 tmppar2->next->previous = tmppar2;
3517 tmppar2 = tmppar2->next;
3521 undopar = 0; // nothing to replace (undo of delete maybe)
3523 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3524 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3526 Undo * undo = new Undo(kind,
3527 before_number, behind_number,
3528 cursor_par, cursor_pos,
3531 undo_finished = false;
3536 void LyXText::SetCursorParUndo(Buffer * buf)
3540 SetUndo(buf, Undo::FINISH,
3541 cursor.par()->ParFromPos(cursor.pos())->previous,
3542 cursor.par()->ParFromPos(cursor.pos())->next);
3547 void LyXText::RemoveTableRow(LyXCursor & cur) const
3553 // move to the previous row
3554 int cell_act = NumberOfCell(cur.par(), cur.pos());
3557 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3558 cur.pos(cur.pos() - 1);
3560 !cur.par()->table->IsFirstCell(cell_act)) {
3561 cur.pos(cur.pos() - 1);
3562 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3563 cur.pos(cur.pos() - 1);
3567 // now we have to pay attention if the actual table is the
3568 // main row of TableContRows and if yes to delete all of them
3573 // delete up to the next row
3574 while (cur.pos() < cur.par()->Last() &&
3576 || !cur.par()->table->IsFirstCell(cell_act))) {
3577 while (cur.pos() < cur.par()->Last() &&
3578 !cur.par()->IsNewline(cur.pos()))
3579 cur.par()->Erase(cur.pos());
3582 if (cur.pos() < cur.par()->Last())
3583 cur.par()->Erase(cur.pos());
3585 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3586 cur.pos(cur.pos() - 1);
3587 cur.par()->Erase(cur.pos()); // no newline at very end!
3589 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3590 !cur.par()->table->IsContRow(cell_org) &&
3591 cur.par()->table->IsContRow(cell));
3592 cur.par()->table->DeleteRow(cell_org);
3599 bool LyXText::IsEmptyTableCell() const
3601 LyXParagraph::size_type pos = cursor.pos() - 1;
3602 while (pos >= 0 && pos < cursor.par()->Last()
3603 && !cursor.par()->IsNewline(pos))
3605 return cursor.par()->IsNewline(pos + 1);
3610 void LyXText::toggleAppendix(BufferView * bview)
3612 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3613 bool start = !par->start_of_appendix;
3615 // ensure that we have only one start_of_appendix in this document
3616 LyXParagraph * tmp = FirstParagraph();
3617 for (; tmp; tmp = tmp->next)
3618 tmp->start_of_appendix = 0;
3619 par->start_of_appendix = start;
3621 // we can set the refreshing parameters now
3622 status = LyXText::NEED_MORE_REFRESH;
3624 refresh_row = 0; // not needed for full update
3625 UpdateCounters(bview, 0);
3626 SetCursor(bview, cursor.par(), cursor.pos());
3629 LyXParagraph * LyXText::OwnerParagraph() const
3632 return inset_owner->par;
3634 return bv_owner->buffer()->paragraph;
3638 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3641 inset_owner->par = p;
3643 bv_owner->buffer()->paragraph = p;