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);
2032 cursor.par()->InsertInset(cursor.pos(), inset);
2034 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2035 cursor.par()->InsertInset(cursor.pos(), inset);
2037 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2038 * The character will not be inserted a
2043 void LyXText::copyEnvironmentType()
2045 copylayouttype = cursor.par()->GetLayout();
2049 void LyXText::pasteEnvironmentType(BufferView * bview)
2051 SetLayout(bview, copylayouttype);
2055 void LyXText::CutSelection(BufferView * bview, bool doclear)
2057 // Stuff what we got on the clipboard. Even if there is no selection.
2059 // There is a problem with having the stuffing here in that the
2060 // larger the selection the slower LyX will get. This can be
2061 // solved by running the line below only when the selection has
2062 // finished. The solution used currently just works, to make it
2063 // faster we need to be more clever and probably also have more
2064 // calls to stuffClipboard. (Lgb)
2065 bview->stuffClipboard(selectionAsString(bview->buffer()));
2067 // This doesn't make sense, if there is no selection
2071 // OK, we have a selection. This is always between sel_start_cursor
2072 // and sel_end cursor
2073 LyXParagraph * tmppar;
2076 // Check whether there are half footnotes in the selection
2077 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2078 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2079 tmppar = sel_start_cursor.par();
2080 while (tmppar != sel_end_cursor.par()){
2081 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2082 WriteAlert(_("Impossible operation"),
2083 _("Don't know what to do with half floats."),
2087 tmppar = tmppar->Next();
2092 /* table stuff -- begin */
2093 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2094 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2095 WriteAlert(_("Impossible operation"),
2096 _("Don't know what to do with half tables."),
2100 sel_start_cursor.par()->table->Reinit();
2102 /* table stuff -- end */
2104 // make sure that the depth behind the selection are restored, too
2105 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2106 LyXParagraph * undoendpar = endpar;
2108 if (endpar && endpar->GetDepth()) {
2109 while (endpar && endpar->GetDepth()) {
2110 endpar = endpar->LastPhysicalPar()->Next();
2111 undoendpar = endpar;
2113 } else if (endpar) {
2114 endpar = endpar->Next(); // because of parindents etc.
2117 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2118 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2122 // there are two cases: cut only within one paragraph or
2123 // more than one paragraph
2124 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2125 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2126 // only within one paragraph
2127 endpar = sel_start_cursor.par();
2128 int pos = sel_end_cursor.pos();
2129 cap.cutSelection(sel_start_cursor.par(), &endpar,
2130 sel_start_cursor.pos(), pos,
2131 bview->buffer()->params.textclass, doclear);
2132 sel_end_cursor.pos(pos);
2134 endpar = sel_end_cursor.par();
2136 int pos = sel_end_cursor.pos();
2137 cap.cutSelection(sel_start_cursor.par(), &endpar,
2138 sel_start_cursor.pos(), pos,
2139 bview->buffer()->params.textclass, doclear);
2141 sel_end_cursor.par(endpar);
2142 sel_end_cursor.pos(pos);
2143 cursor.pos(sel_end_cursor.pos());
2145 endpar = endpar->Next();
2147 // sometimes necessary
2149 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2151 RedoParagraphs(bview, sel_start_cursor, endpar);
2154 cursor = sel_start_cursor;
2155 SetCursor(bview, cursor.par(), cursor.pos());
2156 sel_cursor = cursor;
2157 UpdateCounters(bview, cursor.row());
2161 void LyXText::CopySelection(BufferView * bview)
2163 // Stuff what we got on the clipboard. Even if there is no selection.
2165 // There is a problem with having the stuffing here in that the
2166 // larger the selection the slower LyX will get. This can be
2167 // solved by running the line below only when the selection has
2168 // finished. The solution used currently just works, to make it
2169 // faster we need to be more clever and probably also have more
2170 // calls to stuffClipboard. (Lgb)
2171 bview->stuffClipboard(selectionAsString(bview->buffer()));
2173 // this doesnt make sense, if there is no selection
2177 // ok we have a selection. This is always between sel_start_cursor
2178 // and sel_end cursor
2179 LyXParagraph * tmppar;
2182 /* check wether there are half footnotes in the selection */
2183 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2184 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2185 tmppar = sel_start_cursor.par();
2186 while (tmppar != sel_end_cursor.par()) {
2187 if (tmppar->footnoteflag !=
2188 sel_end_cursor.par()->footnoteflag) {
2189 WriteAlert(_("Impossible operation"),
2190 _("Don't know what to do"
2191 " with half floats."),
2195 tmppar = tmppar->Next();
2200 /* table stuff -- begin */
2201 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2202 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2203 WriteAlert(_("Impossible operation"),
2204 _("Don't know what to do with half tables."),
2209 /* table stuff -- end */
2212 // copy behind a space if there is one
2213 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2214 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2215 && (sel_start_cursor.par() != sel_end_cursor.par()
2216 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2217 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2221 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2222 sel_start_cursor.pos(), sel_end_cursor.pos(),
2223 bview->buffer()->params.textclass);
2227 void LyXText::PasteSelection(BufferView * bview)
2231 // this does not make sense, if there is nothing to paste
2232 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2235 SetUndo(bview->buffer(), Undo::INSERT,
2236 cursor.par()->ParFromPos(cursor.pos())->previous,
2237 cursor.par()->ParFromPos(cursor.pos())->next);
2239 LyXParagraph * endpar;
2240 LyXParagraph * actpar = cursor.par();
2242 int pos = cursor.pos();
2243 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2245 RedoParagraphs(bview, cursor, endpar);
2247 SetCursor(bview, cursor.par(), cursor.pos());
2250 sel_cursor = cursor;
2251 SetCursor(bview, actpar, pos);
2253 UpdateCounters(bview, cursor.row());
2257 // returns a pointer to the very first LyXParagraph
2258 LyXParagraph * LyXText::FirstParagraph() const
2260 return OwnerParagraph();
2264 // returns true if the specified string is at the specified position
2265 bool LyXText::IsStringInText(LyXParagraph * par,
2266 LyXParagraph::size_type pos,
2267 char const * str) const
2271 while (pos + i < par->Last() && str[i] &&
2272 str[i] == par->GetChar(pos + i)) {
2282 // sets the selection over the number of characters of string, no check!!
2283 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2285 sel_cursor = cursor;
2286 for (int i = 0; string[i]; ++i)
2292 // simple replacing. The font of the first selected character is used
2293 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2295 SetCursorParUndo(bview->buffer());
2298 if (!selection) { // create a dummy selection
2299 sel_end_cursor = cursor;
2300 sel_start_cursor = cursor;
2303 // Get font setting before we cut
2304 LyXParagraph::size_type pos = sel_end_cursor.pos();
2305 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2306 sel_start_cursor.pos());
2308 // Insert the new string
2309 for (int i = 0; str[i]; ++i) {
2311 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2313 sel_end_cursor.par()->InsertChar(pos, str[i]);
2314 sel_end_cursor.par()->SetFont(pos, font);
2319 // Cut the selection
2320 CutSelection(bview);
2326 // if the string can be found: return true and set the cursor to
2328 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2330 LyXParagraph * par = cursor.par();
2331 LyXParagraph::size_type pos = cursor.pos();
2332 while (par && !IsStringInText(par, pos, str)) {
2333 if (pos < par->Last() - 1)
2341 SetCursor(bview, par, pos);
2349 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2351 LyXParagraph * par = cursor.par();
2352 int pos = cursor.pos();
2358 // We skip empty paragraphs (Asger)
2360 par = par->Previous();
2362 pos = par->Last() - 1;
2363 } while (par && pos < 0);
2365 } while (par && !IsStringInText(par, pos, string));
2368 SetCursor(bview, par, pos);
2375 // needed to insert the selection
2376 void LyXText::InsertStringA(BufferView * bview, string const & str)
2378 LyXParagraph * par = cursor.par();
2379 LyXParagraph::size_type pos = cursor.pos();
2380 LyXParagraph::size_type a = 0;
2382 LyXParagraph * endpar = cursor.par()->Next();
2384 SetCursorParUndo(bview->buffer());
2387 textclasslist.Style(bview->buffer()->params.textclass,
2388 cursor.par()->GetLayout()).isEnvironment();
2389 // only to be sure, should not be neccessary
2392 // insert the string, don't insert doublespace
2393 string::size_type i = 0;
2394 while (i < str.length()) {
2395 if (str[i] != '\n') {
2397 && i + 1 < str.length() && str[i + 1] != ' '
2398 && pos && par->GetChar(pos - 1)!= ' ') {
2400 par->InsertChar(pos, ' ', current_font);
2402 par->InsertChar(pos,' ');
2403 par->SetFont(pos, current_font);
2407 } else if (par->table) {
2408 if (str[i] == '\t') {
2409 while((pos < par->size()) &&
2410 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2412 if (pos < par->size())
2414 else // no more fields to fill skip the rest
2416 } else if ((str[i] != 13) &&
2417 ((str[i] & 127) >= ' ')) {
2419 par->InsertChar(pos, str[i],
2422 par->InsertChar(pos, str[i]);
2423 par->SetFont(pos, current_font);
2428 } else if (str[i] == ' ') {
2429 InsetSpecialChar * new_inset =
2430 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2431 if (par->InsertInsetAllowed(new_inset)) {
2433 par->InsertInset(pos, new_inset,
2436 par->InsertChar(pos, LyXParagraph::META_INSET);
2437 par->SetFont(pos, current_font);
2438 par->InsertInset(pos, new_inset);
2444 } else if (str[i] == '\t') {
2445 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2446 InsetSpecialChar * new_inset =
2447 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2448 if (par->InsertInsetAllowed(new_inset)) {
2450 par->InsertInset(pos, new_inset,
2453 par->InsertChar(pos, LyXParagraph::META_INSET);
2454 par->SetFont(pos, current_font);
2455 par->InsertInset(pos, new_inset);
2462 } else if (str[i] != 13 &&
2463 // Ignore unprintables
2464 (str[i] & 127) >= ' ') {
2466 par->InsertChar(pos, str[i], current_font);
2468 par->InsertChar(pos, str[i]);
2469 par->SetFont(pos, current_font);
2476 if ((i + 1) >= str.length()) {
2477 if (pos < par->size())
2481 while((pos < par->size()) &&
2482 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2485 cell = NumberOfCell(par, pos);
2486 while((pos < par->size()) &&
2487 !(par->table->IsFirstCell(cell))) {
2489 while((pos < par->size()) &&
2490 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2493 cell = NumberOfCell(par, pos);
2495 if (pos >= par->size())
2496 // no more fields to fill skip the rest
2500 if (!par->size()) { // par is empty
2501 InsetSpecialChar * new_inset =
2502 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2503 if (par->InsertInsetAllowed(new_inset)) {
2505 par->InsertInset(pos,
2509 par->InsertChar(pos, LyXParagraph::META_INSET);
2510 par->SetFont(pos, current_font);
2511 par->InsertInset(pos, new_inset);
2518 par->BreakParagraph(bview->buffer()->params, pos, flag);
2528 RedoParagraphs(bview, cursor, endpar);
2529 SetCursor(bview, cursor.par(), cursor.pos());
2530 sel_cursor = cursor;
2531 SetCursor(bview, par, pos);
2536 /* turns double-CR to single CR, others where converted into one blank and 13s
2537 * that are ignored .Double spaces are also converted into one. Spaces at
2538 * the beginning of a paragraph are forbidden. tabs are converted into one
2539 * space. then InsertStringA is called */
2540 void LyXText::InsertStringB(BufferView * bview, string const & s)
2543 LyXParagraph * par = cursor.par();
2544 string::size_type i = 1;
2545 while (i < str.length()) {
2546 if (str[i] == '\t' && !par->table)
2548 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2550 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2551 if (str[i + 1] != '\n') {
2552 if (str[i - 1] != ' ')
2557 while (i + 1 < str.length()
2558 && (str[i + 1] == ' '
2559 || str[i + 1] == '\t'
2560 || str[i + 1] == '\n'
2561 || str[i + 1] == 13)) {
2568 InsertStringA(bview, str);
2572 bool LyXText::GotoNextError(BufferView * bview) const
2574 LyXCursor res = cursor;
2576 if (res.pos() < res.par()->Last() - 1) {
2577 res.pos(res.pos() + 1);
2579 res.par(res.par()->Next());
2583 } while (res.par() &&
2584 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2585 && res.par()->GetInset(res.pos())->AutoDelete()));
2588 SetCursor(bview, res.par(), res.pos());
2595 bool LyXText::GotoNextNote(BufferView * bview) const
2597 LyXCursor res = cursor;
2599 if (res.pos() < res.par()->Last() - 1) {
2600 res.pos(res.pos() + 1);
2602 res.par(res.par()->Next());
2606 } while (res.par() &&
2607 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2608 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2611 SetCursor(bview, res.par(), res.pos());
2618 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2619 LyXParagraph::size_type pos)
2621 LyXCursor tmpcursor;
2624 /* table stuff -- begin*/
2627 CheckParagraphInTable(bview, par, pos);
2631 /* table stuff -- end*/
2634 LyXParagraph::size_type z;
2635 Row * row = GetRow(par, pos, y);
2637 // is there a break one row above
2638 if (row->previous() && row->previous()->par() == row->par()) {
2639 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2640 if ( z >= row->pos()) {
2641 // set the dimensions of the row above
2642 y -= row->previous()->height();
2644 refresh_row = row->previous();
2645 status = LyXText::NEED_MORE_REFRESH;
2647 BreakAgain(bview, row->previous());
2649 // set the cursor again. Otherwise
2650 // dangling pointers are possible
2651 SetCursor(bview, cursor.par(), cursor.pos());
2652 sel_cursor = cursor;
2657 int tmpheight = row->height();
2658 LyXParagraph::size_type tmplast = RowLast(row);
2662 BreakAgain(bview, row);
2663 if (row->height() == tmpheight && RowLast(row) == tmplast)
2664 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2666 status = LyXText::NEED_MORE_REFRESH;
2668 // check the special right address boxes
2669 if (textclasslist.Style(bview->buffer()->params.textclass,
2670 par->GetLayout()).margintype
2671 == MARGIN_RIGHT_ADDRESS_BOX) {
2678 RedoDrawingOfParagraph(bview, tmpcursor);
2684 // set the cursor again. Otherwise dangling pointers are possible
2685 // also set the selection
2689 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2690 sel_cursor = cursor;
2691 SetCursorIntern(bview, sel_start_cursor.par(),
2692 sel_start_cursor.pos());
2693 sel_start_cursor = cursor;
2694 SetCursorIntern(bview, sel_end_cursor.par(),
2695 sel_end_cursor.pos());
2696 sel_end_cursor = cursor;
2697 SetCursorIntern(bview, last_sel_cursor.par(),
2698 last_sel_cursor.pos());
2699 last_sel_cursor = cursor;
2702 SetCursorIntern(bview, cursor.par(), cursor.pos());
2706 // returns false if inset wasn't found
2707 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2709 // first check the current paragraph
2710 int pos = cursor.par()->GetPositionOfInset(inset);
2712 CheckParagraph(bview, cursor.par(), pos);
2716 // check every paragraph
2718 LyXParagraph * par = FirstParagraph();
2720 // make sure the paragraph is open
2721 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2722 pos = par->GetPositionOfInset(inset);
2724 CheckParagraph(bview, par, pos);
2735 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2736 LyXParagraph::size_type pos,
2737 bool setfont, bool boundary) const
2739 LyXCursor old_cursor = cursor;
2740 SetCursorIntern(bview, par, pos, setfont, boundary);
2741 DeleteEmptyParagraphMechanism(bview, old_cursor);
2745 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2746 LyXParagraph::size_type pos, bool boundary) const
2748 // correct the cursor position if impossible
2749 if (pos > par->Last()){
2750 LyXParagraph * tmppar = par->ParFromPos(pos);
2751 pos = par->PositionInParFromPos(pos);
2755 if (par->IsDummy() && par->previous &&
2756 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2757 while (par->previous &&
2758 ((par->previous->IsDummy() &&
2759 (par->previous->previous->footnoteflag ==
2760 LyXParagraph::CLOSED_FOOTNOTE)) ||
2761 (par->previous->footnoteflag ==
2762 LyXParagraph::CLOSED_FOOTNOTE))) {
2763 par = par->previous ;
2764 if (par->IsDummy() &&
2765 (par->previous->footnoteflag ==
2766 LyXParagraph::CLOSED_FOOTNOTE))
2767 pos += par->size() + 1;
2769 if (par->previous) {
2770 par = par->previous;
2772 pos += par->size() + 1;
2777 cur.boundary(boundary);
2779 /* get the cursor y position in text */
2781 Row * row = GetRow(par, pos, y);
2782 /* y is now the beginning of the cursor row */
2783 y += row->baseline();
2784 /* y is now the cursor baseline */
2787 /* now get the cursors x position */
2789 float fill_separator, fill_hfill, fill_label_hfill;
2790 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2792 LyXParagraph::size_type cursor_vpos = 0;
2793 LyXParagraph::size_type last = RowLastPrintable(row);
2795 if (pos > last + 1) // This shouldn't happen.
2797 else if (pos < row->pos())
2800 if (last < row->pos())
2801 cursor_vpos = row->pos();
2802 else if (pos > last && !boundary)
2803 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2804 ? row->pos() : last + 1;
2805 else if (pos > row->pos() &&
2806 (pos > last || boundary ||
2807 (row->par()->table && row->par()->IsNewline(pos))))
2808 /// Place cursor after char at (logical) position pos - 1
2809 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2810 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2812 /// Place cursor before char at (logical) position pos
2813 cursor_vpos = (bidi_level(pos) % 2 == 0)
2814 ? log2vis(pos) : log2vis(pos) + 1;
2817 /* table stuff -- begin*/
2818 if (row->par()->table) {
2819 int cell = NumberOfCell(row->par(), row->pos());
2821 x += row->par()->table->GetBeginningOfTextInCell(cell);
2822 for (LyXParagraph::size_type vpos = row->pos();
2823 vpos < cursor_vpos; ++vpos) {
2824 pos = vis2log(vpos);
2825 if (row->par()->IsNewline(pos)) {
2826 x = x_old + row->par()->table->WidthOfColumn(cell);
2829 x += row->par()->table->GetBeginningOfTextInCell(cell);
2831 x += SingleWidth(bview, row->par(), pos);
2835 /* table stuff -- end*/
2837 LyXParagraph::size_type main_body =
2838 BeginningOfMainBody(bview->buffer(), row->par());
2839 if ((main_body > 0) &&
2840 ((main_body-1 > last) ||
2841 !row->par()->IsLineSeparator(main_body-1)))
2844 for (LyXParagraph::size_type vpos = row->pos();
2845 vpos < cursor_vpos; ++vpos) {
2846 pos = vis2log(vpos);
2847 if (main_body > 0 && pos == main_body-1) {
2848 x += fill_label_hfill +
2849 lyxfont::width(textclasslist.Style(
2850 bview->buffer()->params.textclass,
2851 row->par()->GetLayout())
2853 GetFont(bview->buffer(), row->par(), -2));
2854 if (row->par()->IsLineSeparator(main_body-1))
2855 x -= SingleWidth(bview, row->par(),main_body-1);
2857 if (HfillExpansion(bview->buffer(), row, pos)) {
2858 x += SingleWidth(bview, row->par(), pos);
2859 if (pos >= main_body)
2862 x += fill_label_hfill;
2863 } else if (row->par()->IsSeparator(pos)) {
2864 x += SingleWidth(bview, row->par(), pos);
2865 if (pos >= main_body)
2866 x += fill_separator;
2868 x += SingleWidth(bview, row->par(), pos);
2880 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2881 LyXParagraph::size_type pos,
2882 bool setfont, bool boundary) const
2884 SetCursor(bview, cursor, par, pos, boundary);
2886 SetCurrentFont(bview);
2889 void LyXText::SetCurrentFont(BufferView * bview) const
2891 LyXParagraph::size_type pos = cursor.pos();
2892 if (cursor.boundary() && pos > 0)
2896 if (pos == cursor.par()->Last() ||
2897 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2899 else if (cursor.par()->IsSeparator(pos)) {
2900 if (pos > cursor.row()->pos() &&
2901 bidi_level(pos) % 2 ==
2902 bidi_level(pos - 1) % 2)
2904 else if (pos + 1 < cursor.par()->Last())
2910 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2911 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2915 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2917 LyXCursor old_cursor = cursor;
2919 /* get the row first */
2921 Row * row = GetRowNearY(y);
2922 cursor.par(row->par());
2925 int column = GetColumnNearX(bview, row, x, bound);
2926 cursor.pos(row->pos() + column);
2928 cursor.y(y + row->baseline());
2930 cursor.boundary(bound);
2931 SetCurrentFont(bview);
2932 DeleteEmptyParagraphMechanism(bview, old_cursor);
2936 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2937 int x, long y) const
2939 /* get the row first */
2941 Row * row = GetRowNearY(y);
2943 int column = GetColumnNearX(bview, row, x, bound);
2945 cur.par(row->par());
2946 cur.pos(row->pos() + column);
2948 cur.y(y + row->baseline());
2950 cur.boundary(bound);
2954 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2956 CursorLeftIntern(bview, internal);
2958 if (cursor.par()->table) {
2959 int cell = NumberOfCell(cursor.par(), cursor.pos());
2960 if (cursor.par()->table->IsContRow(cell)
2961 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2969 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2971 if (cursor.pos() > 0) {
2972 bool boundary = cursor.boundary();
2973 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2974 if (!internal && !boundary &&
2975 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2976 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2977 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2978 LyXParagraph * par = cursor.par()->Previous();
2979 LyXParagraph::size_type pos = par->Last();
2980 SetCursor(bview, par, pos);
2981 if (IsBoundary(bview->buffer(), par, pos))
2982 SetCursor(bview, par, pos, false, true);
2987 void LyXText::CursorRight(BufferView * bview, bool internal) const
2989 CursorRightIntern(bview, internal);
2991 if (cursor.par()->table) {
2992 int cell = NumberOfCell(cursor.par(), cursor.pos());
2993 if (cursor.par()->table->IsContRow(cell) &&
2994 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3002 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3004 if (cursor.pos() < cursor.par()->Last()) {
3005 if (!internal && cursor.boundary() &&
3006 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3007 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3009 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3010 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3011 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3013 } else if (cursor.par()->Next())
3014 SetCursor(bview, cursor.par()->Next(), 0);
3018 void LyXText::CursorUp(BufferView * bview) const
3020 SetCursorFromCoordinates(bview, cursor.x_fix(),
3021 cursor.y() - cursor.row()->baseline() - 1);
3023 if (cursor.par()->table) {
3024 int cell = NumberOfCell(cursor.par(), cursor.pos());
3025 if (cursor.par()->table->IsContRow(cell) &&
3026 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3034 void LyXText::CursorDown(BufferView * bview) const
3037 if (cursor.par()->table &&
3038 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3039 !cursor.par()->next)
3043 SetCursorFromCoordinates(bview, cursor.x_fix(),
3044 cursor.y() - cursor.row()->baseline()
3045 + cursor.row()->height() + 1);
3047 if (cursor.par()->table) {
3048 int cell = NumberOfCell(cursor.par(), cursor.pos());
3049 int cell_above = cursor.par()->table->GetCellAbove(cell);
3050 while(cursor.par()->table &&
3051 cursor.par()->table->IsContRow(cell) &&
3052 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3053 SetCursorFromCoordinates(bview, cursor.x_fix(),
3054 cursor.y() - cursor.row()->baseline()
3055 + cursor.row()->height() + 1);
3056 if (cursor.par()->table) {
3057 cell = NumberOfCell(cursor.par(), cursor.pos());
3058 cell_above = cursor.par()->table->GetCellAbove(cell);
3066 void LyXText::CursorUpParagraph(BufferView * bview) const
3068 if (cursor.pos() > 0) {
3069 SetCursor(bview, cursor.par(), 0);
3071 else if (cursor.par()->Previous()) {
3072 SetCursor(bview, cursor.par()->Previous(), 0);
3077 void LyXText::CursorDownParagraph(BufferView * bview) const
3079 if (cursor.par()->Next()) {
3080 SetCursor(bview, cursor.par()->Next(), 0);
3082 SetCursor(bview, cursor.par(), cursor.par()->Last());
3087 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3088 LyXCursor const & old_cursor) const
3090 // Would be wrong to delete anything if we have a selection.
3091 if (selection) return;
3093 // We allow all kinds of "mumbo-jumbo" when freespacing.
3094 if (textclasslist.Style(bview->buffer()->params.textclass,
3095 old_cursor.par()->GetLayout()).free_spacing)
3098 bool deleted = false;
3100 /* Ok I'll put some comments here about what is missing.
3101 I have fixed BackSpace (and thus Delete) to not delete
3102 double-spaces automagically. I have also changed Cut,
3103 Copy and Paste to hopefully do some sensible things.
3104 There are still some small problems that can lead to
3105 double spaces stored in the document file or space at
3106 the beginning of paragraphs. This happens if you have
3107 the cursor betwenn to spaces and then save. Or if you
3108 cut and paste and the selection have a space at the
3109 beginning and then save right after the paste. I am
3110 sure none of these are very hard to fix, but I will
3111 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3112 that I can get some feedback. (Lgb)
3115 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3116 // delete the LineSeparator.
3119 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3120 // delete the LineSeparator.
3123 // If the pos around the old_cursor were spaces, delete one of them.
3124 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3125 // Only if the cursor has really moved
3127 if (old_cursor.pos() > 0
3128 && old_cursor.pos() < old_cursor.par()->Last()
3129 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3130 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3131 old_cursor.par()->Erase(old_cursor.pos() - 1);
3132 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3134 if (old_cursor.par() == cursor.par() &&
3135 cursor.pos() > old_cursor.pos()) {
3136 SetCursorIntern(bview, cursor.par(),
3139 SetCursorIntern(bview, cursor.par(),
3145 // Do not delete empty paragraphs with keepempty set.
3146 if ((textclasslist.Style(bview->buffer()->params.textclass,
3147 old_cursor.par()->GetLayout())).keepempty)
3150 LyXCursor tmpcursor;
3152 if (old_cursor.par() != cursor.par()) {
3153 if ( (old_cursor.par()->Last() == 0
3154 || (old_cursor.par()->Last() == 1
3155 && old_cursor.par()->IsLineSeparator(0)))
3156 && old_cursor.par()->FirstPhysicalPar()
3157 == old_cursor.par()->LastPhysicalPar()) {
3158 // ok, we will delete anything
3160 // make sure that you do not delete any environments
3161 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3162 !(old_cursor.row()->previous()
3163 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3164 && !(old_cursor.row()->next()
3165 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3166 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3167 && ((old_cursor.row()->previous()
3168 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3169 || (old_cursor.row()->next()
3170 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3172 status = LyXText::NEED_MORE_REFRESH;
3175 if (old_cursor.row()->previous()) {
3176 refresh_row = old_cursor.row()->previous();
3177 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3179 cursor = old_cursor; // that undo can restore the right cursor position
3180 LyXParagraph * endpar = old_cursor.par()->next;
3181 if (endpar && endpar->GetDepth()) {
3182 while (endpar && endpar->GetDepth()) {
3183 endpar = endpar->LastPhysicalPar()->Next();
3186 SetUndo(bview->buffer(), Undo::DELETE,
3187 old_cursor.par()->previous,
3192 RemoveRow(old_cursor.row());
3193 if (OwnerParagraph() == old_cursor.par()) {
3194 OwnerParagraph(OwnerParagraph()->next);
3197 delete old_cursor.par();
3199 /* Breakagain the next par. Needed
3200 * because of the parindent that
3201 * can occur or dissappear. The
3202 * next row can change its height,
3203 * if there is another layout before */
3204 if (refresh_row->next()) {
3205 BreakAgain(bview, refresh_row->next());
3206 UpdateCounters(bview, refresh_row);
3208 SetHeightOfRow(bview, refresh_row);
3210 refresh_row = old_cursor.row()->next();
3211 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3214 cursor = old_cursor; // that undo can restore the right cursor position
3215 LyXParagraph * endpar = old_cursor.par()->next;
3216 if (endpar && endpar->GetDepth()) {
3217 while (endpar && endpar->GetDepth()) {
3218 endpar = endpar->LastPhysicalPar()->Next();
3221 SetUndo(bview->buffer(), Undo::DELETE,
3222 old_cursor.par()->previous,
3227 RemoveRow(old_cursor.row());
3229 if (OwnerParagraph() == old_cursor.par()) {
3230 OwnerParagraph(OwnerParagraph()->next);
3232 delete old_cursor.par();
3234 /* Breakagain the next par. Needed
3235 because of the parindent that can
3236 occur or dissappear.
3237 The next row can change its height,
3238 if there is another layout before
3241 BreakAgain(bview, refresh_row);
3242 UpdateCounters(bview, refresh_row->previous());
3248 SetCursorIntern(bview, cursor.par(), cursor.pos());
3250 if (sel_cursor.par() == old_cursor.par()
3251 && sel_cursor.pos() == sel_cursor.pos()) {
3252 // correct selection
3253 sel_cursor = cursor;
3258 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3259 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3261 SetCursorIntern(bview, cursor.par(), cursor.pos());
3262 sel_cursor = cursor;
3269 LyXParagraph * LyXText::GetParFromID(int id)
3271 LyXParagraph * result = FirstParagraph();
3272 while (result && result->id() != id)
3273 result = result->next;
3279 bool LyXText::TextUndo(BufferView * bview)
3283 // returns false if no undo possible
3284 Undo * undo = bview->buffer()->undostack.pop();
3288 bview->buffer()->redostack
3289 .push(CreateUndo(bview->buffer(), undo->kind,
3290 GetParFromID(undo->number_of_before_par),
3291 GetParFromID(undo->number_of_behind_par)));
3293 return TextHandleUndo(bview, undo);
3297 bool LyXText::TextRedo(BufferView * bview)
3301 // returns false if no redo possible
3302 Undo * undo = bview->buffer()->redostack.pop();
3306 bview->buffer()->undostack
3307 .push(CreateUndo(bview->buffer(), undo->kind,
3308 GetParFromID(undo->number_of_before_par),
3309 GetParFromID(undo->number_of_behind_par)));
3311 return TextHandleUndo(bview, undo);
3315 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3319 // returns false if no undo possible
3320 bool result = false;
3322 LyXParagraph * before =
3323 GetParFromID(undo->number_of_before_par);
3324 LyXParagraph * behind =
3325 GetParFromID(undo->number_of_behind_par);
3326 LyXParagraph * tmppar;
3327 LyXParagraph * tmppar2;
3328 LyXParagraph * endpar;
3329 LyXParagraph * tmppar5;
3331 // if there's no before take the beginning
3332 // of the document for redoing
3334 SetCursorIntern(bview, FirstParagraph(), 0);
3336 // replace the paragraphs with the undo informations
3338 LyXParagraph * tmppar3 = undo->par;
3339 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3340 LyXParagraph * tmppar4 = tmppar3;
3342 while (tmppar4->next)
3343 tmppar4 = tmppar4->next;
3344 } // get last undo par
3346 // now remove the old text if there is any
3347 if (before != behind || (!behind && !before)){
3349 tmppar5 = before->next;
3351 tmppar5 = OwnerParagraph();
3353 while (tmppar5 && tmppar5 != behind){
3355 tmppar5 = tmppar5->next;
3356 // a memory optimization for edit: Only layout information
3357 // is stored in the undo. So restore the text informations.
3358 if (undo->kind == Undo::EDIT) {
3359 tmppar2->setContentsFromPar(tmppar);
3360 tmppar->clearContents();
3361 tmppar2 = tmppar2->next;
3366 // put the new stuff in the list if there is one
3369 before->next = tmppar3;
3371 OwnerParagraph(tmppar3);
3372 tmppar3->previous = before;
3376 OwnerParagraph(behind);
3379 tmppar4->next = behind;
3381 behind->previous = tmppar4;
3385 // Set the cursor for redoing
3387 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3388 // check wether before points to a closed float and open it if necessary
3389 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3390 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3392 while (tmppar4->previous &&
3393 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3394 tmppar4 = tmppar4->previous;
3395 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3396 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3397 tmppar4 = tmppar4->next;
3402 // open a cosed footnote at the end if necessary
3403 if (behind && behind->previous &&
3404 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3405 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3406 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3407 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3408 behind = behind->next;
3412 // calculate the endpar for redoing the paragraphs.
3414 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3415 endpar = behind->LastPhysicalPar()->Next();
3417 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3421 tmppar = GetParFromID(undo->number_of_cursor_par);
3422 RedoParagraphs(bview, cursor, endpar);
3424 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3425 UpdateCounters(bview, cursor.row());
3435 void LyXText::FinishUndo()
3439 // makes sure the next operation will be stored
3440 undo_finished = true;
3444 void LyXText::FreezeUndo()
3448 // this is dangerous and for internal use only
3453 void LyXText::UnFreezeUndo()
3457 // this is dangerous and for internal use only
3458 undo_frozen = false;
3462 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3463 LyXParagraph const * before,
3464 LyXParagraph const * behind) const
3469 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3470 buf->redostack.clear();
3474 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3475 LyXParagraph const * before, LyXParagraph const * behind)
3479 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3483 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3484 LyXParagraph const * before,
3485 LyXParagraph const * behind) const
3490 int before_number = -1;
3491 int behind_number = -1;
3493 before_number = before->id();
3495 behind_number = behind->id();
3496 // Undo::EDIT and Undo::FINISH are
3497 // always finished. (no overlapping there)
3498 // overlapping only with insert and delete inside one paragraph:
3499 // Nobody wants all removed character
3500 // appear one by one when undoing.
3501 // EDIT is special since only layout information, not the
3502 // contents of a paragaph are stored.
3503 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3504 // check wether storing is needed
3505 if (!buf->undostack.empty() &&
3506 buf->undostack.top()->kind == kind &&
3507 buf->undostack.top()->number_of_before_par == before_number &&
3508 buf->undostack.top()->number_of_behind_par == behind_number ){
3513 // create a new Undo
3514 LyXParagraph * undopar;
3515 LyXParagraph * tmppar;
3516 LyXParagraph * tmppar2;
3518 LyXParagraph * start = 0;
3519 LyXParagraph * end = 0;
3522 start = before->next;
3524 start = FirstParagraph();
3526 end = behind->previous;
3528 end = FirstParagraph();
3534 && start != end->next
3535 && (before != behind || (!before && !behind))) {
3537 tmppar2 = tmppar->Clone();
3538 tmppar2->id(tmppar->id());
3540 // a memory optimization: Just store the layout information
3542 if (kind == Undo::EDIT){
3543 //tmppar2->text.clear();
3544 tmppar2->clearContents();
3549 while (tmppar != end && tmppar->next) {
3550 tmppar = tmppar->next;
3551 tmppar2->next = tmppar->Clone();
3552 tmppar2->next->id(tmppar->id());
3553 // a memory optimization: Just store the layout
3554 // information when only edit
3555 if (kind == Undo::EDIT){
3556 //tmppar2->next->text.clear();
3557 tmppar2->clearContents();
3559 tmppar2->next->previous = tmppar2;
3560 tmppar2 = tmppar2->next;
3564 undopar = 0; // nothing to replace (undo of delete maybe)
3566 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3567 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3569 Undo * undo = new Undo(kind,
3570 before_number, behind_number,
3571 cursor_par, cursor_pos,
3574 undo_finished = false;
3579 void LyXText::SetCursorParUndo(Buffer * buf)
3583 SetUndo(buf, Undo::FINISH,
3584 cursor.par()->ParFromPos(cursor.pos())->previous,
3585 cursor.par()->ParFromPos(cursor.pos())->next);
3590 void LyXText::RemoveTableRow(LyXCursor & cur) const
3596 // move to the previous row
3597 int cell_act = NumberOfCell(cur.par(), cur.pos());
3600 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3601 cur.pos(cur.pos() - 1);
3603 !cur.par()->table->IsFirstCell(cell_act)) {
3604 cur.pos(cur.pos() - 1);
3605 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3606 cur.pos(cur.pos() - 1);
3610 // now we have to pay attention if the actual table is the
3611 // main row of TableContRows and if yes to delete all of them
3616 // delete up to the next row
3617 while (cur.pos() < cur.par()->Last() &&
3619 || !cur.par()->table->IsFirstCell(cell_act))) {
3620 while (cur.pos() < cur.par()->Last() &&
3621 !cur.par()->IsNewline(cur.pos()))
3622 cur.par()->Erase(cur.pos());
3625 if (cur.pos() < cur.par()->Last())
3626 cur.par()->Erase(cur.pos());
3628 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3629 cur.pos(cur.pos() - 1);
3630 cur.par()->Erase(cur.pos()); // no newline at very end!
3632 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3633 !cur.par()->table->IsContRow(cell_org) &&
3634 cur.par()->table->IsContRow(cell));
3635 cur.par()->table->DeleteRow(cell_org);
3642 bool LyXText::IsEmptyTableCell() const
3644 LyXParagraph::size_type pos = cursor.pos() - 1;
3645 while (pos >= 0 && pos < cursor.par()->Last()
3646 && !cursor.par()->IsNewline(pos))
3648 return cursor.par()->IsNewline(pos + 1);
3653 void LyXText::toggleAppendix(BufferView * bview)
3655 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3656 bool start = !par->start_of_appendix;
3658 // ensure that we have only one start_of_appendix in this document
3659 LyXParagraph * tmp = FirstParagraph();
3660 for (; tmp; tmp = tmp->next)
3661 tmp->start_of_appendix = 0;
3662 par->start_of_appendix = start;
3664 // we can set the refreshing parameters now
3665 status = LyXText::NEED_MORE_REFRESH;
3667 refresh_row = 0; // not needed for full update
3668 UpdateCounters(bview, 0);
3669 SetCursor(bview, cursor.par(), cursor.pos());
3672 LyXParagraph * LyXText::OwnerParagraph() const
3675 return inset_owner->par;
3677 return bv_owner->buffer()->paragraph;
3681 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3684 inset_owner->par = p;
3686 bv_owner->buffer()->paragraph = p;