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)
74 status = LyXText::UNCHANGED;
75 // set cursor at the very top position
76 selection = true; /* these setting is necessary
77 because of the delete-empty-
78 paragraph mechanism in
81 LyXParagraph * par = OwnerParagraph();
82 current_font = GetFont(bv_owner->buffer(), par, 0);
84 InsertParagraph(bv_owner, par, lastrow);
87 SetCursor(bv_owner, firstrow->par(), 0);
89 current_font = LyXFont(LyXFont::ALL_SANE);
95 // no rebreak necessary
101 // Default layouttype for copy environment type
105 // Dump all rowinformation:
106 Row * tmprow = firstrow;
107 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
109 lyxerr << tmprow->baseline() << '\t'
110 << tmprow->par << '\t'
111 << tmprow->pos() << '\t'
112 << tmprow->height << '\t'
113 << tmprow->ascent_of_text << '\t'
114 << tmprow->fill << '\n';
115 tmprow = tmprow->next();
122 void LyXText::init(BufferView * bview)
127 LyXParagraph * par = OwnerParagraph();
128 current_font = GetFont(bview->buffer(), par, 0);
130 InsertParagraph(bview, par, lastrow);
133 SetCursorIntern(bview, firstrow->par(), 0);
135 // Dump all rowinformation:
136 Row * tmprow = firstrow;
137 lyxerr << "Width = " << width << endl;
138 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
140 lyxerr << tmprow->baseline() << '\t'
141 << tmprow->par() << '\t'
142 << tmprow->pos() << '\t'
143 << tmprow->height() << '\t'
144 << tmprow->ascent_of_text() << '\t'
145 << tmprow->fill() << '\n';
146 tmprow = tmprow->next();
154 // Delete all rows, this does not touch the paragraphs!
155 Row * tmprow = firstrow;
157 tmprow = firstrow->next();
165 void LyXText::owner(BufferView * bv)
167 if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
172 // Gets the fully instantiated font at a given position in a paragraph
173 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
174 // The difference is that this one is used for displaying, and thus we
175 // are allowed to make cosmetic improvements. For instance make footnotes
177 // If position is -1, we get the layout font of the paragraph.
178 // If position is -2, we get the font of the manual label of the paragraph.
179 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
180 LyXParagraph::size_type pos) const
182 LyXLayout const & layout =
183 textclasslist.Style(buf->params.textclass, par->GetLayout());
185 char par_depth = par->GetDepth();
186 // We specialize the 95% common case:
187 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
190 if (layout.labeltype == LABEL_MANUAL
191 && pos < BeginningOfMainBody(buf, par)) {
193 return par->GetFontSettings(buf->params, pos).
194 realize(layout.reslabelfont);
196 return par->GetFontSettings(buf->params, pos).
197 realize(layout.resfont);
200 // process layoutfont for pos == -1 and labelfont for pos < -1
202 return layout.resfont;
204 return layout.reslabelfont;
208 // The uncommon case need not be optimized as much
210 LyXFont layoutfont, tmpfont;
214 if (pos < BeginningOfMainBody(buf, par)) {
216 layoutfont = layout.labelfont;
219 layoutfont = layout.font;
221 tmpfont = par->GetFontSettings(buf->params, pos);
222 tmpfont.realize(layoutfont);
225 // process layoutfont for pos == -1 and labelfont for pos < -1
227 tmpfont = layout.font;
229 tmpfont = layout.labelfont;
232 // Resolve against environment font information
233 while (par && par_depth && !tmpfont.resolved()) {
234 par = par->DepthHook(par_depth - 1);
236 tmpfont.realize(textclasslist.
237 Style(buf->params.textclass,
238 par->GetLayout()).font);
239 par_depth = par->GetDepth();
243 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
245 // Cosmetic improvement: If this is an open footnote, make the font
247 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
248 && par->footnotekind == LyXParagraph::FOOTNOTE) {
256 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
257 LyXParagraph::size_type pos,
261 // Let the insets convert their font
262 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
263 if (par->GetInset(pos))
264 font = par->GetInset(pos)->ConvertFont(font);
267 LyXLayout const & layout =
268 textclasslist.Style(buf->params.textclass,
271 // Get concrete layout font to reduce against
274 if (pos < BeginningOfMainBody(buf, par))
275 layoutfont = layout.labelfont;
277 layoutfont = layout.font;
279 // Realize against environment font information
280 if (par->GetDepth()){
281 LyXParagraph * tp = par;
282 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
283 tp = tp->DepthHook(tp->GetDepth()-1);
285 layoutfont.realize(textclasslist.
286 Style(buf->params.textclass,
287 tp->GetLayout()).font);
291 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
293 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
294 && par->footnotekind == LyXParagraph::FOOTNOTE) {
295 layoutfont.decSize();
298 // Now, reduce font against full layout font
299 font.reduce(layoutfont);
301 par->SetFont(pos, font);
305 /* inserts a new row behind the specified row, increments
306 * the touched counters */
307 void LyXText::InsertRow(Row * row, LyXParagraph * par,
308 LyXParagraph::size_type pos) const
310 Row * tmprow = new Row;
313 tmprow->next(firstrow);
316 tmprow->previous(row);
317 tmprow->next(row->next());
322 tmprow->next()->previous(tmprow);
324 if (tmprow->previous())
325 tmprow->previous()->next(tmprow);
333 ++number_of_rows; // one more row
337 // removes the row and reset the touched counters
338 void LyXText::RemoveRow(Row * row) const
340 /* this must not happen before the currentrow for clear reasons.
341 so the trick is just to set the current row onto the previous
344 GetRow(row->par(), row->pos(), unused_y);
347 row->next()->previous(row->previous());
348 if (!row->previous()) {
349 firstrow = row->next();
351 row->previous()->next(row->next());
354 lastrow = row->previous();
356 height -= row->height(); // the text becomes smaller
359 --number_of_rows; // one row less
363 // remove all following rows of the paragraph of the specified row.
364 void LyXText::RemoveParagraph(Row * row) const
366 LyXParagraph * tmppar = row->par();
370 while (row && row->par() == tmppar) {
371 tmprow = row->next();
378 // insert the specified paragraph behind the specified row
379 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
382 InsertRow(row, par, 0); /* insert a new row, starting
385 SetCounter(bview->buffer(), par); // set the counters
387 // and now append the whole paragraph behind the new row
390 AppendParagraph(bview, firstrow);
392 row->next()->height(0);
393 AppendParagraph(bview, row->next());
398 void LyXText::ToggleFootnote(BufferView * bview)
400 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
402 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
404 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
406 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
407 CloseFootnote(bview);
412 void LyXText::OpenStuff(BufferView * bview)
414 if (cursor.pos() == 0 && cursor.par()->bibkey){
415 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
417 else if (cursor.pos() < cursor.par()->Last()
418 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
419 && cursor.par()->GetInset(cursor.pos())->Editable()) {
420 bview->owner()->getMiniBuffer()
421 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
422 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
423 SetCursorParUndo(bview->buffer());
424 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
426 ToggleFootnote(bview);
431 void LyXText::CloseFootnote(BufferView * bview)
433 LyXParagraph * tmppar;
434 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
436 // if the cursor is not in an open footnote, or
437 // there is no open footnote in this paragraph, just return.
438 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
441 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
442 bview->owner()->getMiniBuffer()
443 ->Set(_("Nothing to do"));
447 // ok, move the cursor right before the footnote
448 // just a little faster than using CursorRight()
450 cursor.par()->ParFromPos(cursor.pos()) != par;) {
451 cursor.pos(cursor.pos() + 1);
454 // now the cursor is at the beginning of the physical par
455 SetCursor(bview, cursor.par(),
457 cursor.par()->ParFromPos(cursor.pos())->size());
459 /* we are in a footnote, so let us move at the beginning */
460 /* this is just faster than using just CursorLeft() */
462 tmppar = cursor.par();
463 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
464 // just a little bit faster than movin the cursor
465 tmppar = tmppar->Previous();
467 SetCursor(bview, tmppar, tmppar->Last());
470 // the cursor must be exactly before the footnote
471 par = cursor.par()->ParFromPos(cursor.pos());
473 status = LyXText::NEED_MORE_REFRESH;
474 refresh_row = cursor.row();
475 refresh_y = cursor.y() - cursor.row()->baseline();
477 tmppar = cursor.par();
478 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
479 Row * row = cursor.row();
481 tmppar->CloseFootnote(cursor.pos());
483 while (tmppar != endpar) {
484 RemoveRow(row->next());
486 tmppar = row->next()->par();
491 AppendParagraph(bview, cursor.row());
493 SetCursor(bview, cursor.par(), cursor.pos());
497 if (cursor.row()->next())
498 SetHeightOfRow(bview, cursor.row()->next());
502 /* used in setlayout */
503 // Asger is not sure we want to do this...
504 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
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);
524 LyXParagraph * LyXText::SetLayout(BufferView * bview,
525 LyXCursor & cur, LyXCursor & sstart_cur,
526 LyXCursor & send_cur,
527 LyXTextClass::size_type layout)
529 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
530 LyXParagraph * undoendpar = endpar;
532 if (endpar && endpar->GetDepth()) {
533 while (endpar && endpar->GetDepth()) {
534 endpar = endpar->LastPhysicalPar()->Next();
538 endpar = endpar->Next(); // because of parindents etc.
541 SetUndo(bview->buffer(), Undo::EDIT,
542 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
545 /* ok we have a selection. This is always between sstart_cur
546 * and sel_end cursor */
549 LyXLayout const & lyxlayout =
550 textclasslist.Style(bview->buffer()->params.textclass, layout);
552 while (cur.par() != send_cur.par()) {
553 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
554 cur.par()->SetLayout(bview->buffer()->params, layout);
555 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
556 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
557 fppar->added_space_top = lyxlayout.fill_top ?
558 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
559 fppar->added_space_bottom = lyxlayout.fill_bottom ?
560 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
561 if (lyxlayout.margintype == MARGIN_MANUAL)
562 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
563 if (lyxlayout.labeltype != LABEL_BIBLIO
565 delete fppar->bibkey;
569 cur.par(cur.par()->Next());
571 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
572 cur.par()->SetLayout(bview->buffer()->params, layout);
573 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
574 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
575 fppar->added_space_top = lyxlayout.fill_top ?
576 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
577 fppar->added_space_bottom = lyxlayout.fill_bottom ?
578 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
579 if (lyxlayout.margintype == MARGIN_MANUAL)
580 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
581 if (lyxlayout.labeltype != LABEL_BIBLIO
583 delete fppar->bibkey;
590 // set layout over selection and make a total rebreak of those paragraphs
591 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
594 tmpcursor = cursor; /* store the current cursor */
596 #ifdef USE_OLD_SET_LAYOUT
597 // if there is no selection just set the layout
598 // of the current paragraph */
600 sel_start_cursor = cursor; // dummy selection
601 sel_end_cursor = cursor;
604 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
605 LyXParagraph * undoendpar = endpar;
607 if (endpar && endpar->GetDepth()) {
608 while (endpar && endpar->GetDepth()) {
609 endpar = endpar->LastPhysicalPar()->Next();
614 endpar = endpar->Next(); // because of parindents etc.
618 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
621 /* ok we have a selection. This is always between sel_start_cursor
622 * and sel_end cursor */
623 cursor = sel_start_cursor;
625 LyXLayout const & lyxlayout =
626 textclasslist.Style(bview->buffer()->params.textclass, layout);
628 while (cursor.par() != sel_end_cursor.par()) {
629 if (cursor.par()->footnoteflag ==
630 sel_start_cursor.par()->footnoteflag) {
631 cursor.par()->SetLayout(layout);
632 MakeFontEntriesLayoutSpecific(cursor.par());
633 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
634 fppar->added_space_top = lyxlayout.fill_top ?
635 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
636 fppar->added_space_bottom = lyxlayout.fill_bottom ?
637 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
638 if (lyxlayout.margintype == MARGIN_MANUAL)
639 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
640 if (lyxlayout.labeltype != LABEL_BIBLIO
642 delete fppar->bibkey;
646 cursor.par() = cursor.par()->Next();
648 if (cursor.par()->footnoteflag ==
649 sel_start_cursor.par()->footnoteflag) {
650 cursor.par()->SetLayout(layout);
651 MakeFontEntriesLayoutSpecific(cursor.par());
652 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
653 fppar->added_space_top = lyxlayout.fill_top ?
654 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
655 fppar->added_space_bottom = lyxlayout.fill_bottom ?
656 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
657 if (lyxlayout.margintype == MARGIN_MANUAL)
658 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
659 if (lyxlayout.labeltype != LABEL_BIBLIO
661 delete fppar->bibkey;
666 // if there is no selection just set the layout
667 // of the current paragraph */
669 sel_start_cursor = cursor; // dummy selection
670 sel_end_cursor = cursor;
673 endpar = SetLayout(bview, cursor, sel_start_cursor,
674 sel_end_cursor, layout);
676 RedoParagraphs(bview, sel_start_cursor, endpar);
678 // we have to reset the selection, because the
679 // geometry could have changed */
680 SetCursor(bview, sel_start_cursor.par(),
681 sel_start_cursor.pos(), false);
683 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
685 UpdateCounters(bview, cursor.row());
688 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
692 // increment depth over selection and
693 // make a total rebreak of those paragraphs
694 void LyXText::IncDepth(BufferView * bview)
696 // If there is no selection, just use the current paragraph
698 sel_start_cursor = cursor; // dummy selection
699 sel_end_cursor = cursor;
702 // We end at the next paragraph with depth 0
703 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
704 LyXParagraph * undoendpar = endpar;
706 if (endpar && endpar->GetDepth()) {
707 while (endpar && endpar->GetDepth()) {
708 endpar = endpar->LastPhysicalPar()->Next();
713 endpar = endpar->Next(); // because of parindents etc.
716 SetUndo(bview->buffer(), Undo::EDIT,
718 .par()->ParFromPos(sel_start_cursor.pos())->previous,
721 LyXCursor tmpcursor = cursor; // store the current cursor
723 // ok we have a selection. This is always between sel_start_cursor
724 // and sel_end cursor
725 cursor = sel_start_cursor;
727 bool anything_changed = false;
730 // NOTE: you can't change the depth of a bibliography entry
731 if (cursor.par()->footnoteflag ==
732 sel_start_cursor.par()->footnoteflag
733 && textclasslist.Style(bview->buffer()->params.textclass,
734 cursor.par()->GetLayout()
735 ).labeltype != LABEL_BIBLIO) {
736 LyXParagraph * prev =
737 cursor.par()->FirstPhysicalPar()->Previous();
739 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
740 || (prev->GetDepth() == cursor.par()->GetDepth()
741 && textclasslist.Style(bview->buffer()->params.textclass,
742 prev->GetLayout()).isEnvironment()))) {
743 cursor.par()->FirstPhysicalPar()->depth++;
744 anything_changed = true;
747 if (cursor.par() == sel_end_cursor.par())
749 cursor.par(cursor.par()->Next());
752 // if nothing changed set all depth to 0
753 if (!anything_changed) {
754 cursor = sel_start_cursor;
755 while (cursor.par() != sel_end_cursor.par()) {
756 cursor.par()->FirstPhysicalPar()->depth = 0;
757 cursor.par(cursor.par()->Next());
759 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
760 cursor.par()->FirstPhysicalPar()->depth = 0;
763 RedoParagraphs(bview, sel_start_cursor, endpar);
765 // we have to reset the selection, because the
766 // geometry could have changed
767 SetCursor(bview, sel_start_cursor.par(),
768 sel_start_cursor.pos());
770 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
771 UpdateCounters(bview, cursor.row());
774 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
778 // decrement depth over selection and
779 // make a total rebreak of those paragraphs
780 void LyXText::DecDepth(BufferView * bview)
782 // if there is no selection just set the layout
783 // of the current paragraph
785 sel_start_cursor = cursor; // dummy selection
786 sel_end_cursor = cursor;
789 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
790 LyXParagraph * undoendpar = endpar;
792 if (endpar && endpar->GetDepth()) {
793 while (endpar && endpar->GetDepth()) {
794 endpar = endpar->LastPhysicalPar()->Next();
799 endpar = endpar->Next(); // because of parindents etc.
802 SetUndo(bview->buffer(), Undo::EDIT,
804 .par()->ParFromPos(sel_start_cursor.pos())->previous,
807 LyXCursor tmpcursor = cursor; // store the current cursor
809 // ok we have a selection. This is always between sel_start_cursor
810 // and sel_end cursor
811 cursor = sel_start_cursor;
814 if (cursor.par()->footnoteflag ==
815 sel_start_cursor.par()->footnoteflag) {
816 if (cursor.par()->FirstPhysicalPar()->depth)
817 cursor.par()->FirstPhysicalPar()->depth--;
819 if (cursor.par() == sel_end_cursor.par())
821 cursor.par(cursor.par()->Next());
824 RedoParagraphs(bview, sel_start_cursor, endpar);
826 // we have to reset the selection, because the
827 // geometry could have changed
828 SetCursor(bview, sel_start_cursor.par(),
829 sel_start_cursor.pos());
831 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
832 UpdateCounters(bview, cursor.row());
835 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
839 // set font over selection and make a total rebreak of those paragraphs
840 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
842 // if there is no selection just set the current_font
844 // Determine basis font
846 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
848 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
850 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
851 // Update current font
852 real_current_font.update(font,
853 bview->buffer()->params.language_info,
856 // Reduce to implicit settings
857 current_font = real_current_font;
858 current_font.reduce(layoutfont);
859 // And resolve it completely
860 real_current_font.realize(layoutfont);
864 LyXCursor tmpcursor = cursor; // store the current cursor
866 // ok we have a selection. This is always between sel_start_cursor
867 // and sel_end cursor
869 SetUndo(bview->buffer(), Undo::EDIT,
870 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
871 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
872 cursor = sel_start_cursor;
873 while (cursor.par() != sel_end_cursor.par() ||
874 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
875 && cursor.pos() < sel_end_cursor.pos()))
877 if (cursor.pos() < cursor.par()->Last()
878 && cursor.par()->footnoteflag
879 == sel_start_cursor.par()->footnoteflag) {
880 // an open footnote should behave
882 LyXFont newfont = GetFont(bview->buffer(),
883 cursor.par(), cursor.pos());
885 bview->buffer()->params.language_info,
887 SetCharFont(bview->buffer(),
888 cursor.par(), cursor.pos(), newfont);
889 cursor.pos(cursor.pos() + 1);
892 cursor.par(cursor.par()->Next());
896 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
898 // we have to reset the selection, because the
899 // geometry could have changed
900 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
902 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
905 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
906 tmpcursor.boundary());
910 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
912 Row * tmprow = cur.row();
913 long y = cur.y() - tmprow->baseline();
915 SetHeightOfRow(bview, tmprow);
916 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
917 // find the first row of the paragraph
918 if (first_phys_par != tmprow->par())
919 while (tmprow->previous()
920 && tmprow->previous()->par() != first_phys_par) {
921 tmprow = tmprow->previous();
922 y -= tmprow->height();
923 SetHeightOfRow(bview, tmprow);
925 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
926 tmprow = tmprow->previous();
927 y -= tmprow->height();
928 SetHeightOfRow(bview, tmprow);
931 // we can set the refreshing parameters now
932 status = LyXText::NEED_MORE_REFRESH;
934 refresh_row = tmprow;
935 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
939 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
941 Row * tmprow = cur.row();
943 long y = cur.y() - tmprow->baseline();
944 SetHeightOfRow(bview, tmprow);
945 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
946 // find the first row of the paragraph
947 if (first_phys_par != tmprow->par())
948 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
949 tmprow = tmprow->previous();
950 y -= tmprow->height();
952 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
953 tmprow = tmprow->previous();
954 y -= tmprow->height();
957 // we can set the refreshing parameters now
958 if (status == LyXText::UNCHANGED || y < refresh_y) {
960 refresh_row = tmprow;
962 status = LyXText::NEED_MORE_REFRESH;
963 SetCursor(bview, cur.par(), cur.pos());
967 /* deletes and inserts again all paragaphs between the cursor
968 * and the specified par
969 * This function is needed after SetLayout and SetFont etc. */
970 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
971 LyXParagraph const * endpar) const
974 LyXParagraph * tmppar = 0, * first_phys_par = 0;
976 Row * tmprow = cur.row();
978 long y = cur.y() - tmprow->baseline();
980 if (!tmprow->previous()){
981 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
983 first_phys_par = tmprow->par()->FirstPhysicalPar();
984 // find the first row of the paragraph
985 if (first_phys_par != tmprow->par())
986 while (tmprow->previous() &&
987 (tmprow->previous()->par() != first_phys_par)) {
988 tmprow = tmprow->previous();
989 y -= tmprow->height();
991 while (tmprow->previous()
992 && tmprow->previous()->par() == first_phys_par) {
993 tmprow = tmprow->previous();
994 y -= tmprow->height();
998 // we can set the refreshing parameters now
999 status = LyXText::NEED_MORE_REFRESH;
1001 refresh_row = tmprow->previous(); /* the real refresh row will
1002 be deleted, so I store
1003 the previous here */
1006 tmppar = tmprow->next()->par();
1009 while (tmppar != endpar) {
1010 RemoveRow(tmprow->next());
1012 tmppar = tmprow->next()->par();
1017 // remove the first one
1018 tmprow2 = tmprow; /* this is because tmprow->previous()
1020 tmprow = tmprow->previous();
1023 tmppar = first_phys_par;
1027 InsertParagraph(bview, tmppar, tmprow);
1030 while (tmprow->next() && tmprow->next()->par() == tmppar)
1031 tmprow = tmprow->next();
1032 tmppar = tmppar->Next();
1034 } while (tmppar != endpar);
1036 // this is because of layout changes
1038 refresh_y -= refresh_row->height();
1039 SetHeightOfRow(bview, refresh_row);
1041 refresh_row = firstrow;
1043 SetHeightOfRow(bview, refresh_row);
1046 if (tmprow && tmprow->next())
1047 SetHeightOfRow(bview, tmprow->next());
1051 bool LyXText::FullRebreak(BufferView * bview)
1057 if (need_break_row) {
1058 BreakAgain(bview, need_break_row);
1066 /* important for the screen */
1069 /* the cursor set functions have a special mechanism. When they
1070 * realize, that you left an empty paragraph, they will delete it.
1071 * They also delete the corresponding row */
1073 // need the selection cursor:
1074 void LyXText::SetSelection()
1077 last_sel_cursor = sel_cursor;
1078 sel_start_cursor = sel_cursor;
1079 sel_end_cursor = sel_cursor;
1084 // first the toggling area
1085 if (cursor.y() < last_sel_cursor.y()
1086 || (cursor.y() == last_sel_cursor.y()
1087 && cursor.x() < last_sel_cursor.x())) {
1088 toggle_end_cursor = last_sel_cursor;
1089 toggle_cursor = cursor;
1091 toggle_end_cursor = cursor;
1092 toggle_cursor = last_sel_cursor;
1095 last_sel_cursor = cursor;
1097 // and now the whole selection
1099 if (sel_cursor.par() == cursor.par())
1100 if (sel_cursor.pos() < cursor.pos()) {
1101 sel_end_cursor = cursor;
1102 sel_start_cursor = sel_cursor;
1104 sel_end_cursor = sel_cursor;
1105 sel_start_cursor = cursor;
1107 else if (sel_cursor.y() < cursor.y() ||
1108 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1109 sel_end_cursor = cursor;
1110 sel_start_cursor = sel_cursor;
1113 sel_end_cursor = sel_cursor;
1114 sel_start_cursor = cursor;
1117 // a selection with no contents is not a selection
1118 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1119 sel_start_cursor.pos() == sel_end_cursor.pos())
1124 string LyXText::selectionAsString(Buffer const * buffer) const
1126 if (!selection) return string();
1129 // Special handling if the whole selection is within one paragraph
1130 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1131 result += sel_start_cursor.par()->String(buffer,
1132 sel_start_cursor.pos(),
1133 sel_end_cursor.pos());
1137 // The selection spans more than one paragraph
1139 // First paragraph in selection
1140 result += sel_start_cursor.par()->String(buffer,
1141 sel_start_cursor.pos(),
1142 sel_start_cursor.par()->Last())
1145 // The paragraphs in between (if any)
1146 LyXCursor tmpcur(sel_start_cursor);
1147 tmpcur.par(tmpcur.par()->Next());
1148 while (tmpcur.par() != sel_end_cursor.par()) {
1149 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1150 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1153 // Last paragraph in selection
1154 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1160 void LyXText::ClearSelection() const
1167 void LyXText::CursorHome(BufferView * bview) const
1169 SetCursor(bview, cursor.par(), cursor.row()->pos());
1173 void LyXText::CursorEnd(BufferView * bview) const
1175 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1176 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1178 if (cursor.par()->Last() &&
1179 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1180 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1181 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1183 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1186 if (cursor.par()->table) {
1187 int cell = NumberOfCell(cursor.par(), cursor.pos());
1188 if (cursor.par()->table->RowHasContRow(cell) &&
1189 cursor.par()->table->CellHasContRow(cell)<0) {
1190 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1191 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1193 if (cursor.par()->Last() &&
1194 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1195 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1196 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1198 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1206 void LyXText::CursorTop(BufferView * bview) const
1208 while (cursor.par()->Previous())
1209 cursor.par(cursor.par()->Previous());
1210 SetCursor(bview, cursor.par(), 0);
1214 void LyXText::CursorBottom(BufferView * bview) const
1216 while (cursor.par()->Next())
1217 cursor.par(cursor.par()->Next());
1218 SetCursor(bview, cursor.par(), cursor.par()->Last());
1222 /* returns a pointer to the row near the specified y-coordinate
1223 * (relative to the whole text). y is set to the real beginning
1225 Row * LyXText::GetRowNearY(long & y) const
1227 Row * tmprow = firstrow;
1230 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1231 tmpy += tmprow->height();
1232 tmprow = tmprow->next();
1235 y = tmpy; // return the real y
1240 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1242 // If the mask is completely neutral, tell user
1243 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1244 // Could only happen with user style
1245 bview->owner()->getMiniBuffer()
1246 ->Set(_("No font change defined. Use Character under"
1247 " the Layout menu to define font change."));
1251 // Try implicit word selection
1252 // If there is a change in the language the implicit word selection
1254 LyXCursor resetCursor = cursor;
1255 bool implicitSelection = (font.language() == ignore_language)
1256 ? SelectWordWhenUnderCursor(bview) : false;
1259 SetFont(bview, font, toggleall);
1261 /* Implicit selections are cleared afterwards and cursor is set to the
1262 original position. */
1263 if (implicitSelection) {
1265 cursor = resetCursor;
1266 SetCursor(bview, cursor.par(), cursor.pos());
1267 sel_cursor = cursor;
1272 LyXParagraph::size_type
1273 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1275 if (textclasslist.Style(buf->params.textclass,
1276 par->GetLayout()).labeltype != LABEL_MANUAL)
1279 return par->BeginningOfMainBody();
1283 /* if there is a selection, reset every environment you can find
1284 * in the selection, otherwise just the environment you are in */
1285 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1287 LyXParagraph * tmppar, * firsttmppar;
1291 /* is is only allowed, if the cursor is IN an open footnote.
1292 * Otherwise it is too dangerous */
1293 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1296 SetUndo(bview->buffer(), Undo::FINISH,
1297 cursor.par()->PreviousBeforeFootnote()->previous,
1298 cursor.par()->NextAfterFootnote()->next);
1300 /* ok, move to the beginning of the footnote. */
1301 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1302 cursor.par(cursor.par()->Previous());
1304 SetCursor(bview, cursor.par(), cursor.par()->Last());
1305 /* this is just faster than using CursorLeft(); */
1307 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1308 tmppar = firsttmppar;
1309 /* tmppar is now the paragraph right before the footnote */
1311 bool first_footnote_par_is_not_empty = tmppar->next->size();
1314 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1315 tmppar = tmppar->next; /* I use next instead of Next(),
1316 * because there cannot be any
1317 * footnotes in a footnote
1319 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1321 /* remember the captions and empty paragraphs */
1322 if ((textclasslist.Style(bview->buffer()->params.textclass,
1323 tmppar->GetLayout())
1324 .labeltype == LABEL_SENSITIVE)
1326 tmppar->SetLayout(bview->buffer()->params, 0);
1329 // now we will paste the ex-footnote, if the layouts allow it
1330 // first restore the layout of the paragraph right behind
1333 tmppar->next->MakeSameLayout(cursor.par());
1336 if ((!tmppar->GetLayout() && !tmppar->table)
1338 && (!tmppar->Next()->Last()
1339 || tmppar->Next()->HasSameLayout(tmppar)))) {
1340 if (tmppar->Next()->Last()
1341 && tmppar->Next()->IsLineSeparator(0))
1342 tmppar->Next()->Erase(0);
1343 tmppar->PasteParagraph(bview->buffer()->params);
1346 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1347 * by the pasting of the beginning */
1349 /* then the beginning */
1350 /* if there is no space between the text and the footnote, so we insert
1352 * (only if the previous par and the footnotepar are not empty!) */
1353 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1354 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1355 if (firsttmppar->size()
1356 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1357 && first_footnote_par_is_not_empty) {
1358 firsttmppar->next->InsertChar(0, ' ');
1360 firsttmppar->PasteParagraph(bview->buffer()->params);
1363 /* now redo the paragaphs */
1364 RedoParagraphs(bview, cursor, tmppar);
1366 SetCursor(bview, cursor.par(), cursor.pos());
1368 /* sometimes it can happen, that there is a counter change */
1369 Row * row = cursor.row();
1370 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1372 UpdateCounters(bview, row);
1379 /* the DTP switches for paragraphs. LyX will store them in the
1380 * first physicla paragraph. When a paragraph is broken, the top settings
1381 * rest, the bottom settings are given to the new one. So I can make shure,
1382 * they do not duplicate themself and you cannnot make dirty things with
1385 void LyXText::SetParagraph(BufferView * bview,
1386 bool line_top, bool line_bottom,
1387 bool pagebreak_top, bool pagebreak_bottom,
1388 VSpace const & space_top,
1389 VSpace const & space_bottom,
1391 string labelwidthstring,
1394 LyXCursor tmpcursor = cursor;
1396 sel_start_cursor = cursor;
1397 sel_end_cursor = cursor;
1400 // make sure that the depth behind the selection are restored, too
1401 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1402 LyXParagraph * undoendpar = endpar;
1404 if (endpar && endpar->GetDepth()) {
1405 while (endpar && endpar->GetDepth()) {
1406 endpar = endpar->LastPhysicalPar()->Next();
1407 undoendpar = endpar;
1411 endpar = endpar->Next(); // because of parindents etc.
1414 SetUndo(bview->buffer(), Undo::EDIT,
1416 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1420 LyXParagraph * tmppar = sel_end_cursor.par();
1421 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1422 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1423 status = LyXText::NEED_MORE_REFRESH;
1424 refresh_row = cursor.row();
1425 refresh_y = cursor.y() - cursor.row()->baseline();
1426 if (cursor.par()->footnoteflag ==
1427 sel_start_cursor.par()->footnoteflag) {
1428 cursor.par()->line_top = line_top;
1429 cursor.par()->line_bottom = line_bottom;
1430 cursor.par()->pagebreak_top = pagebreak_top;
1431 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1432 cursor.par()->added_space_top = space_top;
1433 cursor.par()->added_space_bottom = space_bottom;
1434 // does the layout allow the new alignment?
1435 if (align == LYX_ALIGN_LAYOUT)
1436 align = textclasslist
1437 .Style(bview->buffer()->params.textclass,
1438 cursor.par()->GetLayout()).align;
1439 if (align & textclasslist
1440 .Style(bview->buffer()->params.textclass,
1441 cursor.par()->GetLayout()).alignpossible) {
1442 if (align == textclasslist
1443 .Style(bview->buffer()->params.textclass,
1444 cursor.par()->GetLayout()).align)
1445 cursor.par()->align = LYX_ALIGN_LAYOUT;
1447 cursor.par()->align = align;
1449 cursor.par()->SetLabelWidthString(labelwidthstring);
1450 cursor.par()->noindent = noindent;
1453 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1456 RedoParagraphs(bview, sel_start_cursor, endpar);
1459 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1460 sel_cursor = cursor;
1461 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1463 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1467 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1469 char const * widthp,
1470 int alignment, bool hfill,
1471 bool start_minipage)
1473 LyXCursor tmpcursor = cursor;
1474 LyXParagraph * tmppar;
1476 sel_start_cursor = cursor;
1477 sel_end_cursor = cursor;
1480 // make sure that the depth behind the selection are restored, too
1481 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1482 LyXParagraph * undoendpar = endpar;
1484 if (endpar && endpar->GetDepth()) {
1485 while (endpar && endpar->GetDepth()) {
1486 endpar = endpar->LastPhysicalPar()->Next();
1487 undoendpar = endpar;
1491 endpar = endpar->Next(); // because of parindents etc.
1494 SetUndo(bview->buffer(), Undo::EDIT,
1496 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1499 tmppar = sel_end_cursor.par();
1500 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1501 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1502 status = LyXText::NEED_MORE_REFRESH;
1503 refresh_row = cursor.row();
1504 refresh_y = cursor.y() - cursor.row()->baseline();
1505 if (cursor.par()->footnoteflag ==
1506 sel_start_cursor.par()->footnoteflag) {
1507 if (type == LyXParagraph::PEXTRA_NONE) {
1508 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1509 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1510 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1513 cursor.par()->SetPExtraType(bview->buffer()->params,
1514 type, width, widthp);
1515 cursor.par()->pextra_hfill = hfill;
1516 cursor.par()->pextra_start_minipage = start_minipage;
1517 cursor.par()->pextra_alignment = alignment;
1520 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1522 RedoParagraphs(bview, sel_start_cursor, endpar);
1524 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1525 sel_cursor = cursor;
1526 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1528 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1532 char loweralphaCounter(int n)
1534 if (n < 1 || n > 26)
1540 char alphaCounter(int n)
1542 if (n < 1 || n > 26)
1548 char hebrewCounter(int n)
1550 static const char hebrew[22] = {
1551 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1552 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1553 '÷', 'ø', 'ù', 'ú'
1555 if (n < 1 || n > 22)
1561 static char const * romanCounter(int n)
1563 static char const * roman[20] = {
1564 "i", "ii", "iii", "iv", "v",
1565 "vi", "vii", "viii", "ix", "x",
1566 "xi", "xii", "xiii", "xiv", "xv",
1567 "xvi", "xvii", "xviii", "xix", "xx"
1569 if (n < 1 || n > 20)
1575 // set the counter of a paragraph. This includes the labels
1576 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1578 // this is only relevant for the beginning of paragraph
1579 par = par->FirstPhysicalPar();
1581 LyXLayout const & layout =
1582 textclasslist.Style(buf->params.textclass,
1585 LyXTextClass const & textclass =
1586 textclasslist.TextClass(buf->params.textclass);
1588 /* copy the prev-counters to this one, unless this is the start of a
1589 footnote or of a bibliography or the very first paragraph */
1591 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1592 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1593 && par->footnotekind == LyXParagraph::FOOTNOTE)
1594 && !(textclasslist.Style(buf->params.textclass,
1595 par->Previous()->GetLayout()
1596 ).labeltype != LABEL_BIBLIO
1597 && layout.labeltype == LABEL_BIBLIO)) {
1598 for (int i = 0; i < 10; ++i) {
1599 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1601 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1602 if (!par->appendix && par->start_of_appendix){
1603 par->appendix = true;
1604 for (int i = 0; i < 10; ++i) {
1605 par->setCounter(i, 0);
1608 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1609 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1612 for (int i = 0; i < 10; ++i) {
1613 par->setCounter(i, 0);
1615 par->appendix = par->start_of_appendix;
1620 // if this is an open marginnote and this is the first
1621 // entry in the marginnote and the enclosing
1622 // environment is an enum/item then correct for the
1623 // LaTeX behaviour (ARRae)
1624 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1625 && par->footnotekind == LyXParagraph::MARGIN
1627 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1628 && (par->PreviousBeforeFootnote()
1629 && textclasslist.Style(buf->params.textclass,
1630 par->PreviousBeforeFootnote()->GetLayout()
1631 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1632 // Any itemize or enumerate environment in a marginnote
1633 // that is embedded in an itemize or enumerate
1634 // paragraph is seen by LaTeX as being at a deeper
1635 // level within that enclosing itemization/enumeration
1636 // even if there is a "standard" layout at the start of
1642 /* Maybe we have to increment the enumeration depth.
1643 * BUT, enumeration in a footnote is considered in isolation from its
1644 * surrounding paragraph so don't increment if this is the
1645 * first line of the footnote
1646 * AND, bibliographies can't have their depth changed ie. they
1647 * are always of depth 0
1650 && par->Previous()->GetDepth() < par->GetDepth()
1651 && textclasslist.Style(buf->params.textclass,
1652 par->Previous()->GetLayout()
1653 ).labeltype == LABEL_COUNTER_ENUMI
1654 && par->enumdepth < 3
1655 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1656 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1657 && par->footnotekind == LyXParagraph::FOOTNOTE)
1658 && layout.labeltype != LABEL_BIBLIO) {
1662 /* Maybe we have to decrement the enumeration depth, see note above */
1664 && par->Previous()->GetDepth() > par->GetDepth()
1665 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1666 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1667 && par->footnotekind == LyXParagraph::FOOTNOTE)
1668 && layout.labeltype != LABEL_BIBLIO) {
1669 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1670 par->setCounter(6 + par->enumdepth,
1671 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1672 /* reset the counters.
1673 * A depth change is like a breaking layout
1675 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1676 par->setCounter(i, 0);
1679 if (!par->labelstring.empty()) {
1680 par->labelstring.erase();
1683 if (layout.margintype == MARGIN_MANUAL) {
1684 if (par->labelwidthstring.empty()) {
1685 par->SetLabelWidthString(layout.labelstring());
1688 par->SetLabelWidthString(string());
1691 /* is it a layout that has an automatic label ? */
1692 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1694 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1695 if (i >= 0 && i<= buf->params.secnumdepth) {
1696 par->incCounter(i); // increment the counter
1698 // Is there a label? Useful for Chapter layout
1699 if (!par->appendix){
1700 if (!layout.labelstring().empty())
1701 par->labelstring = layout.labelstring();
1703 par->labelstring.erase();
1705 if (!layout.labelstring_appendix().empty())
1706 par->labelstring = layout.labelstring_appendix();
1708 par->labelstring.erase();
1712 std::ostringstream s;
1716 if (!par->appendix) {
1717 switch (2 * LABEL_FIRST_COUNTER -
1718 textclass.maxcounter() + i) {
1719 case LABEL_COUNTER_CHAPTER:
1720 s << par->getCounter(i);
1722 case LABEL_COUNTER_SECTION:
1723 s << par->getCounter(i - 1) << '.'
1724 << par->getCounter(i);
1726 case LABEL_COUNTER_SUBSECTION:
1727 s << par->getCounter(i - 2) << '.'
1728 << par->getCounter(i - 1) << '.'
1729 << par->getCounter(i);
1731 case LABEL_COUNTER_SUBSUBSECTION:
1732 s << par->getCounter(i - 3) << '.'
1733 << par->getCounter(i - 2) << '.'
1734 << par->getCounter(i - 1) << '.'
1735 << par->getCounter(i);
1738 case LABEL_COUNTER_PARAGRAPH:
1739 s << par->getCounter(i - 4) << '.'
1740 << par->getCounter(i - 3) << '.'
1741 << par->getCounter(i - 2) << '.'
1742 << par->getCounter(i - 1) << '.'
1743 << par->getCounter(i);
1745 case LABEL_COUNTER_SUBPARAGRAPH:
1746 s << par->getCounter(i - 5) << '.'
1747 << par->getCounter(i - 4) << '.'
1748 << par->getCounter(i - 3) << '.'
1749 << par->getCounter(i - 2) << '.'
1750 << par->getCounter(i - 1) << '.'
1751 << par->getCounter(i);
1755 s << par->getCounter(i) << '.';
1758 } else { // appendix
1759 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1760 case LABEL_COUNTER_CHAPTER:
1761 if (par->isRightToLeftPar(buf->params))
1762 s << hebrewCounter(par->getCounter(i));
1764 s << alphaCounter(par->getCounter(i));
1766 case LABEL_COUNTER_SECTION:
1767 if (par->isRightToLeftPar(buf->params))
1768 s << hebrewCounter(par->getCounter(i - 1));
1770 s << alphaCounter(par->getCounter(i - 1));
1773 << par->getCounter(i);
1776 case LABEL_COUNTER_SUBSECTION:
1777 if (par->isRightToLeftPar(buf->params))
1778 s << hebrewCounter(par->getCounter(i - 2));
1780 s << alphaCounter(par->getCounter(i - 2));
1783 << par->getCounter(i-1) << '.'
1784 << par->getCounter(i);
1787 case LABEL_COUNTER_SUBSUBSECTION:
1788 if (par->isRightToLeftPar(buf->params))
1789 s << hebrewCounter(par->getCounter(i-3));
1791 s << alphaCounter(par->getCounter(i-3));
1794 << par->getCounter(i-2) << '.'
1795 << par->getCounter(i-1) << '.'
1796 << par->getCounter(i);
1799 case LABEL_COUNTER_PARAGRAPH:
1800 if (par->isRightToLeftPar(buf->params))
1801 s << hebrewCounter(par->getCounter(i-4));
1803 s << alphaCounter(par->getCounter(i-4));
1806 << par->getCounter(i-3) << '.'
1807 << par->getCounter(i-2) << '.'
1808 << par->getCounter(i-1) << '.'
1809 << par->getCounter(i);
1812 case LABEL_COUNTER_SUBPARAGRAPH:
1813 if (par->isRightToLeftPar(buf->params))
1814 s << hebrewCounter(par->getCounter(i-5));
1816 s << alphaCounter(par->getCounter(i-5));
1819 << par->getCounter(i-4) << '.'
1820 << par->getCounter(i-3) << '.'
1821 << par->getCounter(i-2) << '.'
1822 << par->getCounter(i-1) << '.'
1823 << par->getCounter(i);
1827 // Can this ever be reached? And in the
1828 // case it is, how can this be correct?
1830 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1836 par->labelstring += s.str().c_str();
1837 // We really want to remove the c_str as soon as
1841 char * tmps = s.str();
1842 par->labelstring += tmps;
1846 for (i++; i < 10; ++i) {
1847 // reset the following counters
1848 par->setCounter(i, 0);
1850 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1851 for (i++; i < 10; ++i) {
1852 // reset the following counters
1853 par->setCounter(i, 0);
1855 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1856 par->incCounter(i + par->enumdepth);
1857 int number = par->getCounter(i + par->enumdepth);
1860 std::ostringstream s;
1864 switch (par->enumdepth) {
1866 if (par->isRightToLeftPar(buf->params))
1868 << hebrewCounter(number)
1872 << loweralphaCounter(number)
1876 if (par->isRightToLeftPar(buf->params))
1877 s << '.' << romanCounter(number);
1879 s << romanCounter(number) << '.';
1882 if (par->isRightToLeftPar(buf->params))
1884 << alphaCounter(number);
1886 s << alphaCounter(number)
1890 if (par->isRightToLeftPar(buf->params))
1897 par->labelstring = s.str().c_str();
1898 // we really want to get rid of that c_str()
1901 char * tmps = s.str();
1902 par->labelstring = tmps;
1906 for (i += par->enumdepth + 1; i < 10; ++i)
1907 par->setCounter(i, 0); /* reset the following counters */
1910 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1911 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1913 int number = par->getCounter(i);
1915 par->bibkey = new InsetBibKey();
1916 par->bibkey->setCounter(number);
1917 par->labelstring = layout.labelstring();
1919 // In biblio should't be following counters but...
1921 string s = layout.labelstring();
1923 // the caption hack:
1925 if (layout.labeltype == LABEL_SENSITIVE) {
1926 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1927 && (par->footnotekind == LyXParagraph::FIG
1928 || par->footnotekind == LyXParagraph::WIDE_FIG))
1929 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1930 ? ":øåéà " : "Figure:";
1931 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1932 && (par->footnotekind == LyXParagraph::TAB
1933 || par->footnotekind == LyXParagraph::WIDE_TAB))
1934 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1935 ? ":äìáè" : "Table:";
1936 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1937 && par->footnotekind == LyXParagraph::ALGORITHM)
1938 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1939 ? ":Ãúéøåâìà " : "Algorithm:";
1941 /* par->SetLayout(0);
1942 s = layout->labelstring; */
1943 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1944 ? " :úåòîùî øñç" : "Senseless: ";
1947 par->labelstring = s;
1949 /* reset the enumeration counter. They are always resetted
1950 * when there is any other layout between */
1951 for (int i = 6 + par->enumdepth; i < 10; ++i)
1952 par->setCounter(i, 0);
1957 /* Updates all counters BEHIND the row. Changed paragraphs
1958 * with a dynamic left margin will be rebroken. */
1959 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1967 if (row->par()->next
1968 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1969 par = row->par()->LastPhysicalPar()->Next();
1971 par = row->par()->next;
1976 while (row->par() != par)
1979 SetCounter(bview->buffer(), par);
1981 /* now check for the headline layouts. remember that they
1982 * have a dynamic left margin */
1984 && ( textclasslist.Style(bview->buffer()->params.textclass,
1985 par->layout).margintype == MARGIN_DYNAMIC
1986 || textclasslist.Style(bview->buffer()->params.textclass,
1987 par->layout).labeltype == LABEL_SENSITIVE)
1990 /* Rebreak the paragraph */
1991 RemoveParagraph(row);
1992 AppendParagraph(bview, row);
1994 /* think about the damned open footnotes! */
1995 while (par->Next() &&
1996 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1997 || par->Next()->IsDummy())){
1999 if (par->IsDummy()) {
2000 while (row->par() != par)
2002 RemoveParagraph(row);
2003 AppendParagraph(bview, row);
2008 par = par->LastPhysicalPar()->Next();
2014 /* insets an inset. */
2015 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2017 if (!cursor.par()->InsertInsetAllowed(inset))
2019 SetUndo(bview->buffer(), Undo::INSERT,
2020 cursor.par()->ParFromPos(cursor.pos())->previous,
2021 cursor.par()->ParFromPos(cursor.pos())->next);
2022 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2023 cursor.par()->InsertInset(cursor.pos(), inset);
2024 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2025 * The character will not be inserted a
2030 void LyXText::copyEnvironmentType()
2032 copylayouttype = cursor.par()->GetLayout();
2036 void LyXText::pasteEnvironmentType(BufferView * bview)
2038 SetLayout(bview, copylayouttype);
2042 void LyXText::CutSelection(BufferView * bview, bool doclear)
2044 // Stuff what we got on the clipboard. Even if there is no selection.
2046 // There is a problem with having the stuffing here in that the
2047 // larger the selection the slower LyX will get. This can be
2048 // solved by running the line below only when the selection has
2049 // finished. The solution used currently just works, to make it
2050 // faster we need to be more clever and probably also have more
2051 // calls to stuffClipboard. (Lgb)
2052 bview->stuffClipboard(selectionAsString(bview->buffer()));
2054 // This doesn't make sense, if there is no selection
2058 // OK, we have a selection. This is always between sel_start_cursor
2059 // and sel_end cursor
2060 LyXParagraph * tmppar;
2062 // Check whether there are half footnotes in the selection
2063 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2064 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2065 tmppar = sel_start_cursor.par();
2066 while (tmppar != sel_end_cursor.par()){
2067 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2068 WriteAlert(_("Impossible operation"),
2069 _("Don't know what to do with half floats."),
2073 tmppar = tmppar->Next();
2078 /* table stuff -- begin */
2079 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2080 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2081 WriteAlert(_("Impossible operation"),
2082 _("Don't know what to do with half tables."),
2086 sel_start_cursor.par()->table->Reinit();
2088 /* table stuff -- end */
2090 // make sure that the depth behind the selection are restored, too
2091 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2092 LyXParagraph * undoendpar = endpar;
2094 if (endpar && endpar->GetDepth()) {
2095 while (endpar && endpar->GetDepth()) {
2096 endpar = endpar->LastPhysicalPar()->Next();
2097 undoendpar = endpar;
2099 } else if (endpar) {
2100 endpar = endpar->Next(); // because of parindents etc.
2103 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2104 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2108 // there are two cases: cut only within one paragraph or
2109 // more than one paragraph
2110 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2111 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2112 // only within one paragraph
2113 endpar = sel_start_cursor.par();
2114 int pos = sel_end_cursor.pos();
2115 cap.cutSelection(sel_start_cursor.par(), &endpar,
2116 sel_start_cursor.pos(), pos,
2117 bview->buffer()->params.textclass, doclear);
2118 sel_end_cursor.pos(pos);
2120 endpar = sel_end_cursor.par();
2122 int pos = sel_end_cursor.pos();
2123 cap.cutSelection(sel_start_cursor.par(), &endpar,
2124 sel_start_cursor.pos(), pos,
2125 bview->buffer()->params.textclass, doclear);
2127 sel_end_cursor.par(endpar);
2128 sel_end_cursor.pos(pos);
2129 cursor.pos(sel_end_cursor.pos());
2131 endpar = endpar->Next();
2133 // sometimes necessary
2135 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2137 RedoParagraphs(bview, sel_start_cursor, endpar);
2140 cursor = sel_start_cursor;
2141 SetCursor(bview, cursor.par(), cursor.pos());
2142 sel_cursor = cursor;
2143 UpdateCounters(bview, cursor.row());
2147 void LyXText::CopySelection(BufferView * bview)
2149 // Stuff what we got on the clipboard. Even if there is no selection.
2151 // There is a problem with having the stuffing here in that the
2152 // larger the selection the slower LyX will get. This can be
2153 // solved by running the line below only when the selection has
2154 // finished. The solution used currently just works, to make it
2155 // faster we need to be more clever and probably also have more
2156 // calls to stuffClipboard. (Lgb)
2157 bview->stuffClipboard(selectionAsString(bview->buffer()));
2159 // this doesnt make sense, if there is no selection
2163 // ok we have a selection. This is always between sel_start_cursor
2164 // and sel_end cursor
2165 LyXParagraph * tmppar;
2167 /* check wether there are half footnotes in the selection */
2168 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2169 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2170 tmppar = sel_start_cursor.par();
2171 while (tmppar != sel_end_cursor.par()) {
2172 if (tmppar->footnoteflag !=
2173 sel_end_cursor.par()->footnoteflag) {
2174 WriteAlert(_("Impossible operation"),
2175 _("Don't know what to do"
2176 " with half floats."),
2180 tmppar = tmppar->Next();
2185 /* table stuff -- begin */
2186 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2187 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2188 WriteAlert(_("Impossible operation"),
2189 _("Don't know what to do with half tables."),
2194 /* table stuff -- end */
2197 // copy behind a space if there is one
2198 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2199 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2200 && (sel_start_cursor.par() != sel_end_cursor.par()
2201 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2202 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2206 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2207 sel_start_cursor.pos(), sel_end_cursor.pos(),
2208 bview->buffer()->params.textclass);
2212 void LyXText::PasteSelection(BufferView * bview)
2216 // this does not make sense, if there is nothing to paste
2217 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2220 SetUndo(bview->buffer(), Undo::INSERT,
2221 cursor.par()->ParFromPos(cursor.pos())->previous,
2222 cursor.par()->ParFromPos(cursor.pos())->next);
2224 LyXParagraph * endpar;
2225 LyXParagraph * actpar = cursor.par();
2227 int pos = cursor.pos();
2228 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2230 RedoParagraphs(bview, cursor, endpar);
2232 SetCursor(bview, cursor.par(), cursor.pos());
2235 sel_cursor = cursor;
2236 SetCursor(bview, actpar, pos);
2238 UpdateCounters(bview, cursor.row());
2242 // returns a pointer to the very first LyXParagraph
2243 LyXParagraph * LyXText::FirstParagraph() const
2245 return OwnerParagraph();
2249 // returns true if the specified string is at the specified position
2250 bool LyXText::IsStringInText(LyXParagraph * par,
2251 LyXParagraph::size_type pos,
2252 char const * str) const
2256 while (pos + i < par->Last() && str[i] &&
2257 str[i] == par->GetChar(pos + i)) {
2267 // sets the selection over the number of characters of string, no check!!
2268 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2270 sel_cursor = cursor;
2271 for (int i = 0; string[i]; ++i)
2277 // simple replacing. The font of the first selected character is used
2278 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2280 SetCursorParUndo(bview->buffer());
2283 if (!selection) { // create a dummy selection
2284 sel_end_cursor = cursor;
2285 sel_start_cursor = cursor;
2288 // Get font setting before we cut
2289 LyXParagraph::size_type pos = sel_end_cursor.pos();
2290 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2291 sel_start_cursor.pos());
2293 // Insert the new string
2294 for (int i = 0; str[i]; ++i) {
2295 sel_end_cursor.par()->InsertChar(pos, str[i]);
2296 sel_end_cursor.par()->SetFont(pos, font);
2300 // Cut the selection
2301 CutSelection(bview);
2307 // if the string can be found: return true and set the cursor to
2309 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2311 LyXParagraph * par = cursor.par();
2312 LyXParagraph::size_type pos = cursor.pos();
2313 while (par && !IsStringInText(par, pos, str)) {
2314 if (pos < par->Last() - 1)
2322 SetCursor(bview, par, pos);
2330 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2332 LyXParagraph * par = cursor.par();
2333 int pos = cursor.pos();
2339 // We skip empty paragraphs (Asger)
2341 par = par->Previous();
2343 pos = par->Last() - 1;
2344 } while (par && pos < 0);
2346 } while (par && !IsStringInText(par, pos, string));
2349 SetCursor(bview, par, pos);
2356 // needed to insert the selection
2357 void LyXText::InsertStringA(BufferView * bview, string const & str)
2359 LyXParagraph * par = cursor.par();
2360 LyXParagraph::size_type pos = cursor.pos();
2361 LyXParagraph::size_type a = 0;
2363 LyXParagraph * endpar = cursor.par()->Next();
2365 SetCursorParUndo(bview->buffer());
2368 textclasslist.Style(bview->buffer()->params.textclass,
2369 cursor.par()->GetLayout()).isEnvironment();
2370 // only to be sure, should not be neccessary
2373 // insert the string, don't insert doublespace
2374 string::size_type i = 0;
2375 while (i < str.length()) {
2376 if (str[i] != '\n') {
2378 && i + 1 < str.length() && str[i + 1] != ' '
2379 && pos && par->GetChar(pos - 1)!= ' ') {
2380 par->InsertChar(pos,' ');
2381 par->SetFont(pos, current_font);
2384 } else if (par->table) {
2385 if (str[i] == '\t') {
2386 while((pos < par->size()) &&
2387 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2389 if (pos < par->size())
2391 else // no more fields to fill skip the rest
2393 } else if ((str[i] != 13) &&
2394 ((str[i] & 127) >= ' ')) {
2395 par->InsertChar(pos, str[i]);
2396 par->SetFont(pos, current_font);
2400 } else if (str[i] == ' ') {
2401 InsetSpecialChar * new_inset =
2402 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2403 if (par->InsertInsetAllowed(new_inset)) {
2404 par->InsertChar(pos, LyXParagraph::META_INSET);
2405 par->SetFont(pos, current_font);
2406 par->InsertInset(pos, new_inset);
2411 } else if (str[i] == '\t') {
2412 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2413 InsetSpecialChar * new_inset =
2414 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2415 if (par->InsertInsetAllowed(new_inset)) {
2416 par->InsertChar(pos, LyXParagraph::META_INSET);
2417 par->SetFont(pos, current_font);
2418 par->InsertInset(pos, new_inset);
2424 } else if (str[i] != 13 &&
2425 // Ignore unprintables
2426 (str[i] & 127) >= ' ') {
2427 par->InsertChar(pos, str[i]);
2428 par->SetFont(pos, current_font);
2434 if ((i + 1) >= str.length()) {
2435 if (pos < par->size())
2439 while((pos < par->size()) &&
2440 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2443 cell = NumberOfCell(par, pos);
2444 while((pos < par->size()) &&
2445 !(par->table->IsFirstCell(cell))) {
2447 while((pos < par->size()) &&
2448 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2451 cell = NumberOfCell(par, pos);
2453 if (pos >= par->size())
2454 // no more fields to fill skip the rest
2458 if (!par->size()) { // par is empty
2459 InsetSpecialChar * new_inset =
2460 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2461 if (par->InsertInsetAllowed(new_inset)) {
2462 par->InsertChar(pos, LyXParagraph::META_INSET);
2463 par->SetFont(pos, current_font);
2464 par->InsertInset(pos, new_inset);
2470 par->BreakParagraph(bview->buffer()->params, pos, flag);
2480 RedoParagraphs(bview, cursor, endpar);
2481 SetCursor(bview, cursor.par(), cursor.pos());
2482 sel_cursor = cursor;
2483 SetCursor(bview, par, pos);
2488 /* turns double-CR to single CR, others where converted into one blank and 13s
2489 * that are ignored .Double spaces are also converted into one. Spaces at
2490 * the beginning of a paragraph are forbidden. tabs are converted into one
2491 * space. then InsertStringA is called */
2492 void LyXText::InsertStringB(BufferView * bview, string const & s)
2495 LyXParagraph * par = cursor.par();
2496 string::size_type i = 1;
2497 while (i < str.length()) {
2498 if (str[i] == '\t' && !par->table)
2500 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2502 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2503 if (str[i + 1] != '\n') {
2504 if (str[i - 1] != ' ')
2509 while (i + 1 < str.length()
2510 && (str[i + 1] == ' '
2511 || str[i + 1] == '\t'
2512 || str[i + 1] == '\n'
2513 || str[i + 1] == 13)) {
2520 InsertStringA(bview, str);
2524 bool LyXText::GotoNextError(BufferView * bview) const
2526 LyXCursor res = cursor;
2528 if (res.pos() < res.par()->Last() - 1) {
2529 res.pos(res.pos() + 1);
2531 res.par(res.par()->Next());
2535 } while (res.par() &&
2536 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2537 && res.par()->GetInset(res.pos())->AutoDelete()));
2540 SetCursor(bview, res.par(), res.pos());
2547 bool LyXText::GotoNextNote(BufferView * bview) const
2549 LyXCursor res = cursor;
2551 if (res.pos() < res.par()->Last() - 1) {
2552 res.pos(res.pos() + 1);
2554 res.par(res.par()->Next());
2558 } while (res.par() &&
2559 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2560 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2563 SetCursor(bview, res.par(), res.pos());
2570 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2571 LyXParagraph::size_type pos)
2573 LyXCursor tmpcursor;
2576 /* table stuff -- begin*/
2579 CheckParagraphInTable(bview, par, pos);
2583 /* table stuff -- end*/
2586 LyXParagraph::size_type z;
2587 Row * row = GetRow(par, pos, y);
2589 // is there a break one row above
2590 if (row->previous() && row->previous()->par() == row->par()) {
2591 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2592 if ( z >= row->pos()) {
2593 // set the dimensions of the row above
2594 y -= row->previous()->height();
2596 refresh_row = row->previous();
2597 status = LyXText::NEED_MORE_REFRESH;
2599 BreakAgain(bview, row->previous());
2601 // set the cursor again. Otherwise
2602 // dangling pointers are possible
2603 SetCursor(bview, cursor.par(), cursor.pos());
2604 sel_cursor = cursor;
2609 int tmpheight = row->height();
2610 LyXParagraph::size_type tmplast = RowLast(row);
2614 BreakAgain(bview, row);
2615 if (row->height() == tmpheight && RowLast(row) == tmplast)
2616 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2618 status = LyXText::NEED_MORE_REFRESH;
2620 // check the special right address boxes
2621 if (textclasslist.Style(bview->buffer()->params.textclass,
2622 par->GetLayout()).margintype
2623 == MARGIN_RIGHT_ADDRESS_BOX) {
2630 RedoDrawingOfParagraph(bview, tmpcursor);
2636 // set the cursor again. Otherwise dangling pointers are possible
2637 // also set the selection
2641 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2642 sel_cursor = cursor;
2643 SetCursorIntern(bview, sel_start_cursor.par(),
2644 sel_start_cursor.pos());
2645 sel_start_cursor = cursor;
2646 SetCursorIntern(bview, sel_end_cursor.par(),
2647 sel_end_cursor.pos());
2648 sel_end_cursor = cursor;
2649 SetCursorIntern(bview, last_sel_cursor.par(),
2650 last_sel_cursor.pos());
2651 last_sel_cursor = cursor;
2654 SetCursorIntern(bview, cursor.par(), cursor.pos());
2658 // returns false if inset wasn't found
2659 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2661 // first check the current paragraph
2662 int pos = cursor.par()->GetPositionOfInset(inset);
2664 CheckParagraph(bview, cursor.par(), pos);
2668 // check every paragraph
2670 LyXParagraph * par = FirstParagraph();
2672 // make sure the paragraph is open
2673 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2674 pos = par->GetPositionOfInset(inset);
2676 CheckParagraph(bview, par, pos);
2687 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2688 LyXParagraph::size_type pos,
2689 bool setfont, bool boundary) const
2691 LyXCursor old_cursor = cursor;
2692 SetCursorIntern(bview, par, pos, setfont, boundary);
2693 DeleteEmptyParagraphMechanism(bview, old_cursor);
2697 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2698 LyXParagraph::size_type pos, bool boundary) const
2700 // correct the cursor position if impossible
2701 if (pos > par->Last()){
2702 LyXParagraph * tmppar = par->ParFromPos(pos);
2703 pos = par->PositionInParFromPos(pos);
2706 if (par->IsDummy() && par->previous &&
2707 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2708 while (par->previous &&
2709 ((par->previous->IsDummy() &&
2710 (par->previous->previous->footnoteflag ==
2711 LyXParagraph::CLOSED_FOOTNOTE)) ||
2712 (par->previous->footnoteflag ==
2713 LyXParagraph::CLOSED_FOOTNOTE))) {
2714 par = par->previous ;
2715 if (par->IsDummy() &&
2716 (par->previous->footnoteflag ==
2717 LyXParagraph::CLOSED_FOOTNOTE))
2718 pos += par->size() + 1;
2720 if (par->previous) {
2721 par = par->previous;
2723 pos += par->size() + 1;
2728 cur.boundary(boundary);
2730 /* get the cursor y position in text */
2732 Row * row = GetRow(par, pos, y);
2733 /* y is now the beginning of the cursor row */
2734 y += row->baseline();
2735 /* y is now the cursor baseline */
2738 /* now get the cursors x position */
2740 float fill_separator, fill_hfill, fill_label_hfill;
2741 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2743 LyXParagraph::size_type cursor_vpos = 0;
2744 LyXParagraph::size_type last = RowLastPrintable(row);
2746 if (pos > last + 1) // This shouldn't happen.
2748 else if (pos < row->pos())
2751 if (last < row->pos())
2752 cursor_vpos = row->pos();
2753 else if (pos > last && !boundary)
2754 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2755 ? row->pos() : last + 1;
2756 else if (pos > row->pos() &&
2757 (pos > last || boundary ||
2758 (row->par()->table && row->par()->IsNewline(pos))))
2759 /// Place cursor after char at (logical) position pos - 1
2760 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2761 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2763 /// Place cursor before char at (logical) position pos
2764 cursor_vpos = (bidi_level(pos) % 2 == 0)
2765 ? log2vis(pos) : log2vis(pos) + 1;
2768 /* table stuff -- begin*/
2769 if (row->par()->table) {
2770 int cell = NumberOfCell(row->par(), row->pos());
2772 x += row->par()->table->GetBeginningOfTextInCell(cell);
2773 for (LyXParagraph::size_type vpos = row->pos();
2774 vpos < cursor_vpos; ++vpos) {
2775 pos = vis2log(vpos);
2776 if (row->par()->IsNewline(pos)) {
2777 x = x_old + row->par()->table->WidthOfColumn(cell);
2780 x += row->par()->table->GetBeginningOfTextInCell(cell);
2782 x += SingleWidth(bview, row->par(), pos);
2786 /* table stuff -- end*/
2788 LyXParagraph::size_type main_body =
2789 BeginningOfMainBody(bview->buffer(), row->par());
2790 if ((main_body > 0) &&
2791 ((main_body-1 > last) ||
2792 !row->par()->IsLineSeparator(main_body-1)))
2795 for (LyXParagraph::size_type vpos = row->pos();
2796 vpos < cursor_vpos; ++vpos) {
2797 pos = vis2log(vpos);
2798 if (main_body > 0 && pos == main_body-1) {
2799 x += fill_label_hfill +
2800 lyxfont::width(textclasslist.Style(
2801 bview->buffer()->params.textclass,
2802 row->par()->GetLayout())
2804 GetFont(bview->buffer(), row->par(), -2));
2805 if (row->par()->IsLineSeparator(main_body-1))
2806 x -= SingleWidth(bview, row->par(),main_body-1);
2808 if (HfillExpansion(bview->buffer(), row, pos)) {
2809 x += SingleWidth(bview, row->par(), pos);
2810 if (pos >= main_body)
2813 x += fill_label_hfill;
2814 } else if (row->par()->IsSeparator(pos)) {
2815 x += SingleWidth(bview, row->par(), pos);
2816 if (pos >= main_body)
2817 x += fill_separator;
2819 x += SingleWidth(bview, row->par(), pos);
2831 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2832 LyXParagraph::size_type pos,
2833 bool setfont, bool boundary) const
2835 SetCursor(bview, cursor, par, pos, boundary);
2836 // #warning Remove this when verified working (Jug 20000413)
2838 // correct the cursor position if impossible
2839 if (pos > par->Last()){
2840 LyXParagraph * tmppar = par->ParFromPos(pos);
2841 pos = par->PositionInParFromPos(pos);
2844 if (par->IsDummy() && par->previous &&
2845 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2846 while (par->previous &&
2847 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2848 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2849 par = par->previous ;
2850 if (par->IsDummy() &&
2851 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2852 pos += par->size() + 1;
2854 if (par->previous) {
2855 par = par->previous;
2857 pos += par->size() + 1;
2863 /* get the cursor y position in text */
2865 Row * row = GetRow(par, pos, y);
2866 /* y is now the beginning of the cursor row */
2867 y += row->baseline();
2868 /* y is now the cursor baseline */
2871 /* now get the cursors x position */
2873 float fill_separator, fill_hfill, fill_label_hfill;
2874 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2875 LyXParagraph::size_type cursor_vpos;
2876 LyXParagraph::size_type last = RowLastPrintable(row);
2878 if (pos > last + 1) // This shouldn't happen.
2881 if (last < row->pos())
2883 else if (pos > last ||
2884 (pos - 1 >= row->pos() &&
2885 (row->par()->IsSeparator(pos) ||
2886 (row->par()->table && row->par()->IsNewline(pos))
2888 /// Place cursor after char at (logical) position pos-1
2889 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2890 ? log2vis(pos-1) + 1 : log2vis(pos-1);
2892 /// Place cursor before char at (logical) position pos
2893 cursor_vpos = (bidi_level(pos) % 2 == 0)
2894 ? log2vis(pos) : log2vis(pos) + 1;
2897 /* table stuff -- begin*/
2898 if (row->par()->table) {
2899 int cell = NumberOfCell(row->par(), row->pos());
2901 x += row->par()->table->GetBeginningOfTextInCell(cell);
2902 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2903 pos = vis2log(vpos);
2904 if (row->par()->IsNewline(pos)) {
2905 x = x_old + row->par()->table->WidthOfColumn(cell);
2908 x += row->par()->table->GetBeginningOfTextInCell(cell);
2910 x += SingleWidth(row->par(), pos);
2914 /* table stuff -- end*/
2916 LyXParagraph::size_type main_body =
2917 BeginningOfMainBody(row->par());
2918 if (main_body > 0 &&
2919 (main_body-1 > last ||
2920 !row->par()->IsLineSeparator(main_body-1)))
2923 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2924 pos = vis2log(vpos);
2925 if (main_body > 0 && pos == main_body-1) {
2926 x += fill_label_hfill +
2927 lyxfont::width(textclasslist
2928 .Style(bview->buffer()->params.textclass,
2929 row->par()->GetLayout())
2931 GetFont(row->par(), -2));
2932 if (row->par()->IsLineSeparator(main_body-1))
2933 x -= SingleWidth(row->par(), main_body-1);
2935 if (HfillExpansion(row, pos)) {
2936 x += SingleWidth(row->par(), pos);
2937 if (pos >= main_body)
2940 x += fill_label_hfill;
2942 else if (row->par()->IsSeparator(pos)) {
2943 x += SingleWidth(row->par(), pos);
2944 if (pos >= main_body)
2945 x += fill_separator;
2947 x += SingleWidth(row->par(), pos);
2954 cursor.x_fix = cursor.x;
2958 SetCurrentFont(bview);
2961 void LyXText::SetCurrentFont(BufferView * bview) const
2963 LyXParagraph::size_type pos = cursor.pos();
2964 if (cursor.boundary() && pos > 0)
2968 if (pos == cursor.par()->Last() ||
2969 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2971 else if (cursor.par()->IsSeparator(pos)) {
2972 if (pos > cursor.row()->pos() &&
2973 bidi_level(pos) % 2 ==
2974 bidi_level(pos - 1) % 2)
2976 else if (pos + 1 < cursor.par()->Last())
2981 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2982 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2986 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2988 LyXCursor old_cursor = cursor;
2990 /* get the row first */
2992 Row * row = GetRowNearY(y);
2993 cursor.par(row->par());
2996 int column = GetColumnNearX(bview, row, x, bound);
2997 cursor.pos(row->pos() + column);
2999 cursor.y(y + row->baseline());
3001 cursor.boundary(bound);
3002 SetCurrentFont(bview);
3003 DeleteEmptyParagraphMechanism(bview, old_cursor);
3007 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3008 int x, long y) const
3010 /* get the row first */
3012 Row * row = GetRowNearY(y);
3014 int column = GetColumnNearX(bview, row, x, bound);
3016 cur.par(row->par());
3017 cur.pos(row->pos() + column);
3019 cur.y(y + row->baseline());
3021 cur.boundary(bound);
3025 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3027 CursorLeftIntern(bview, internal);
3029 if (cursor.par()->table) {
3030 int cell = NumberOfCell(cursor.par(), cursor.pos());
3031 if (cursor.par()->table->IsContRow(cell)
3032 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3040 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3042 if (cursor.pos() > 0) {
3043 bool boundary = cursor.boundary();
3044 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3045 if (!internal && !boundary &&
3046 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3047 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3048 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3049 LyXParagraph * par = cursor.par()->Previous();
3050 LyXParagraph::size_type pos = par->Last();
3051 SetCursor(bview, par, pos);
3052 if (IsBoundary(bview->buffer(), par, pos))
3053 SetCursor(bview, par, pos, false, true);
3058 void LyXText::CursorRight(BufferView * bview, bool internal) const
3060 CursorRightIntern(bview, internal);
3062 if (cursor.par()->table) {
3063 int cell = NumberOfCell(cursor.par(), cursor.pos());
3064 if (cursor.par()->table->IsContRow(cell) &&
3065 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3073 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3075 if (cursor.pos() < cursor.par()->Last()) {
3076 if (!internal && cursor.boundary() &&
3077 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3078 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3080 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3081 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3082 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3084 } else if (cursor.par()->Next())
3085 SetCursor(bview, cursor.par()->Next(), 0);
3089 void LyXText::CursorUp(BufferView * bview) const
3091 SetCursorFromCoordinates(bview, cursor.x_fix(),
3092 cursor.y() - cursor.row()->baseline() - 1);
3094 if (cursor.par()->table) {
3095 int cell = NumberOfCell(cursor.par(), cursor.pos());
3096 if (cursor.par()->table->IsContRow(cell) &&
3097 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3105 void LyXText::CursorDown(BufferView * bview) const
3108 if (cursor.par()->table &&
3109 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3110 !cursor.par()->next)
3114 SetCursorFromCoordinates(bview, cursor.x_fix(),
3115 cursor.y() - cursor.row()->baseline()
3116 + cursor.row()->height() + 1);
3118 if (cursor.par()->table) {
3119 int cell = NumberOfCell(cursor.par(), cursor.pos());
3120 int cell_above = cursor.par()->table->GetCellAbove(cell);
3121 while(cursor.par()->table &&
3122 cursor.par()->table->IsContRow(cell) &&
3123 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3124 SetCursorFromCoordinates(bview, cursor.x_fix(),
3125 cursor.y() - cursor.row()->baseline()
3126 + cursor.row()->height() + 1);
3127 if (cursor.par()->table) {
3128 cell = NumberOfCell(cursor.par(), cursor.pos());
3129 cell_above = cursor.par()->table->GetCellAbove(cell);
3137 void LyXText::CursorUpParagraph(BufferView * bview) const
3139 if (cursor.pos() > 0) {
3140 SetCursor(bview, cursor.par(), 0);
3142 else if (cursor.par()->Previous()) {
3143 SetCursor(bview, cursor.par()->Previous(), 0);
3148 void LyXText::CursorDownParagraph(BufferView * bview) const
3150 if (cursor.par()->Next()) {
3151 SetCursor(bview, cursor.par()->Next(), 0);
3153 SetCursor(bview, cursor.par(), cursor.par()->Last());
3158 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3159 LyXCursor const & old_cursor) const
3161 // Would be wrong to delete anything if we have a selection.
3162 if (selection) return;
3164 // We allow all kinds of "mumbo-jumbo" when freespacing.
3165 if (textclasslist.Style(bview->buffer()->params.textclass,
3166 old_cursor.par()->GetLayout()).free_spacing)
3169 bool deleted = false;
3171 /* Ok I'll put some comments here about what is missing.
3172 I have fixed BackSpace (and thus Delete) to not delete
3173 double-spaces automagically. I have also changed Cut,
3174 Copy and Paste to hopefully do some sensible things.
3175 There are still some small problems that can lead to
3176 double spaces stored in the document file or space at
3177 the beginning of paragraphs. This happens if you have
3178 the cursor betwenn to spaces and then save. Or if you
3179 cut and paste and the selection have a space at the
3180 beginning and then save right after the paste. I am
3181 sure none of these are very hard to fix, but I will
3182 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3183 that I can get some feedback. (Lgb)
3186 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3187 // delete the LineSeparator.
3190 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3191 // delete the LineSeparator.
3194 // If the pos around the old_cursor were spaces, delete one of them.
3195 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3196 // Only if the cursor has really moved
3198 if (old_cursor.pos() > 0
3199 && old_cursor.pos() < old_cursor.par()->Last()
3200 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3201 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3202 old_cursor.par()->Erase(old_cursor.pos() - 1);
3203 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3205 if (old_cursor.par() == cursor.par() &&
3206 cursor.pos() > old_cursor.pos()) {
3207 SetCursorIntern(bview, cursor.par(),
3210 SetCursorIntern(bview, cursor.par(),
3216 // Do not delete empty paragraphs with keepempty set.
3217 if ((textclasslist.Style(bview->buffer()->params.textclass,
3218 old_cursor.par()->GetLayout())).keepempty)
3221 LyXCursor tmpcursor;
3223 if (old_cursor.par() != cursor.par()) {
3224 if ( (old_cursor.par()->Last() == 0
3225 || (old_cursor.par()->Last() == 1
3226 && old_cursor.par()->IsLineSeparator(0)))
3227 && old_cursor.par()->FirstPhysicalPar()
3228 == old_cursor.par()->LastPhysicalPar()) {
3229 // ok, we will delete anything
3231 // make sure that you do not delete any environments
3232 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3233 !(old_cursor.row()->previous()
3234 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3235 && !(old_cursor.row()->next()
3236 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3237 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3238 && ((old_cursor.row()->previous()
3239 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3240 || (old_cursor.row()->next()
3241 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3243 status = LyXText::NEED_MORE_REFRESH;
3246 if (old_cursor.row()->previous()) {
3247 refresh_row = old_cursor.row()->previous();
3248 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3250 cursor = old_cursor; // that undo can restore the right cursor position
3251 LyXParagraph * endpar = old_cursor.par()->next;
3252 if (endpar && endpar->GetDepth()) {
3253 while (endpar && endpar->GetDepth()) {
3254 endpar = endpar->LastPhysicalPar()->Next();
3257 SetUndo(bview->buffer(), Undo::DELETE,
3258 old_cursor.par()->previous,
3263 RemoveRow(old_cursor.row());
3264 if (OwnerParagraph() == old_cursor.par()) {
3265 OwnerParagraph(OwnerParagraph()->next);
3268 delete old_cursor.par();
3270 /* Breakagain the next par. Needed
3271 * because of the parindent that
3272 * can occur or dissappear. The
3273 * next row can change its height,
3274 * if there is another layout before */
3275 if (refresh_row->next()) {
3276 BreakAgain(bview, refresh_row->next());
3277 UpdateCounters(bview, refresh_row);
3279 SetHeightOfRow(bview, refresh_row);
3281 refresh_row = old_cursor.row()->next();
3282 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3285 cursor = old_cursor; // that undo can restore the right cursor position
3286 LyXParagraph * endpar = old_cursor.par()->next;
3287 if (endpar && endpar->GetDepth()) {
3288 while (endpar && endpar->GetDepth()) {
3289 endpar = endpar->LastPhysicalPar()->Next();
3292 SetUndo(bview->buffer(), Undo::DELETE,
3293 old_cursor.par()->previous,
3298 RemoveRow(old_cursor.row());
3300 if (OwnerParagraph() == old_cursor.par()) {
3301 OwnerParagraph(OwnerParagraph()->next);
3303 delete old_cursor.par();
3305 /* Breakagain the next par. Needed
3306 because of the parindent that can
3307 occur or dissappear.
3308 The next row can change its height,
3309 if there is another layout before
3312 BreakAgain(bview, refresh_row);
3313 UpdateCounters(bview, refresh_row->previous());
3319 SetCursorIntern(bview, cursor.par(), cursor.pos());
3321 if (sel_cursor.par() == old_cursor.par()
3322 && sel_cursor.pos() == sel_cursor.pos()) {
3323 // correct selection
3324 sel_cursor = cursor;
3329 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3330 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3332 SetCursorIntern(bview, cursor.par(), cursor.pos());
3333 sel_cursor = cursor;
3340 LyXParagraph * LyXText::GetParFromID(int id)
3342 LyXParagraph * result = FirstParagraph();
3343 while (result && result->id() != id)
3344 result = result->next;
3350 bool LyXText::TextUndo(BufferView * bview)
3354 // returns false if no undo possible
3355 Undo * undo = bview->buffer()->undostack.pop();
3359 bview->buffer()->redostack
3360 .push(CreateUndo(bview->buffer(), undo->kind,
3361 GetParFromID(undo->number_of_before_par),
3362 GetParFromID(undo->number_of_behind_par)));
3364 return TextHandleUndo(bview, undo);
3368 bool LyXText::TextRedo(BufferView * bview)
3372 // returns false if no redo possible
3373 Undo * undo = bview->buffer()->redostack.pop();
3377 bview->buffer()->undostack
3378 .push(CreateUndo(bview->buffer(), undo->kind,
3379 GetParFromID(undo->number_of_before_par),
3380 GetParFromID(undo->number_of_behind_par)));
3382 return TextHandleUndo(bview, undo);
3386 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3390 // returns false if no undo possible
3391 bool result = false;
3393 LyXParagraph * before =
3394 GetParFromID(undo->number_of_before_par);
3395 LyXParagraph * behind =
3396 GetParFromID(undo->number_of_behind_par);
3397 LyXParagraph * tmppar;
3398 LyXParagraph * tmppar2;
3399 LyXParagraph * endpar;
3400 LyXParagraph * tmppar5;
3402 // if there's no before take the beginning
3403 // of the document for redoing
3405 SetCursorIntern(bview, FirstParagraph(), 0);
3407 // replace the paragraphs with the undo informations
3409 LyXParagraph * tmppar3 = undo->par;
3410 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3411 LyXParagraph * tmppar4 = tmppar3;
3413 while (tmppar4->next)
3414 tmppar4 = tmppar4->next;
3415 } // get last undo par
3417 // now remove the old text if there is any
3418 if (before != behind || (!behind && !before)){
3420 tmppar5 = before->next;
3422 tmppar5 = OwnerParagraph();
3424 while (tmppar5 && tmppar5 != behind){
3426 tmppar5 = tmppar5->next;
3427 // a memory optimization for edit: Only layout information
3428 // is stored in the undo. So restore the text informations.
3429 if (undo->kind == Undo::EDIT) {
3430 tmppar2->setContentsFromPar(tmppar);
3431 tmppar->clearContents();
3432 tmppar2 = tmppar2->next;
3437 // put the new stuff in the list if there is one
3440 before->next = tmppar3;
3442 OwnerParagraph(tmppar3);
3443 tmppar3->previous = before;
3447 OwnerParagraph(behind);
3450 tmppar4->next = behind;
3452 behind->previous = tmppar4;
3456 // Set the cursor for redoing
3458 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3459 // check wether before points to a closed float and open it if necessary
3460 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3461 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3463 while (tmppar4->previous &&
3464 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3465 tmppar4 = tmppar4->previous;
3466 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3467 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3468 tmppar4 = tmppar4->next;
3473 // open a cosed footnote at the end if necessary
3474 if (behind && behind->previous &&
3475 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3476 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3477 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3478 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3479 behind = behind->next;
3483 // calculate the endpar for redoing the paragraphs.
3485 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3486 endpar = behind->LastPhysicalPar()->Next();
3488 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3492 tmppar = GetParFromID(undo->number_of_cursor_par);
3493 RedoParagraphs(bview, cursor, endpar);
3495 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3496 UpdateCounters(bview, cursor.row());
3506 void LyXText::FinishUndo()
3510 // makes sure the next operation will be stored
3511 undo_finished = true;
3515 void LyXText::FreezeUndo()
3519 // this is dangerous and for internal use only
3524 void LyXText::UnFreezeUndo()
3528 // this is dangerous and for internal use only
3529 undo_frozen = false;
3533 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3534 LyXParagraph const * before,
3535 LyXParagraph const * behind) const
3540 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3541 buf->redostack.clear();
3545 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3546 LyXParagraph const * before, LyXParagraph const * behind)
3550 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3554 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3555 LyXParagraph const * before,
3556 LyXParagraph const * behind) const
3561 int before_number = -1;
3562 int behind_number = -1;
3564 before_number = before->id();
3566 behind_number = behind->id();
3567 // Undo::EDIT and Undo::FINISH are
3568 // always finished. (no overlapping there)
3569 // overlapping only with insert and delete inside one paragraph:
3570 // Nobody wants all removed character
3571 // appear one by one when undoing.
3572 // EDIT is special since only layout information, not the
3573 // contents of a paragaph are stored.
3574 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3575 // check wether storing is needed
3576 if (!buf->undostack.empty() &&
3577 buf->undostack.top()->kind == kind &&
3578 buf->undostack.top()->number_of_before_par == before_number &&
3579 buf->undostack.top()->number_of_behind_par == behind_number ){
3584 // create a new Undo
3585 LyXParagraph * undopar;
3586 LyXParagraph * tmppar;
3587 LyXParagraph * tmppar2;
3589 LyXParagraph * start = 0;
3590 LyXParagraph * end = 0;
3593 start = before->next;
3595 start = FirstParagraph();
3597 end = behind->previous;
3599 end = FirstParagraph();
3605 && start != end->next
3606 && (before != behind || (!before && !behind))) {
3608 tmppar2 = tmppar->Clone();
3609 tmppar2->id(tmppar->id());
3611 // a memory optimization: Just store the layout information
3613 if (kind == Undo::EDIT){
3614 //tmppar2->text.clear();
3615 tmppar2->clearContents();
3620 while (tmppar != end && tmppar->next) {
3621 tmppar = tmppar->next;
3622 tmppar2->next = tmppar->Clone();
3623 tmppar2->next->id(tmppar->id());
3624 // a memory optimization: Just store the layout
3625 // information when only edit
3626 if (kind == Undo::EDIT){
3627 //tmppar2->next->text.clear();
3628 tmppar2->clearContents();
3630 tmppar2->next->previous = tmppar2;
3631 tmppar2 = tmppar2->next;
3635 undopar = 0; // nothing to replace (undo of delete maybe)
3637 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3638 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3640 Undo * undo = new Undo(kind,
3641 before_number, behind_number,
3642 cursor_par, cursor_pos,
3645 undo_finished = false;
3650 void LyXText::SetCursorParUndo(Buffer * buf)
3654 SetUndo(buf, Undo::FINISH,
3655 cursor.par()->ParFromPos(cursor.pos())->previous,
3656 cursor.par()->ParFromPos(cursor.pos())->next);
3661 void LyXText::RemoveTableRow(LyXCursor & cur) const
3667 // move to the previous row
3668 int cell_act = NumberOfCell(cur.par(), cur.pos());
3671 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3672 cur.pos(cur.pos() - 1);
3674 !cur.par()->table->IsFirstCell(cell_act)) {
3675 cur.pos(cur.pos() - 1);
3676 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3677 cur.pos(cur.pos() - 1);
3681 // now we have to pay attention if the actual table is the
3682 // main row of TableContRows and if yes to delete all of them
3687 // delete up to the next row
3688 while (cur.pos() < cur.par()->Last() &&
3690 || !cur.par()->table->IsFirstCell(cell_act))) {
3691 while (cur.pos() < cur.par()->Last() &&
3692 !cur.par()->IsNewline(cur.pos()))
3693 cur.par()->Erase(cur.pos());
3696 if (cur.pos() < cur.par()->Last())
3697 cur.par()->Erase(cur.pos());
3699 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3700 cur.pos(cur.pos() - 1);
3701 cur.par()->Erase(cur.pos()); // no newline at very end!
3703 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3704 !cur.par()->table->IsContRow(cell_org) &&
3705 cur.par()->table->IsContRow(cell));
3706 cur.par()->table->DeleteRow(cell_org);
3713 bool LyXText::IsEmptyTableCell() const
3715 LyXParagraph::size_type pos = cursor.pos() - 1;
3716 while (pos >= 0 && pos < cursor.par()->Last()
3717 && !cursor.par()->IsNewline(pos))
3719 return cursor.par()->IsNewline(pos + 1);
3724 void LyXText::toggleAppendix(BufferView * bview)
3726 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3727 bool start = !par->start_of_appendix;
3729 // ensure that we have only one start_of_appendix in this document
3730 LyXParagraph * tmp = FirstParagraph();
3731 for (; tmp; tmp = tmp->next)
3732 tmp->start_of_appendix = 0;
3733 par->start_of_appendix = start;
3735 // we can set the refreshing parameters now
3736 status = LyXText::NEED_MORE_REFRESH;
3738 refresh_row = 0; // not needed for full update
3739 UpdateCounters(bview, 0);
3740 SetCursor(bview, cursor.par(), cursor.pos());
3743 LyXParagraph * LyXText::OwnerParagraph() const
3746 return inset_owner->par;
3748 return bv_owner->buffer()->paragraph;
3752 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3755 inset_owner->par = p;
3757 bv_owner->buffer()->paragraph = p;