1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
28 #include "support/textutils.h"
30 #include "minibuffer.h"
32 #include "bufferparams.h"
33 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
39 #include "CutAndPaste.h"
44 //#define USE_OLD_CUT_AND_PASTE 1
50 LyXText::LyXText(BufferView * bv)
58 LyXText::LyXText(InsetText * inset)
75 status = LyXText::UNCHANGED;
76 // set cursor at the very top position
77 selection = true; /* these setting is necessary
78 because of the delete-empty-
79 paragraph mechanism in
82 LyXParagraph * par = OwnerParagraph();
83 current_font = GetFont(bv_owner->buffer(), par, 0);
85 InsertParagraph(bv_owner, par, lastrow);
88 SetCursor(bv_owner, firstrow->par(), 0);
90 current_font = LyXFont(LyXFont::ALL_SANE);
96 // no rebreak necessary
102 // Default layouttype for copy environment type
106 // Dump all rowinformation:
107 Row * tmprow = firstrow;
108 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
110 lyxerr << tmprow->baseline() << '\t'
111 << tmprow->par << '\t'
112 << tmprow->pos() << '\t'
113 << tmprow->height << '\t'
114 << tmprow->ascent_of_text << '\t'
115 << tmprow->fill << '\n';
116 tmprow = tmprow->next();
123 void LyXText::init(BufferView * bview)
128 LyXParagraph * par = OwnerParagraph();
129 current_font = GetFont(bview->buffer(), par, 0);
131 InsertParagraph(bview, par, lastrow);
134 SetCursorIntern(bview, firstrow->par(), 0);
136 // Dump all rowinformation:
137 Row * tmprow = firstrow;
138 lyxerr << "Width = " << width << endl;
139 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
141 lyxerr << tmprow->baseline() << '\t'
142 << tmprow->par() << '\t'
143 << tmprow->pos() << '\t'
144 << tmprow->height() << '\t'
145 << tmprow->ascent_of_text() << '\t'
146 << tmprow->fill() << '\n';
147 tmprow = tmprow->next();
155 // Delete all rows, this does not touch the paragraphs!
156 Row * tmprow = firstrow;
158 tmprow = firstrow->next();
166 void LyXText::owner(BufferView * bv)
168 if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
173 // Gets the fully instantiated font at a given position in a paragraph
174 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
175 // The difference is that this one is used for displaying, and thus we
176 // are allowed to make cosmetic improvements. For instance make footnotes
178 // If position is -1, we get the layout font of the paragraph.
179 // If position is -2, we get the font of the manual label of the paragraph.
180 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
181 LyXParagraph::size_type pos) const
183 LyXLayout const & layout =
184 textclasslist.Style(buf->params.textclass, par->GetLayout());
186 char par_depth = par->GetDepth();
187 // We specialize the 95% common case:
188 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
191 if (layout.labeltype == LABEL_MANUAL
192 && pos < BeginningOfMainBody(buf, par)) {
194 return par->GetFontSettings(buf->params, pos).
195 realize(layout.reslabelfont);
197 return par->GetFontSettings(buf->params, pos).
198 realize(layout.resfont);
201 // process layoutfont for pos == -1 and labelfont for pos < -1
203 return layout.resfont;
205 return layout.reslabelfont;
209 // The uncommon case need not be optimized as much
211 LyXFont layoutfont, tmpfont;
215 if (pos < BeginningOfMainBody(buf, par)) {
217 layoutfont = layout.labelfont;
220 layoutfont = layout.font;
222 tmpfont = par->GetFontSettings(buf->params, pos);
223 tmpfont.realize(layoutfont);
226 // process layoutfont for pos == -1 and labelfont for pos < -1
228 tmpfont = layout.font;
230 tmpfont = layout.labelfont;
233 // Resolve against environment font information
234 while (par && par_depth && !tmpfont.resolved()) {
235 par = par->DepthHook(par_depth - 1);
237 tmpfont.realize(textclasslist.
238 Style(buf->params.textclass,
239 par->GetLayout()).font);
240 par_depth = par->GetDepth();
244 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
246 // Cosmetic improvement: If this is an open footnote, make the font
248 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
249 && par->footnotekind == LyXParagraph::FOOTNOTE) {
257 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
258 LyXParagraph::size_type pos,
262 // Let the insets convert their font
263 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
264 if (par->GetInset(pos))
265 font = par->GetInset(pos)->ConvertFont(font);
268 LyXLayout const & layout =
269 textclasslist.Style(buf->params.textclass,
272 // Get concrete layout font to reduce against
275 if (pos < BeginningOfMainBody(buf, par))
276 layoutfont = layout.labelfont;
278 layoutfont = layout.font;
280 // Realize against environment font information
281 if (par->GetDepth()){
282 LyXParagraph * tp = par;
283 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
284 tp = tp->DepthHook(tp->GetDepth()-1);
286 layoutfont.realize(textclasslist.
287 Style(buf->params.textclass,
288 tp->GetLayout()).font);
292 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
294 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
295 && par->footnotekind == LyXParagraph::FOOTNOTE) {
296 layoutfont.decSize();
299 // Now, reduce font against full layout font
300 font.reduce(layoutfont);
302 par->SetFont(pos, font);
306 /* inserts a new row behind the specified row, increments
307 * the touched counters */
308 void LyXText::InsertRow(Row * row, LyXParagraph * par,
309 LyXParagraph::size_type pos) const
311 Row * tmprow = new Row;
314 tmprow->next(firstrow);
317 tmprow->previous(row);
318 tmprow->next(row->next());
323 tmprow->next()->previous(tmprow);
325 if (tmprow->previous())
326 tmprow->previous()->next(tmprow);
334 ++number_of_rows; // one more row
338 // removes the row and reset the touched counters
339 void LyXText::RemoveRow(Row * row) const
341 /* this must not happen before the currentrow for clear reasons.
342 so the trick is just to set the current row onto the previous
345 GetRow(row->par(), row->pos(), unused_y);
348 row->next()->previous(row->previous());
349 if (!row->previous()) {
350 firstrow = row->next();
352 row->previous()->next(row->next());
355 lastrow = row->previous();
357 height -= row->height(); // the text becomes smaller
360 --number_of_rows; // one row less
364 // remove all following rows of the paragraph of the specified row.
365 void LyXText::RemoveParagraph(Row * row) const
367 LyXParagraph * tmppar = row->par();
371 while (row && row->par() == tmppar) {
372 tmprow = row->next();
379 // insert the specified paragraph behind the specified row
380 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
383 InsertRow(row, par, 0); /* insert a new row, starting
386 SetCounter(bview->buffer(), par); // set the counters
388 // and now append the whole paragraph behind the new row
391 AppendParagraph(bview, firstrow);
393 row->next()->height(0);
394 AppendParagraph(bview, row->next());
399 void LyXText::ToggleFootnote(BufferView * bview)
401 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
403 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
405 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
407 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
408 CloseFootnote(bview);
413 void LyXText::OpenStuff(BufferView * bview)
415 if (cursor.pos() == 0 && cursor.par()->bibkey){
416 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
418 else if (cursor.pos() < cursor.par()->Last()
419 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
420 && cursor.par()->GetInset(cursor.pos())->Editable()) {
421 bview->owner()->getMiniBuffer()
422 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
423 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
424 SetCursorParUndo(bview->buffer());
425 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
427 ToggleFootnote(bview);
432 void LyXText::CloseFootnote(BufferView * bview)
434 LyXParagraph * tmppar;
435 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
437 // if the cursor is not in an open footnote, or
438 // there is no open footnote in this paragraph, just return.
439 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
442 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
443 bview->owner()->getMiniBuffer()
444 ->Set(_("Nothing to do"));
448 // ok, move the cursor right before the footnote
449 // just a little faster than using CursorRight()
451 cursor.par()->ParFromPos(cursor.pos()) != par;) {
452 cursor.pos(cursor.pos() + 1);
455 // now the cursor is at the beginning of the physical par
456 SetCursor(bview, cursor.par(),
458 cursor.par()->ParFromPos(cursor.pos())->size());
460 /* we are in a footnote, so let us move at the beginning */
461 /* this is just faster than using just CursorLeft() */
463 tmppar = cursor.par();
464 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
465 // just a little bit faster than movin the cursor
466 tmppar = tmppar->Previous();
468 SetCursor(bview, tmppar, tmppar->Last());
471 // the cursor must be exactly before the footnote
472 par = cursor.par()->ParFromPos(cursor.pos());
474 status = LyXText::NEED_MORE_REFRESH;
475 refresh_row = cursor.row();
476 refresh_y = cursor.y() - cursor.row()->baseline();
478 tmppar = cursor.par();
479 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
480 Row * row = cursor.row();
482 tmppar->CloseFootnote(cursor.pos());
484 while (tmppar != endpar) {
485 RemoveRow(row->next());
487 tmppar = row->next()->par();
492 AppendParagraph(bview, cursor.row());
494 SetCursor(bview, cursor.par(), cursor.pos());
498 if (cursor.row()->next())
499 SetHeightOfRow(bview, cursor.row()->next());
503 /* used in setlayout */
504 // Asger is not sure we want to do this...
505 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
508 LyXLayout const & layout =
509 textclasslist.Style(buf->params.textclass, par->GetLayout());
511 LyXFont layoutfont, tmpfont;
512 for (LyXParagraph::size_type pos = 0;
513 pos < par->Last(); ++pos) {
514 if (pos < BeginningOfMainBody(buf, par))
515 layoutfont = layout.labelfont;
517 layoutfont = layout.font;
519 tmpfont = par->GetFontSettings(buf->params, pos);
520 tmpfont.reduce(layoutfont);
521 par->SetFont(pos, tmpfont);
525 LyXParagraph * LyXText::SetLayout(BufferView * bview,
526 LyXCursor & cur, LyXCursor & sstart_cur,
527 LyXCursor & send_cur,
528 LyXTextClass::size_type layout)
530 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
531 LyXParagraph * undoendpar = endpar;
533 if (endpar && endpar->GetDepth()) {
534 while (endpar && endpar->GetDepth()) {
535 endpar = endpar->LastPhysicalPar()->Next();
539 endpar = endpar->Next(); // because of parindents etc.
542 SetUndo(bview->buffer(), Undo::EDIT,
543 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
546 /* ok we have a selection. This is always between sstart_cur
547 * and sel_end cursor */
550 LyXLayout const & lyxlayout =
551 textclasslist.Style(bview->buffer()->params.textclass, layout);
553 while (cur.par() != send_cur.par()) {
554 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
555 cur.par()->SetLayout(bview->buffer()->params, layout);
556 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
557 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
558 fppar->added_space_top = lyxlayout.fill_top ?
559 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
560 fppar->added_space_bottom = lyxlayout.fill_bottom ?
561 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
562 if (lyxlayout.margintype == MARGIN_MANUAL)
563 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
564 if (lyxlayout.labeltype != LABEL_BIBLIO
566 delete fppar->bibkey;
570 cur.par(cur.par()->Next());
572 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
573 cur.par()->SetLayout(bview->buffer()->params, layout);
574 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
575 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
576 fppar->added_space_top = lyxlayout.fill_top ?
577 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
578 fppar->added_space_bottom = lyxlayout.fill_bottom ?
579 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
580 if (lyxlayout.margintype == MARGIN_MANUAL)
581 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
582 if (lyxlayout.labeltype != LABEL_BIBLIO
584 delete fppar->bibkey;
591 // set layout over selection and make a total rebreak of those paragraphs
592 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
595 tmpcursor = cursor; /* store the current cursor */
597 #ifdef USE_OLD_SET_LAYOUT
598 // if there is no selection just set the layout
599 // of the current paragraph */
601 sel_start_cursor = cursor; // dummy selection
602 sel_end_cursor = cursor;
605 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
606 LyXParagraph * undoendpar = endpar;
608 if (endpar && endpar->GetDepth()) {
609 while (endpar && endpar->GetDepth()) {
610 endpar = endpar->LastPhysicalPar()->Next();
615 endpar = endpar->Next(); // because of parindents etc.
619 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
622 /* ok we have a selection. This is always between sel_start_cursor
623 * and sel_end cursor */
624 cursor = sel_start_cursor;
626 LyXLayout const & lyxlayout =
627 textclasslist.Style(bview->buffer()->params.textclass, layout);
629 while (cursor.par() != sel_end_cursor.par()) {
630 if (cursor.par()->footnoteflag ==
631 sel_start_cursor.par()->footnoteflag) {
632 cursor.par()->SetLayout(layout);
633 MakeFontEntriesLayoutSpecific(cursor.par());
634 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
635 fppar->added_space_top = lyxlayout.fill_top ?
636 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
637 fppar->added_space_bottom = lyxlayout.fill_bottom ?
638 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
639 if (lyxlayout.margintype == MARGIN_MANUAL)
640 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
641 if (lyxlayout.labeltype != LABEL_BIBLIO
643 delete fppar->bibkey;
647 cursor.par() = cursor.par()->Next();
649 if (cursor.par()->footnoteflag ==
650 sel_start_cursor.par()->footnoteflag) {
651 cursor.par()->SetLayout(layout);
652 MakeFontEntriesLayoutSpecific(cursor.par());
653 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
654 fppar->added_space_top = lyxlayout.fill_top ?
655 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
656 fppar->added_space_bottom = lyxlayout.fill_bottom ?
657 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
658 if (lyxlayout.margintype == MARGIN_MANUAL)
659 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
660 if (lyxlayout.labeltype != LABEL_BIBLIO
662 delete fppar->bibkey;
667 // if there is no selection just set the layout
668 // of the current paragraph */
670 sel_start_cursor = cursor; // dummy selection
671 sel_end_cursor = cursor;
674 endpar = SetLayout(bview, cursor, sel_start_cursor,
675 sel_end_cursor, layout);
677 RedoParagraphs(bview, sel_start_cursor, endpar);
679 // we have to reset the selection, because the
680 // geometry could have changed */
681 SetCursor(bview, sel_start_cursor.par(),
682 sel_start_cursor.pos(), false);
684 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
686 UpdateCounters(bview, cursor.row());
689 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
693 // increment depth over selection and
694 // make a total rebreak of those paragraphs
695 void LyXText::IncDepth(BufferView * bview)
697 // If there is no selection, just use the current paragraph
699 sel_start_cursor = cursor; // dummy selection
700 sel_end_cursor = cursor;
703 // We end at the next paragraph with depth 0
704 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
705 LyXParagraph * undoendpar = endpar;
707 if (endpar && endpar->GetDepth()) {
708 while (endpar && endpar->GetDepth()) {
709 endpar = endpar->LastPhysicalPar()->Next();
714 endpar = endpar->Next(); // because of parindents etc.
717 SetUndo(bview->buffer(), Undo::EDIT,
719 .par()->ParFromPos(sel_start_cursor.pos())->previous,
722 LyXCursor tmpcursor = cursor; // store the current cursor
724 // ok we have a selection. This is always between sel_start_cursor
725 // and sel_end cursor
726 cursor = sel_start_cursor;
728 bool anything_changed = false;
731 // NOTE: you can't change the depth of a bibliography entry
732 if (cursor.par()->footnoteflag ==
733 sel_start_cursor.par()->footnoteflag
734 && textclasslist.Style(bview->buffer()->params.textclass,
735 cursor.par()->GetLayout()
736 ).labeltype != LABEL_BIBLIO) {
737 LyXParagraph * prev =
738 cursor.par()->FirstPhysicalPar()->Previous();
740 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
741 || (prev->GetDepth() == cursor.par()->GetDepth()
742 && textclasslist.Style(bview->buffer()->params.textclass,
743 prev->GetLayout()).isEnvironment()))) {
744 cursor.par()->FirstPhysicalPar()->depth++;
745 anything_changed = true;
748 if (cursor.par() == sel_end_cursor.par())
750 cursor.par(cursor.par()->Next());
753 // if nothing changed set all depth to 0
754 if (!anything_changed) {
755 cursor = sel_start_cursor;
756 while (cursor.par() != sel_end_cursor.par()) {
757 cursor.par()->FirstPhysicalPar()->depth = 0;
758 cursor.par(cursor.par()->Next());
760 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
761 cursor.par()->FirstPhysicalPar()->depth = 0;
764 RedoParagraphs(bview, sel_start_cursor, endpar);
766 // we have to reset the selection, because the
767 // geometry could have changed
768 SetCursor(bview, sel_start_cursor.par(),
769 sel_start_cursor.pos());
771 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
772 UpdateCounters(bview, cursor.row());
775 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
779 // decrement depth over selection and
780 // make a total rebreak of those paragraphs
781 void LyXText::DecDepth(BufferView * bview)
783 // if there is no selection just set the layout
784 // of the current paragraph
786 sel_start_cursor = cursor; // dummy selection
787 sel_end_cursor = cursor;
790 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
791 LyXParagraph * undoendpar = endpar;
793 if (endpar && endpar->GetDepth()) {
794 while (endpar && endpar->GetDepth()) {
795 endpar = endpar->LastPhysicalPar()->Next();
800 endpar = endpar->Next(); // because of parindents etc.
803 SetUndo(bview->buffer(), Undo::EDIT,
805 .par()->ParFromPos(sel_start_cursor.pos())->previous,
808 LyXCursor tmpcursor = cursor; // store the current cursor
810 // ok we have a selection. This is always between sel_start_cursor
811 // and sel_end cursor
812 cursor = sel_start_cursor;
815 if (cursor.par()->footnoteflag ==
816 sel_start_cursor.par()->footnoteflag) {
817 if (cursor.par()->FirstPhysicalPar()->depth)
818 cursor.par()->FirstPhysicalPar()->depth--;
820 if (cursor.par() == sel_end_cursor.par())
822 cursor.par(cursor.par()->Next());
825 RedoParagraphs(bview, sel_start_cursor, endpar);
827 // we have to reset the selection, because the
828 // geometry could have changed
829 SetCursor(bview, sel_start_cursor.par(),
830 sel_start_cursor.pos());
832 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
833 UpdateCounters(bview, cursor.row());
836 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
840 // set font over selection and make a total rebreak of those paragraphs
841 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
843 // if there is no selection just set the current_font
845 // Determine basis font
847 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
849 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
851 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
852 // Update current font
853 real_current_font.update(font,
854 bview->buffer()->params.language_info,
857 // Reduce to implicit settings
858 current_font = real_current_font;
859 current_font.reduce(layoutfont);
860 // And resolve it completely
861 real_current_font.realize(layoutfont);
865 LyXCursor tmpcursor = cursor; // store the current cursor
867 // ok we have a selection. This is always between sel_start_cursor
868 // and sel_end cursor
870 SetUndo(bview->buffer(), Undo::EDIT,
871 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
872 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
873 cursor = sel_start_cursor;
874 while (cursor.par() != sel_end_cursor.par() ||
875 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
876 && cursor.pos() < sel_end_cursor.pos()))
878 if (cursor.pos() < cursor.par()->Last()
879 && cursor.par()->footnoteflag
880 == sel_start_cursor.par()->footnoteflag) {
881 // an open footnote should behave
883 LyXFont newfont = GetFont(bview->buffer(),
884 cursor.par(), cursor.pos());
886 bview->buffer()->params.language_info,
888 SetCharFont(bview->buffer(),
889 cursor.par(), cursor.pos(), newfont);
890 cursor.pos(cursor.pos() + 1);
893 cursor.par(cursor.par()->Next());
897 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
899 // we have to reset the selection, because the
900 // geometry could have changed
901 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
903 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
906 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
907 tmpcursor.boundary());
911 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
913 Row * tmprow = cur.row();
914 long y = cur.y() - tmprow->baseline();
916 SetHeightOfRow(bview, tmprow);
917 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
918 // find the first row of the paragraph
919 if (first_phys_par != tmprow->par())
920 while (tmprow->previous()
921 && tmprow->previous()->par() != first_phys_par) {
922 tmprow = tmprow->previous();
923 y -= tmprow->height();
924 SetHeightOfRow(bview, tmprow);
926 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
927 tmprow = tmprow->previous();
928 y -= tmprow->height();
929 SetHeightOfRow(bview, tmprow);
932 // we can set the refreshing parameters now
933 status = LyXText::NEED_MORE_REFRESH;
935 refresh_row = tmprow;
936 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
940 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
942 Row * tmprow = cur.row();
944 long y = cur.y() - tmprow->baseline();
945 SetHeightOfRow(bview, tmprow);
946 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
947 // find the first row of the paragraph
948 if (first_phys_par != tmprow->par())
949 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
950 tmprow = tmprow->previous();
951 y -= tmprow->height();
953 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
954 tmprow = tmprow->previous();
955 y -= tmprow->height();
958 // we can set the refreshing parameters now
959 if (status == LyXText::UNCHANGED || y < refresh_y) {
961 refresh_row = tmprow;
963 status = LyXText::NEED_MORE_REFRESH;
964 SetCursor(bview, cur.par(), cur.pos());
968 /* deletes and inserts again all paragaphs between the cursor
969 * and the specified par
970 * This function is needed after SetLayout and SetFont etc. */
971 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
972 LyXParagraph const * endpar) const
975 LyXParagraph * tmppar = 0, * first_phys_par = 0;
977 Row * tmprow = cur.row();
979 long y = cur.y() - tmprow->baseline();
981 if (!tmprow->previous()){
982 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
984 first_phys_par = tmprow->par()->FirstPhysicalPar();
985 // find the first row of the paragraph
986 if (first_phys_par != tmprow->par())
987 while (tmprow->previous() &&
988 (tmprow->previous()->par() != first_phys_par)) {
989 tmprow = tmprow->previous();
990 y -= tmprow->height();
992 while (tmprow->previous()
993 && tmprow->previous()->par() == first_phys_par) {
994 tmprow = tmprow->previous();
995 y -= tmprow->height();
999 // we can set the refreshing parameters now
1000 status = LyXText::NEED_MORE_REFRESH;
1002 refresh_row = tmprow->previous(); /* the real refresh row will
1003 be deleted, so I store
1004 the previous here */
1007 tmppar = tmprow->next()->par();
1010 while (tmppar != endpar) {
1011 RemoveRow(tmprow->next());
1013 tmppar = tmprow->next()->par();
1018 // remove the first one
1019 tmprow2 = tmprow; /* this is because tmprow->previous()
1021 tmprow = tmprow->previous();
1024 tmppar = first_phys_par;
1028 InsertParagraph(bview, tmppar, tmprow);
1031 while (tmprow->next() && tmprow->next()->par() == tmppar)
1032 tmprow = tmprow->next();
1033 tmppar = tmppar->Next();
1035 } while (tmppar != endpar);
1037 // this is because of layout changes
1039 refresh_y -= refresh_row->height();
1040 SetHeightOfRow(bview, refresh_row);
1042 refresh_row = firstrow;
1044 SetHeightOfRow(bview, refresh_row);
1047 if (tmprow && tmprow->next())
1048 SetHeightOfRow(bview, tmprow->next());
1052 bool LyXText::FullRebreak(BufferView * bview)
1058 if (need_break_row) {
1059 BreakAgain(bview, need_break_row);
1067 /* important for the screen */
1070 /* the cursor set functions have a special mechanism. When they
1071 * realize, that you left an empty paragraph, they will delete it.
1072 * They also delete the corresponding row */
1074 // need the selection cursor:
1075 void LyXText::SetSelection()
1078 last_sel_cursor = sel_cursor;
1079 sel_start_cursor = sel_cursor;
1080 sel_end_cursor = sel_cursor;
1085 // first the toggling area
1086 if (cursor.y() < last_sel_cursor.y()
1087 || (cursor.y() == last_sel_cursor.y()
1088 && cursor.x() < last_sel_cursor.x())) {
1089 toggle_end_cursor = last_sel_cursor;
1090 toggle_cursor = cursor;
1092 toggle_end_cursor = cursor;
1093 toggle_cursor = last_sel_cursor;
1096 last_sel_cursor = cursor;
1098 // and now the whole selection
1100 if (sel_cursor.par() == cursor.par())
1101 if (sel_cursor.pos() < cursor.pos()) {
1102 sel_end_cursor = cursor;
1103 sel_start_cursor = sel_cursor;
1105 sel_end_cursor = sel_cursor;
1106 sel_start_cursor = cursor;
1108 else if (sel_cursor.y() < cursor.y() ||
1109 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1110 sel_end_cursor = cursor;
1111 sel_start_cursor = sel_cursor;
1114 sel_end_cursor = sel_cursor;
1115 sel_start_cursor = cursor;
1118 // a selection with no contents is not a selection
1119 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1120 sel_start_cursor.pos() == sel_end_cursor.pos())
1125 string LyXText::selectionAsString(Buffer const * buffer) const
1127 if (!selection) return string();
1130 // Special handling if the whole selection is within one paragraph
1131 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1132 result += sel_start_cursor.par()->String(buffer,
1133 sel_start_cursor.pos(),
1134 sel_end_cursor.pos());
1138 // The selection spans more than one paragraph
1140 // First paragraph in selection
1141 result += sel_start_cursor.par()->String(buffer,
1142 sel_start_cursor.pos(),
1143 sel_start_cursor.par()->Last())
1146 // The paragraphs in between (if any)
1147 LyXCursor tmpcur(sel_start_cursor);
1148 tmpcur.par(tmpcur.par()->Next());
1149 while (tmpcur.par() != sel_end_cursor.par()) {
1150 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1151 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1154 // Last paragraph in selection
1155 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1161 void LyXText::ClearSelection() const
1168 void LyXText::CursorHome(BufferView * bview) const
1170 SetCursor(bview, cursor.par(), cursor.row()->pos());
1174 void LyXText::CursorEnd(BufferView * bview) const
1176 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1177 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1179 if (cursor.par()->Last() &&
1180 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1181 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1182 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1184 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1187 if (cursor.par()->table) {
1188 int cell = NumberOfCell(cursor.par(), cursor.pos());
1189 if (cursor.par()->table->RowHasContRow(cell) &&
1190 cursor.par()->table->CellHasContRow(cell)<0) {
1191 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1192 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1194 if (cursor.par()->Last() &&
1195 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1196 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1197 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1199 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1207 void LyXText::CursorTop(BufferView * bview) const
1209 while (cursor.par()->Previous())
1210 cursor.par(cursor.par()->Previous());
1211 SetCursor(bview, cursor.par(), 0);
1215 void LyXText::CursorBottom(BufferView * bview) const
1217 while (cursor.par()->Next())
1218 cursor.par(cursor.par()->Next());
1219 SetCursor(bview, cursor.par(), cursor.par()->Last());
1223 /* returns a pointer to the row near the specified y-coordinate
1224 * (relative to the whole text). y is set to the real beginning
1226 Row * LyXText::GetRowNearY(long & y) const
1228 Row * tmprow = firstrow;
1231 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1232 tmpy += tmprow->height();
1233 tmprow = tmprow->next();
1236 y = tmpy; // return the real y
1241 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1243 // If the mask is completely neutral, tell user
1244 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1245 // Could only happen with user style
1246 bview->owner()->getMiniBuffer()
1247 ->Set(_("No font change defined. Use Character under"
1248 " the Layout menu to define font change."));
1252 // Try implicit word selection
1253 // If there is a change in the language the implicit word selection
1255 LyXCursor resetCursor = cursor;
1256 bool implicitSelection = (font.language() == ignore_language)
1257 ? SelectWordWhenUnderCursor(bview) : false;
1260 SetFont(bview, font, toggleall);
1262 /* Implicit selections are cleared afterwards and cursor is set to the
1263 original position. */
1264 if (implicitSelection) {
1266 cursor = resetCursor;
1267 SetCursor(bview, cursor.par(), cursor.pos());
1268 sel_cursor = cursor;
1273 LyXParagraph::size_type
1274 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1276 if (textclasslist.Style(buf->params.textclass,
1277 par->GetLayout()).labeltype != LABEL_MANUAL)
1280 return par->BeginningOfMainBody();
1284 /* if there is a selection, reset every environment you can find
1285 * in the selection, otherwise just the environment you are in */
1286 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1288 LyXParagraph * tmppar, * firsttmppar;
1292 /* is is only allowed, if the cursor is IN an open footnote.
1293 * Otherwise it is too dangerous */
1294 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1297 SetUndo(bview->buffer(), Undo::FINISH,
1298 cursor.par()->PreviousBeforeFootnote()->previous,
1299 cursor.par()->NextAfterFootnote()->next);
1301 /* ok, move to the beginning of the footnote. */
1302 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1303 cursor.par(cursor.par()->Previous());
1305 SetCursor(bview, cursor.par(), cursor.par()->Last());
1306 /* this is just faster than using CursorLeft(); */
1308 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1309 tmppar = firsttmppar;
1310 /* tmppar is now the paragraph right before the footnote */
1312 bool first_footnote_par_is_not_empty = tmppar->next->size();
1315 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1316 tmppar = tmppar->next; /* I use next instead of Next(),
1317 * because there cannot be any
1318 * footnotes in a footnote
1320 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1322 /* remember the captions and empty paragraphs */
1323 if ((textclasslist.Style(bview->buffer()->params.textclass,
1324 tmppar->GetLayout())
1325 .labeltype == LABEL_SENSITIVE)
1327 tmppar->SetLayout(bview->buffer()->params, 0);
1330 // now we will paste the ex-footnote, if the layouts allow it
1331 // first restore the layout of the paragraph right behind
1334 tmppar->next->MakeSameLayout(cursor.par());
1337 if ((!tmppar->GetLayout() && !tmppar->table)
1339 && (!tmppar->Next()->Last()
1340 || tmppar->Next()->HasSameLayout(tmppar)))) {
1341 if (tmppar->Next()->Last()
1342 && tmppar->Next()->IsLineSeparator(0))
1343 tmppar->Next()->Erase(0);
1344 tmppar->PasteParagraph(bview->buffer()->params);
1347 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1348 * by the pasting of the beginning */
1350 /* then the beginning */
1351 /* if there is no space between the text and the footnote, so we insert
1353 * (only if the previous par and the footnotepar are not empty!) */
1354 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1355 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1356 if (firsttmppar->size()
1357 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1358 && first_footnote_par_is_not_empty) {
1359 firsttmppar->next->InsertChar(0, ' ');
1361 firsttmppar->PasteParagraph(bview->buffer()->params);
1364 /* now redo the paragaphs */
1365 RedoParagraphs(bview, cursor, tmppar);
1367 SetCursor(bview, cursor.par(), cursor.pos());
1369 /* sometimes it can happen, that there is a counter change */
1370 Row * row = cursor.row();
1371 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1373 UpdateCounters(bview, row);
1380 /* the DTP switches for paragraphs. LyX will store them in the
1381 * first physicla paragraph. When a paragraph is broken, the top settings
1382 * rest, the bottom settings are given to the new one. So I can make shure,
1383 * they do not duplicate themself and you cannnot make dirty things with
1386 void LyXText::SetParagraph(BufferView * bview,
1387 bool line_top, bool line_bottom,
1388 bool pagebreak_top, bool pagebreak_bottom,
1389 VSpace const & space_top,
1390 VSpace const & space_bottom,
1392 string labelwidthstring,
1395 LyXCursor tmpcursor = cursor;
1397 sel_start_cursor = cursor;
1398 sel_end_cursor = cursor;
1401 // make sure that the depth behind the selection are restored, too
1402 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1403 LyXParagraph * undoendpar = endpar;
1405 if (endpar && endpar->GetDepth()) {
1406 while (endpar && endpar->GetDepth()) {
1407 endpar = endpar->LastPhysicalPar()->Next();
1408 undoendpar = endpar;
1412 endpar = endpar->Next(); // because of parindents etc.
1415 SetUndo(bview->buffer(), Undo::EDIT,
1417 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1421 LyXParagraph * tmppar = sel_end_cursor.par();
1422 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1423 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1424 status = LyXText::NEED_MORE_REFRESH;
1425 refresh_row = cursor.row();
1426 refresh_y = cursor.y() - cursor.row()->baseline();
1427 if (cursor.par()->footnoteflag ==
1428 sel_start_cursor.par()->footnoteflag) {
1429 cursor.par()->line_top = line_top;
1430 cursor.par()->line_bottom = line_bottom;
1431 cursor.par()->pagebreak_top = pagebreak_top;
1432 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1433 cursor.par()->added_space_top = space_top;
1434 cursor.par()->added_space_bottom = space_bottom;
1435 // does the layout allow the new alignment?
1436 if (align == LYX_ALIGN_LAYOUT)
1437 align = textclasslist
1438 .Style(bview->buffer()->params.textclass,
1439 cursor.par()->GetLayout()).align;
1440 if (align & textclasslist
1441 .Style(bview->buffer()->params.textclass,
1442 cursor.par()->GetLayout()).alignpossible) {
1443 if (align == textclasslist
1444 .Style(bview->buffer()->params.textclass,
1445 cursor.par()->GetLayout()).align)
1446 cursor.par()->align = LYX_ALIGN_LAYOUT;
1448 cursor.par()->align = align;
1450 cursor.par()->SetLabelWidthString(labelwidthstring);
1451 cursor.par()->noindent = noindent;
1454 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1457 RedoParagraphs(bview, sel_start_cursor, endpar);
1460 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1461 sel_cursor = cursor;
1462 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1464 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1468 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1470 char const * widthp,
1471 int alignment, bool hfill,
1472 bool start_minipage)
1474 LyXCursor tmpcursor = cursor;
1475 LyXParagraph * tmppar;
1477 sel_start_cursor = cursor;
1478 sel_end_cursor = cursor;
1481 // make sure that the depth behind the selection are restored, too
1482 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1483 LyXParagraph * undoendpar = endpar;
1485 if (endpar && endpar->GetDepth()) {
1486 while (endpar && endpar->GetDepth()) {
1487 endpar = endpar->LastPhysicalPar()->Next();
1488 undoendpar = endpar;
1492 endpar = endpar->Next(); // because of parindents etc.
1495 SetUndo(bview->buffer(), Undo::EDIT,
1497 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1500 tmppar = sel_end_cursor.par();
1501 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1502 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1503 status = LyXText::NEED_MORE_REFRESH;
1504 refresh_row = cursor.row();
1505 refresh_y = cursor.y() - cursor.row()->baseline();
1506 if (cursor.par()->footnoteflag ==
1507 sel_start_cursor.par()->footnoteflag) {
1508 if (type == LyXParagraph::PEXTRA_NONE) {
1509 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1510 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1511 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1514 cursor.par()->SetPExtraType(bview->buffer()->params,
1515 type, width, widthp);
1516 cursor.par()->pextra_hfill = hfill;
1517 cursor.par()->pextra_start_minipage = start_minipage;
1518 cursor.par()->pextra_alignment = alignment;
1521 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1523 RedoParagraphs(bview, sel_start_cursor, endpar);
1525 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1526 sel_cursor = cursor;
1527 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1529 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1533 char loweralphaCounter(int n)
1535 if (n < 1 || n > 26)
1541 char alphaCounter(int n)
1543 if (n < 1 || n > 26)
1549 char hebrewCounter(int n)
1551 static const char hebrew[22] = {
1552 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1553 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1554 '÷', 'ø', 'ù', 'ú'
1556 if (n < 1 || n > 22)
1562 static char const * romanCounter(int n)
1564 static char const * roman[20] = {
1565 "i", "ii", "iii", "iv", "v",
1566 "vi", "vii", "viii", "ix", "x",
1567 "xi", "xii", "xiii", "xiv", "xv",
1568 "xvi", "xvii", "xviii", "xix", "xx"
1570 if (n < 1 || n > 20)
1576 // set the counter of a paragraph. This includes the labels
1577 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1579 // this is only relevant for the beginning of paragraph
1580 par = par->FirstPhysicalPar();
1582 LyXLayout const & layout =
1583 textclasslist.Style(buf->params.textclass,
1586 LyXTextClass const & textclass =
1587 textclasslist.TextClass(buf->params.textclass);
1589 /* copy the prev-counters to this one, unless this is the start of a
1590 footnote or of a bibliography or the very first paragraph */
1592 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1593 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1594 && par->footnotekind == LyXParagraph::FOOTNOTE)
1595 && !(textclasslist.Style(buf->params.textclass,
1596 par->Previous()->GetLayout()
1597 ).labeltype != LABEL_BIBLIO
1598 && layout.labeltype == LABEL_BIBLIO)) {
1599 for (int i = 0; i < 10; ++i) {
1600 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1602 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1603 if (!par->appendix && par->start_of_appendix){
1604 par->appendix = true;
1605 for (int i = 0; i < 10; ++i) {
1606 par->setCounter(i, 0);
1609 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1610 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1613 for (int i = 0; i < 10; ++i) {
1614 par->setCounter(i, 0);
1616 par->appendix = par->start_of_appendix;
1621 // if this is an open marginnote and this is the first
1622 // entry in the marginnote and the enclosing
1623 // environment is an enum/item then correct for the
1624 // LaTeX behaviour (ARRae)
1625 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1626 && par->footnotekind == LyXParagraph::MARGIN
1628 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1629 && (par->PreviousBeforeFootnote()
1630 && textclasslist.Style(buf->params.textclass,
1631 par->PreviousBeforeFootnote()->GetLayout()
1632 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1633 // Any itemize or enumerate environment in a marginnote
1634 // that is embedded in an itemize or enumerate
1635 // paragraph is seen by LaTeX as being at a deeper
1636 // level within that enclosing itemization/enumeration
1637 // even if there is a "standard" layout at the start of
1643 /* Maybe we have to increment the enumeration depth.
1644 * BUT, enumeration in a footnote is considered in isolation from its
1645 * surrounding paragraph so don't increment if this is the
1646 * first line of the footnote
1647 * AND, bibliographies can't have their depth changed ie. they
1648 * are always of depth 0
1651 && par->Previous()->GetDepth() < par->GetDepth()
1652 && textclasslist.Style(buf->params.textclass,
1653 par->Previous()->GetLayout()
1654 ).labeltype == LABEL_COUNTER_ENUMI
1655 && par->enumdepth < 3
1656 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1657 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1658 && par->footnotekind == LyXParagraph::FOOTNOTE)
1659 && layout.labeltype != LABEL_BIBLIO) {
1663 /* Maybe we have to decrement the enumeration depth, see note above */
1665 && par->Previous()->GetDepth() > par->GetDepth()
1666 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1667 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1668 && par->footnotekind == LyXParagraph::FOOTNOTE)
1669 && layout.labeltype != LABEL_BIBLIO) {
1670 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1671 par->setCounter(6 + par->enumdepth,
1672 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1673 /* reset the counters.
1674 * A depth change is like a breaking layout
1676 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1677 par->setCounter(i, 0);
1680 if (!par->labelstring.empty()) {
1681 par->labelstring.erase();
1684 if (layout.margintype == MARGIN_MANUAL) {
1685 if (par->labelwidthstring.empty()) {
1686 par->SetLabelWidthString(layout.labelstring());
1689 par->SetLabelWidthString(string());
1692 /* is it a layout that has an automatic label ? */
1693 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1695 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1696 if (i >= 0 && i<= buf->params.secnumdepth) {
1697 par->incCounter(i); // increment the counter
1699 // Is there a label? Useful for Chapter layout
1700 if (!par->appendix){
1701 if (!layout.labelstring().empty())
1702 par->labelstring = layout.labelstring();
1704 par->labelstring.erase();
1706 if (!layout.labelstring_appendix().empty())
1707 par->labelstring = layout.labelstring_appendix();
1709 par->labelstring.erase();
1713 std::ostringstream s;
1717 if (!par->appendix) {
1718 switch (2 * LABEL_FIRST_COUNTER -
1719 textclass.maxcounter() + i) {
1720 case LABEL_COUNTER_CHAPTER:
1721 s << par->getCounter(i);
1723 case LABEL_COUNTER_SECTION:
1724 s << par->getCounter(i - 1) << '.'
1725 << par->getCounter(i);
1727 case LABEL_COUNTER_SUBSECTION:
1728 s << par->getCounter(i - 2) << '.'
1729 << par->getCounter(i - 1) << '.'
1730 << par->getCounter(i);
1732 case LABEL_COUNTER_SUBSUBSECTION:
1733 s << par->getCounter(i - 3) << '.'
1734 << par->getCounter(i - 2) << '.'
1735 << par->getCounter(i - 1) << '.'
1736 << par->getCounter(i);
1739 case LABEL_COUNTER_PARAGRAPH:
1740 s << par->getCounter(i - 4) << '.'
1741 << par->getCounter(i - 3) << '.'
1742 << par->getCounter(i - 2) << '.'
1743 << par->getCounter(i - 1) << '.'
1744 << par->getCounter(i);
1746 case LABEL_COUNTER_SUBPARAGRAPH:
1747 s << par->getCounter(i - 5) << '.'
1748 << par->getCounter(i - 4) << '.'
1749 << par->getCounter(i - 3) << '.'
1750 << par->getCounter(i - 2) << '.'
1751 << par->getCounter(i - 1) << '.'
1752 << par->getCounter(i);
1756 s << par->getCounter(i) << '.';
1759 } else { // appendix
1760 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1761 case LABEL_COUNTER_CHAPTER:
1762 if (par->isRightToLeftPar(buf->params))
1763 s << hebrewCounter(par->getCounter(i));
1765 s << alphaCounter(par->getCounter(i));
1767 case LABEL_COUNTER_SECTION:
1768 if (par->isRightToLeftPar(buf->params))
1769 s << hebrewCounter(par->getCounter(i - 1));
1771 s << alphaCounter(par->getCounter(i - 1));
1774 << par->getCounter(i);
1777 case LABEL_COUNTER_SUBSECTION:
1778 if (par->isRightToLeftPar(buf->params))
1779 s << hebrewCounter(par->getCounter(i - 2));
1781 s << alphaCounter(par->getCounter(i - 2));
1784 << par->getCounter(i-1) << '.'
1785 << par->getCounter(i);
1788 case LABEL_COUNTER_SUBSUBSECTION:
1789 if (par->isRightToLeftPar(buf->params))
1790 s << hebrewCounter(par->getCounter(i-3));
1792 s << alphaCounter(par->getCounter(i-3));
1795 << par->getCounter(i-2) << '.'
1796 << par->getCounter(i-1) << '.'
1797 << par->getCounter(i);
1800 case LABEL_COUNTER_PARAGRAPH:
1801 if (par->isRightToLeftPar(buf->params))
1802 s << hebrewCounter(par->getCounter(i-4));
1804 s << alphaCounter(par->getCounter(i-4));
1807 << par->getCounter(i-3) << '.'
1808 << par->getCounter(i-2) << '.'
1809 << par->getCounter(i-1) << '.'
1810 << par->getCounter(i);
1813 case LABEL_COUNTER_SUBPARAGRAPH:
1814 if (par->isRightToLeftPar(buf->params))
1815 s << hebrewCounter(par->getCounter(i-5));
1817 s << alphaCounter(par->getCounter(i-5));
1820 << par->getCounter(i-4) << '.'
1821 << par->getCounter(i-3) << '.'
1822 << par->getCounter(i-2) << '.'
1823 << par->getCounter(i-1) << '.'
1824 << par->getCounter(i);
1828 // Can this ever be reached? And in the
1829 // case it is, how can this be correct?
1831 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1837 par->labelstring += s.str().c_str();
1838 // We really want to remove the c_str as soon as
1842 char * tmps = s.str();
1843 par->labelstring += tmps;
1847 for (i++; i < 10; ++i) {
1848 // reset the following counters
1849 par->setCounter(i, 0);
1851 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1852 for (i++; i < 10; ++i) {
1853 // reset the following counters
1854 par->setCounter(i, 0);
1856 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1857 par->incCounter(i + par->enumdepth);
1858 int number = par->getCounter(i + par->enumdepth);
1861 std::ostringstream s;
1865 switch (par->enumdepth) {
1867 if (par->isRightToLeftPar(buf->params))
1869 << hebrewCounter(number)
1873 << loweralphaCounter(number)
1877 if (par->isRightToLeftPar(buf->params))
1878 s << '.' << romanCounter(number);
1880 s << romanCounter(number) << '.';
1883 if (par->isRightToLeftPar(buf->params))
1885 << alphaCounter(number);
1887 s << alphaCounter(number)
1891 if (par->isRightToLeftPar(buf->params))
1898 par->labelstring = s.str().c_str();
1899 // we really want to get rid of that c_str()
1902 char * tmps = s.str();
1903 par->labelstring = tmps;
1907 for (i += par->enumdepth + 1; i < 10; ++i)
1908 par->setCounter(i, 0); /* reset the following counters */
1911 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1912 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1914 int number = par->getCounter(i);
1916 par->bibkey = new InsetBibKey();
1917 par->bibkey->setCounter(number);
1918 par->labelstring = layout.labelstring();
1920 // In biblio should't be following counters but...
1922 string s = layout.labelstring();
1924 // the caption hack:
1926 if (layout.labeltype == LABEL_SENSITIVE) {
1927 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1928 && (par->footnotekind == LyXParagraph::FIG
1929 || par->footnotekind == LyXParagraph::WIDE_FIG))
1930 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1931 ? ":øåéà " : "Figure:";
1932 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1933 && (par->footnotekind == LyXParagraph::TAB
1934 || par->footnotekind == LyXParagraph::WIDE_TAB))
1935 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1936 ? ":äìáè" : "Table:";
1937 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1938 && par->footnotekind == LyXParagraph::ALGORITHM)
1939 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1940 ? ":Ãúéøåâìà " : "Algorithm:";
1942 /* par->SetLayout(0);
1943 s = layout->labelstring; */
1944 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1945 ? " :úåòîùî øñç" : "Senseless: ";
1948 par->labelstring = s;
1950 /* reset the enumeration counter. They are always resetted
1951 * when there is any other layout between */
1952 for (int i = 6 + par->enumdepth; i < 10; ++i)
1953 par->setCounter(i, 0);
1958 /* Updates all counters BEHIND the row. Changed paragraphs
1959 * with a dynamic left margin will be rebroken. */
1960 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1968 if (row->par()->next
1969 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1970 par = row->par()->LastPhysicalPar()->Next();
1972 par = row->par()->next;
1977 while (row->par() != par)
1980 SetCounter(bview->buffer(), par);
1982 /* now check for the headline layouts. remember that they
1983 * have a dynamic left margin */
1985 && ( textclasslist.Style(bview->buffer()->params.textclass,
1986 par->layout).margintype == MARGIN_DYNAMIC
1987 || textclasslist.Style(bview->buffer()->params.textclass,
1988 par->layout).labeltype == LABEL_SENSITIVE)
1991 /* Rebreak the paragraph */
1992 RemoveParagraph(row);
1993 AppendParagraph(bview, row);
1995 /* think about the damned open footnotes! */
1996 while (par->Next() &&
1997 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1998 || par->Next()->IsDummy())){
2000 if (par->IsDummy()) {
2001 while (row->par() != par)
2003 RemoveParagraph(row);
2004 AppendParagraph(bview, row);
2009 par = par->LastPhysicalPar()->Next();
2015 /* insets an inset. */
2016 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2018 if (!cursor.par()->InsertInsetAllowed(inset))
2020 SetUndo(bview->buffer(), Undo::INSERT,
2021 cursor.par()->ParFromPos(cursor.pos())->previous,
2022 cursor.par()->ParFromPos(cursor.pos())->next);
2023 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2024 cursor.par()->InsertInset(cursor.pos(), inset);
2025 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2026 * The character will not be inserted a
2031 void LyXText::copyEnvironmentType()
2033 copylayouttype = cursor.par()->GetLayout();
2037 void LyXText::pasteEnvironmentType(BufferView * bview)
2039 SetLayout(bview, copylayouttype);
2043 void LyXText::CutSelection(BufferView * bview, bool doclear)
2045 // Stuff what we got on the clipboard. Even if there is no selection.
2047 // There is a problem with having the stuffing here in that the
2048 // larger the selection the slower LyX will get. This can be
2049 // solved by running the line below only when the selection has
2050 // finished. The solution used currently just works, to make it
2051 // faster we need to be more clever and probably also have more
2052 // calls to stuffClipboard. (Lgb)
2053 bview->stuffClipboard(selectionAsString(bview->buffer()));
2055 // This doesn't make sense, if there is no selection
2059 // OK, we have a selection. This is always between sel_start_cursor
2060 // and sel_end cursor
2061 LyXParagraph * tmppar;
2063 // Check whether there are half footnotes in the selection
2064 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2065 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2066 tmppar = sel_start_cursor.par();
2067 while (tmppar != sel_end_cursor.par()){
2068 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2069 WriteAlert(_("Impossible operation"),
2070 _("Don't know what to do with half floats."),
2074 tmppar = tmppar->Next();
2079 /* table stuff -- begin */
2080 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2081 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2082 WriteAlert(_("Impossible operation"),
2083 _("Don't know what to do with half tables."),
2087 sel_start_cursor.par()->table->Reinit();
2089 /* table stuff -- end */
2091 // make sure that the depth behind the selection are restored, too
2092 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2093 LyXParagraph * undoendpar = endpar;
2095 if (endpar && endpar->GetDepth()) {
2096 while (endpar && endpar->GetDepth()) {
2097 endpar = endpar->LastPhysicalPar()->Next();
2098 undoendpar = endpar;
2100 } else if (endpar) {
2101 endpar = endpar->Next(); // because of parindents etc.
2104 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2105 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2109 // there are two cases: cut only within one paragraph or
2110 // more than one paragraph
2111 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2112 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2113 // only within one paragraph
2114 endpar = sel_start_cursor.par();
2115 int pos = sel_end_cursor.pos();
2116 cap.cutSelection(sel_start_cursor.par(), &endpar,
2117 sel_start_cursor.pos(), pos,
2118 bview->buffer()->params.textclass, doclear);
2119 sel_end_cursor.pos(pos);
2121 endpar = sel_end_cursor.par();
2123 int pos = sel_end_cursor.pos();
2124 cap.cutSelection(sel_start_cursor.par(), &endpar,
2125 sel_start_cursor.pos(), pos,
2126 bview->buffer()->params.textclass, doclear);
2128 sel_end_cursor.par(endpar);
2129 sel_end_cursor.pos(pos);
2130 cursor.pos(sel_end_cursor.pos());
2132 endpar = endpar->Next();
2134 // sometimes necessary
2136 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2138 RedoParagraphs(bview, sel_start_cursor, endpar);
2141 cursor = sel_start_cursor;
2142 SetCursor(bview, cursor.par(), cursor.pos());
2143 sel_cursor = cursor;
2144 UpdateCounters(bview, cursor.row());
2148 void LyXText::CopySelection(BufferView * bview)
2150 // Stuff what we got on the clipboard. Even if there is no selection.
2152 // There is a problem with having the stuffing here in that the
2153 // larger the selection the slower LyX will get. This can be
2154 // solved by running the line below only when the selection has
2155 // finished. The solution used currently just works, to make it
2156 // faster we need to be more clever and probably also have more
2157 // calls to stuffClipboard. (Lgb)
2158 bview->stuffClipboard(selectionAsString(bview->buffer()));
2160 // this doesnt make sense, if there is no selection
2164 // ok we have a selection. This is always between sel_start_cursor
2165 // and sel_end cursor
2166 LyXParagraph * tmppar;
2168 /* check wether there are half footnotes in the selection */
2169 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2170 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2171 tmppar = sel_start_cursor.par();
2172 while (tmppar != sel_end_cursor.par()) {
2173 if (tmppar->footnoteflag !=
2174 sel_end_cursor.par()->footnoteflag) {
2175 WriteAlert(_("Impossible operation"),
2176 _("Don't know what to do"
2177 " with half floats."),
2181 tmppar = tmppar->Next();
2186 /* table stuff -- begin */
2187 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2188 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2189 WriteAlert(_("Impossible operation"),
2190 _("Don't know what to do with half tables."),
2195 /* table stuff -- end */
2198 // copy behind a space if there is one
2199 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2200 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2201 && (sel_start_cursor.par() != sel_end_cursor.par()
2202 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2203 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2207 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2208 sel_start_cursor.pos(), sel_end_cursor.pos(),
2209 bview->buffer()->params.textclass);
2213 void LyXText::PasteSelection(BufferView * bview)
2217 // this does not make sense, if there is nothing to paste
2218 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2221 SetUndo(bview->buffer(), Undo::INSERT,
2222 cursor.par()->ParFromPos(cursor.pos())->previous,
2223 cursor.par()->ParFromPos(cursor.pos())->next);
2225 LyXParagraph * endpar;
2226 LyXParagraph * actpar = cursor.par();
2228 int pos = cursor.pos();
2229 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2231 RedoParagraphs(bview, cursor, endpar);
2233 SetCursor(bview, cursor.par(), cursor.pos());
2236 sel_cursor = cursor;
2237 SetCursor(bview, actpar, pos);
2239 UpdateCounters(bview, cursor.row());
2243 // returns a pointer to the very first LyXParagraph
2244 LyXParagraph * LyXText::FirstParagraph() const
2246 return OwnerParagraph();
2250 // returns true if the specified string is at the specified position
2251 bool LyXText::IsStringInText(LyXParagraph * par,
2252 LyXParagraph::size_type pos,
2253 char const * str) const
2257 while (pos + i < par->Last() && str[i] &&
2258 str[i] == par->GetChar(pos + i)) {
2268 // sets the selection over the number of characters of string, no check!!
2269 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2271 sel_cursor = cursor;
2272 for (int i = 0; string[i]; ++i)
2278 // simple replacing. The font of the first selected character is used
2279 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2281 SetCursorParUndo(bview->buffer());
2284 if (!selection) { // create a dummy selection
2285 sel_end_cursor = cursor;
2286 sel_start_cursor = cursor;
2289 // Get font setting before we cut
2290 LyXParagraph::size_type pos = sel_end_cursor.pos();
2291 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2292 sel_start_cursor.pos());
2294 // Insert the new string
2295 for (int i = 0; str[i]; ++i) {
2296 sel_end_cursor.par()->InsertChar(pos, str[i]);
2297 sel_end_cursor.par()->SetFont(pos, font);
2301 // Cut the selection
2302 CutSelection(bview);
2308 // if the string can be found: return true and set the cursor to
2310 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2312 LyXParagraph * par = cursor.par();
2313 LyXParagraph::size_type pos = cursor.pos();
2314 while (par && !IsStringInText(par, pos, str)) {
2315 if (pos < par->Last() - 1)
2323 SetCursor(bview, par, pos);
2331 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2333 LyXParagraph * par = cursor.par();
2334 int pos = cursor.pos();
2340 // We skip empty paragraphs (Asger)
2342 par = par->Previous();
2344 pos = par->Last() - 1;
2345 } while (par && pos < 0);
2347 } while (par && !IsStringInText(par, pos, string));
2350 SetCursor(bview, par, pos);
2357 // needed to insert the selection
2358 void LyXText::InsertStringA(BufferView * bview, string const & str)
2360 LyXParagraph * par = cursor.par();
2361 LyXParagraph::size_type pos = cursor.pos();
2362 LyXParagraph::size_type a = 0;
2364 LyXParagraph * endpar = cursor.par()->Next();
2366 SetCursorParUndo(bview->buffer());
2369 textclasslist.Style(bview->buffer()->params.textclass,
2370 cursor.par()->GetLayout()).isEnvironment();
2371 // only to be sure, should not be neccessary
2374 // insert the string, don't insert doublespace
2375 string::size_type i = 0;
2376 while (i < str.length()) {
2377 if (str[i] != '\n') {
2379 && i + 1 < str.length() && str[i + 1] != ' '
2380 && pos && par->GetChar(pos - 1)!= ' ') {
2381 par->InsertChar(pos,' ');
2382 par->SetFont(pos, current_font);
2385 } else if (par->table) {
2386 if (str[i] == '\t') {
2387 while((pos < par->size()) &&
2388 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2390 if (pos < par->size())
2392 else // no more fields to fill skip the rest
2394 } else if ((str[i] != 13) &&
2395 ((str[i] & 127) >= ' ')) {
2396 par->InsertChar(pos, str[i]);
2397 par->SetFont(pos, current_font);
2401 } else if (str[i] == ' ') {
2402 InsetSpecialChar * new_inset =
2403 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2404 if (par->InsertInsetAllowed(new_inset)) {
2405 par->InsertChar(pos, LyXParagraph::META_INSET);
2406 par->SetFont(pos, current_font);
2407 par->InsertInset(pos, new_inset);
2412 } else if (str[i] == '\t') {
2413 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2414 InsetSpecialChar * new_inset =
2415 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2416 if (par->InsertInsetAllowed(new_inset)) {
2417 par->InsertChar(pos, LyXParagraph::META_INSET);
2418 par->SetFont(pos, current_font);
2419 par->InsertInset(pos, new_inset);
2425 } else if (str[i] != 13 &&
2426 // Ignore unprintables
2427 (str[i] & 127) >= ' ') {
2428 par->InsertChar(pos, str[i]);
2429 par->SetFont(pos, current_font);
2435 if ((i + 1) >= str.length()) {
2436 if (pos < par->size())
2440 while((pos < par->size()) &&
2441 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2444 cell = NumberOfCell(par, pos);
2445 while((pos < par->size()) &&
2446 !(par->table->IsFirstCell(cell))) {
2448 while((pos < par->size()) &&
2449 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2452 cell = NumberOfCell(par, pos);
2454 if (pos >= par->size())
2455 // no more fields to fill skip the rest
2459 if (!par->size()) { // par is empty
2460 InsetSpecialChar * new_inset =
2461 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2462 if (par->InsertInsetAllowed(new_inset)) {
2463 par->InsertChar(pos, LyXParagraph::META_INSET);
2464 par->SetFont(pos, current_font);
2465 par->InsertInset(pos, new_inset);
2471 par->BreakParagraph(bview->buffer()->params, pos, flag);
2481 RedoParagraphs(bview, cursor, endpar);
2482 SetCursor(bview, cursor.par(), cursor.pos());
2483 sel_cursor = cursor;
2484 SetCursor(bview, par, pos);
2489 /* turns double-CR to single CR, others where converted into one blank and 13s
2490 * that are ignored .Double spaces are also converted into one. Spaces at
2491 * the beginning of a paragraph are forbidden. tabs are converted into one
2492 * space. then InsertStringA is called */
2493 void LyXText::InsertStringB(BufferView * bview, string const & s)
2496 LyXParagraph * par = cursor.par();
2497 string::size_type i = 1;
2498 while (i < str.length()) {
2499 if (str[i] == '\t' && !par->table)
2501 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2503 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2504 if (str[i + 1] != '\n') {
2505 if (str[i - 1] != ' ')
2510 while (i + 1 < str.length()
2511 && (str[i + 1] == ' '
2512 || str[i + 1] == '\t'
2513 || str[i + 1] == '\n'
2514 || str[i + 1] == 13)) {
2521 InsertStringA(bview, str);
2525 bool LyXText::GotoNextError(BufferView * bview) const
2527 LyXCursor res = cursor;
2529 if (res.pos() < res.par()->Last() - 1) {
2530 res.pos(res.pos() + 1);
2532 res.par(res.par()->Next());
2536 } while (res.par() &&
2537 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2538 && res.par()->GetInset(res.pos())->AutoDelete()));
2541 SetCursor(bview, res.par(), res.pos());
2548 bool LyXText::GotoNextNote(BufferView * bview) const
2550 LyXCursor res = cursor;
2552 if (res.pos() < res.par()->Last() - 1) {
2553 res.pos(res.pos() + 1);
2555 res.par(res.par()->Next());
2559 } while (res.par() &&
2560 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2561 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2564 SetCursor(bview, res.par(), res.pos());
2571 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2572 LyXParagraph::size_type pos)
2574 LyXCursor tmpcursor;
2577 /* table stuff -- begin*/
2580 CheckParagraphInTable(bview, par, pos);
2584 /* table stuff -- end*/
2587 LyXParagraph::size_type z;
2588 Row * row = GetRow(par, pos, y);
2590 // is there a break one row above
2591 if (row->previous() && row->previous()->par() == row->par()) {
2592 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2593 if ( z >= row->pos()) {
2594 // set the dimensions of the row above
2595 y -= row->previous()->height();
2597 refresh_row = row->previous();
2598 status = LyXText::NEED_MORE_REFRESH;
2600 BreakAgain(bview, row->previous());
2602 // set the cursor again. Otherwise
2603 // dangling pointers are possible
2604 SetCursor(bview, cursor.par(), cursor.pos());
2605 sel_cursor = cursor;
2610 int tmpheight = row->height();
2611 LyXParagraph::size_type tmplast = RowLast(row);
2615 BreakAgain(bview, row);
2616 if (row->height() == tmpheight && RowLast(row) == tmplast)
2617 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2619 status = LyXText::NEED_MORE_REFRESH;
2621 // check the special right address boxes
2622 if (textclasslist.Style(bview->buffer()->params.textclass,
2623 par->GetLayout()).margintype
2624 == MARGIN_RIGHT_ADDRESS_BOX) {
2631 RedoDrawingOfParagraph(bview, tmpcursor);
2637 // set the cursor again. Otherwise dangling pointers are possible
2638 // also set the selection
2642 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2643 sel_cursor = cursor;
2644 SetCursorIntern(bview, sel_start_cursor.par(),
2645 sel_start_cursor.pos());
2646 sel_start_cursor = cursor;
2647 SetCursorIntern(bview, sel_end_cursor.par(),
2648 sel_end_cursor.pos());
2649 sel_end_cursor = cursor;
2650 SetCursorIntern(bview, last_sel_cursor.par(),
2651 last_sel_cursor.pos());
2652 last_sel_cursor = cursor;
2655 SetCursorIntern(bview, cursor.par(), cursor.pos());
2659 // returns false if inset wasn't found
2660 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2662 // first check the current paragraph
2663 int pos = cursor.par()->GetPositionOfInset(inset);
2665 CheckParagraph(bview, cursor.par(), pos);
2669 // check every paragraph
2671 LyXParagraph * par = FirstParagraph();
2673 // make sure the paragraph is open
2674 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2675 pos = par->GetPositionOfInset(inset);
2677 CheckParagraph(bview, par, pos);
2688 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2689 LyXParagraph::size_type pos,
2690 bool setfont, bool boundary) const
2692 LyXCursor old_cursor = cursor;
2693 SetCursorIntern(bview, par, pos, setfont, boundary);
2694 DeleteEmptyParagraphMechanism(bview, old_cursor);
2698 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2699 LyXParagraph::size_type pos, bool boundary) const
2701 // correct the cursor position if impossible
2702 if (pos > par->Last()){
2703 LyXParagraph * tmppar = par->ParFromPos(pos);
2704 pos = par->PositionInParFromPos(pos);
2707 if (par->IsDummy() && par->previous &&
2708 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2709 while (par->previous &&
2710 ((par->previous->IsDummy() &&
2711 (par->previous->previous->footnoteflag ==
2712 LyXParagraph::CLOSED_FOOTNOTE)) ||
2713 (par->previous->footnoteflag ==
2714 LyXParagraph::CLOSED_FOOTNOTE))) {
2715 par = par->previous ;
2716 if (par->IsDummy() &&
2717 (par->previous->footnoteflag ==
2718 LyXParagraph::CLOSED_FOOTNOTE))
2719 pos += par->size() + 1;
2721 if (par->previous) {
2722 par = par->previous;
2724 pos += par->size() + 1;
2729 cur.boundary(boundary);
2731 /* get the cursor y position in text */
2733 Row * row = GetRow(par, pos, y);
2734 /* y is now the beginning of the cursor row */
2735 y += row->baseline();
2736 /* y is now the cursor baseline */
2739 /* now get the cursors x position */
2741 float fill_separator, fill_hfill, fill_label_hfill;
2742 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2744 LyXParagraph::size_type cursor_vpos = 0;
2745 LyXParagraph::size_type last = RowLastPrintable(row);
2747 if (pos > last + 1) // This shouldn't happen.
2749 else if (pos < row->pos())
2752 if (last < row->pos())
2753 cursor_vpos = row->pos();
2754 else if (pos > last && !boundary)
2755 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2756 ? row->pos() : last + 1;
2757 else if (pos > row->pos() &&
2758 (pos > last || boundary ||
2759 (row->par()->table && row->par()->IsNewline(pos))))
2760 /// Place cursor after char at (logical) position pos - 1
2761 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2762 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2764 /// Place cursor before char at (logical) position pos
2765 cursor_vpos = (bidi_level(pos) % 2 == 0)
2766 ? log2vis(pos) : log2vis(pos) + 1;
2769 /* table stuff -- begin*/
2770 if (row->par()->table) {
2771 int cell = NumberOfCell(row->par(), row->pos());
2773 x += row->par()->table->GetBeginningOfTextInCell(cell);
2774 for (LyXParagraph::size_type vpos = row->pos();
2775 vpos < cursor_vpos; ++vpos) {
2776 pos = vis2log(vpos);
2777 if (row->par()->IsNewline(pos)) {
2778 x = x_old + row->par()->table->WidthOfColumn(cell);
2781 x += row->par()->table->GetBeginningOfTextInCell(cell);
2783 x += SingleWidth(bview, row->par(), pos);
2787 /* table stuff -- end*/
2789 LyXParagraph::size_type main_body =
2790 BeginningOfMainBody(bview->buffer(), row->par());
2791 if ((main_body > 0) &&
2792 ((main_body-1 > last) ||
2793 !row->par()->IsLineSeparator(main_body-1)))
2796 for (LyXParagraph::size_type vpos = row->pos();
2797 vpos < cursor_vpos; ++vpos) {
2798 pos = vis2log(vpos);
2799 if (main_body > 0 && pos == main_body-1) {
2800 x += fill_label_hfill +
2801 lyxfont::width(textclasslist.Style(
2802 bview->buffer()->params.textclass,
2803 row->par()->GetLayout())
2805 GetFont(bview->buffer(), row->par(), -2));
2806 if (row->par()->IsLineSeparator(main_body-1))
2807 x -= SingleWidth(bview, row->par(),main_body-1);
2809 if (HfillExpansion(bview->buffer(), row, pos)) {
2810 x += SingleWidth(bview, row->par(), pos);
2811 if (pos >= main_body)
2814 x += fill_label_hfill;
2815 } else if (row->par()->IsSeparator(pos)) {
2816 x += SingleWidth(bview, row->par(), pos);
2817 if (pos >= main_body)
2818 x += fill_separator;
2820 x += SingleWidth(bview, row->par(), pos);
2832 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2833 LyXParagraph::size_type pos,
2834 bool setfont, bool boundary) const
2836 SetCursor(bview, cursor, par, pos, boundary);
2837 // #warning Remove this when verified working (Jug 20000413)
2839 // correct the cursor position if impossible
2840 if (pos > par->Last()){
2841 LyXParagraph * tmppar = par->ParFromPos(pos);
2842 pos = par->PositionInParFromPos(pos);
2845 if (par->IsDummy() && par->previous &&
2846 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2847 while (par->previous &&
2848 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2849 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2850 par = par->previous ;
2851 if (par->IsDummy() &&
2852 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2853 pos += par->size() + 1;
2855 if (par->previous) {
2856 par = par->previous;
2858 pos += par->size() + 1;
2864 /* get the cursor y position in text */
2866 Row * row = GetRow(par, pos, y);
2867 /* y is now the beginning of the cursor row */
2868 y += row->baseline();
2869 /* y is now the cursor baseline */
2872 /* now get the cursors x position */
2874 float fill_separator, fill_hfill, fill_label_hfill;
2875 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2876 LyXParagraph::size_type cursor_vpos;
2877 LyXParagraph::size_type last = RowLastPrintable(row);
2879 if (pos > last + 1) // This shouldn't happen.
2882 if (last < row->pos())
2884 else if (pos > last ||
2885 (pos - 1 >= row->pos() &&
2886 (row->par()->IsSeparator(pos) ||
2887 (row->par()->table && row->par()->IsNewline(pos))
2889 /// Place cursor after char at (logical) position pos-1
2890 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2891 ? log2vis(pos-1) + 1 : log2vis(pos-1);
2893 /// Place cursor before char at (logical) position pos
2894 cursor_vpos = (bidi_level(pos) % 2 == 0)
2895 ? log2vis(pos) : log2vis(pos) + 1;
2898 /* table stuff -- begin*/
2899 if (row->par()->table) {
2900 int cell = NumberOfCell(row->par(), row->pos());
2902 x += row->par()->table->GetBeginningOfTextInCell(cell);
2903 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2904 pos = vis2log(vpos);
2905 if (row->par()->IsNewline(pos)) {
2906 x = x_old + row->par()->table->WidthOfColumn(cell);
2909 x += row->par()->table->GetBeginningOfTextInCell(cell);
2911 x += SingleWidth(row->par(), pos);
2915 /* table stuff -- end*/
2917 LyXParagraph::size_type main_body =
2918 BeginningOfMainBody(row->par());
2919 if (main_body > 0 &&
2920 (main_body-1 > last ||
2921 !row->par()->IsLineSeparator(main_body-1)))
2924 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2925 pos = vis2log(vpos);
2926 if (main_body > 0 && pos == main_body-1) {
2927 x += fill_label_hfill +
2928 lyxfont::width(textclasslist
2929 .Style(bview->buffer()->params.textclass,
2930 row->par()->GetLayout())
2932 GetFont(row->par(), -2));
2933 if (row->par()->IsLineSeparator(main_body-1))
2934 x -= SingleWidth(row->par(), main_body-1);
2936 if (HfillExpansion(row, pos)) {
2937 x += SingleWidth(row->par(), pos);
2938 if (pos >= main_body)
2941 x += fill_label_hfill;
2943 else if (row->par()->IsSeparator(pos)) {
2944 x += SingleWidth(row->par(), pos);
2945 if (pos >= main_body)
2946 x += fill_separator;
2948 x += SingleWidth(row->par(), pos);
2955 cursor.x_fix = cursor.x;
2959 SetCurrentFont(bview);
2962 void LyXText::SetCurrentFont(BufferView * bview) const
2964 LyXParagraph::size_type pos = cursor.pos();
2965 if (cursor.boundary() && pos > 0)
2969 if (pos == cursor.par()->Last() ||
2970 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2972 else if (cursor.par()->IsSeparator(pos)) {
2973 if (pos > cursor.row()->pos() &&
2974 bidi_level(pos) % 2 ==
2975 bidi_level(pos - 1) % 2)
2977 else if (pos + 1 < cursor.par()->Last())
2982 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2983 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2987 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2989 LyXCursor old_cursor = cursor;
2991 /* get the row first */
2993 Row * row = GetRowNearY(y);
2994 cursor.par(row->par());
2997 int column = GetColumnNearX(bview, row, x, bound);
2998 cursor.pos(row->pos() + column);
3000 cursor.y(y + row->baseline());
3002 cursor.boundary(bound);
3003 SetCurrentFont(bview);
3004 DeleteEmptyParagraphMechanism(bview, old_cursor);
3008 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3009 int x, long y) const
3011 /* get the row first */
3013 Row * row = GetRowNearY(y);
3015 int column = GetColumnNearX(bview, row, x, bound);
3017 cur.par(row->par());
3018 cur.pos(row->pos() + column);
3020 cur.y(y + row->baseline());
3022 cur.boundary(bound);
3026 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3028 CursorLeftIntern(bview, internal);
3030 if (cursor.par()->table) {
3031 int cell = NumberOfCell(cursor.par(), cursor.pos());
3032 if (cursor.par()->table->IsContRow(cell)
3033 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3041 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3043 if (cursor.pos() > 0) {
3044 bool boundary = cursor.boundary();
3045 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3046 if (!internal && !boundary &&
3047 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3048 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3049 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3050 LyXParagraph * par = cursor.par()->Previous();
3051 LyXParagraph::size_type pos = par->Last();
3052 SetCursor(bview, par, pos);
3053 if (IsBoundary(bview->buffer(), par, pos))
3054 SetCursor(bview, par, pos, false, true);
3059 void LyXText::CursorRight(BufferView * bview, bool internal) const
3061 CursorRightIntern(bview, internal);
3063 if (cursor.par()->table) {
3064 int cell = NumberOfCell(cursor.par(), cursor.pos());
3065 if (cursor.par()->table->IsContRow(cell) &&
3066 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3074 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3076 if (cursor.pos() < cursor.par()->Last()) {
3077 if (!internal && cursor.boundary() &&
3078 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3079 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3081 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3082 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3083 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3085 } else if (cursor.par()->Next())
3086 SetCursor(bview, cursor.par()->Next(), 0);
3090 void LyXText::CursorUp(BufferView * bview) const
3092 SetCursorFromCoordinates(bview, cursor.x_fix(),
3093 cursor.y() - cursor.row()->baseline() - 1);
3095 if (cursor.par()->table) {
3096 int cell = NumberOfCell(cursor.par(), cursor.pos());
3097 if (cursor.par()->table->IsContRow(cell) &&
3098 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3106 void LyXText::CursorDown(BufferView * bview) const
3109 if (cursor.par()->table &&
3110 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3111 !cursor.par()->next)
3115 SetCursorFromCoordinates(bview, cursor.x_fix(),
3116 cursor.y() - cursor.row()->baseline()
3117 + cursor.row()->height() + 1);
3119 if (cursor.par()->table) {
3120 int cell = NumberOfCell(cursor.par(), cursor.pos());
3121 int cell_above = cursor.par()->table->GetCellAbove(cell);
3122 while(cursor.par()->table &&
3123 cursor.par()->table->IsContRow(cell) &&
3124 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3125 SetCursorFromCoordinates(bview, cursor.x_fix(),
3126 cursor.y() - cursor.row()->baseline()
3127 + cursor.row()->height() + 1);
3128 if (cursor.par()->table) {
3129 cell = NumberOfCell(cursor.par(), cursor.pos());
3130 cell_above = cursor.par()->table->GetCellAbove(cell);
3138 void LyXText::CursorUpParagraph(BufferView * bview) const
3140 if (cursor.pos() > 0) {
3141 SetCursor(bview, cursor.par(), 0);
3143 else if (cursor.par()->Previous()) {
3144 SetCursor(bview, cursor.par()->Previous(), 0);
3149 void LyXText::CursorDownParagraph(BufferView * bview) const
3151 if (cursor.par()->Next()) {
3152 SetCursor(bview, cursor.par()->Next(), 0);
3154 SetCursor(bview, cursor.par(), cursor.par()->Last());
3159 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3160 LyXCursor const & old_cursor) const
3162 // Would be wrong to delete anything if we have a selection.
3163 if (selection) return;
3165 // We allow all kinds of "mumbo-jumbo" when freespacing.
3166 if (textclasslist.Style(bview->buffer()->params.textclass,
3167 old_cursor.par()->GetLayout()).free_spacing)
3170 bool deleted = false;
3172 /* Ok I'll put some comments here about what is missing.
3173 I have fixed BackSpace (and thus Delete) to not delete
3174 double-spaces automagically. I have also changed Cut,
3175 Copy and Paste to hopefully do some sensible things.
3176 There are still some small problems that can lead to
3177 double spaces stored in the document file or space at
3178 the beginning of paragraphs. This happens if you have
3179 the cursor betwenn to spaces and then save. Or if you
3180 cut and paste and the selection have a space at the
3181 beginning and then save right after the paste. I am
3182 sure none of these are very hard to fix, but I will
3183 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3184 that I can get some feedback. (Lgb)
3187 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3188 // delete the LineSeparator.
3191 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3192 // delete the LineSeparator.
3195 // If the pos around the old_cursor were spaces, delete one of them.
3196 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3197 // Only if the cursor has really moved
3199 if (old_cursor.pos() > 0
3200 && old_cursor.pos() < old_cursor.par()->Last()
3201 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3202 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3203 old_cursor.par()->Erase(old_cursor.pos() - 1);
3204 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3206 if (old_cursor.par() == cursor.par() &&
3207 cursor.pos() > old_cursor.pos()) {
3208 SetCursorIntern(bview, cursor.par(),
3211 SetCursorIntern(bview, cursor.par(),
3217 // Do not delete empty paragraphs with keepempty set.
3218 if ((textclasslist.Style(bview->buffer()->params.textclass,
3219 old_cursor.par()->GetLayout())).keepempty)
3222 LyXCursor tmpcursor;
3224 if (old_cursor.par() != cursor.par()) {
3225 if ( (old_cursor.par()->Last() == 0
3226 || (old_cursor.par()->Last() == 1
3227 && old_cursor.par()->IsLineSeparator(0)))
3228 && old_cursor.par()->FirstPhysicalPar()
3229 == old_cursor.par()->LastPhysicalPar()) {
3230 // ok, we will delete anything
3232 // make sure that you do not delete any environments
3233 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3234 !(old_cursor.row()->previous()
3235 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3236 && !(old_cursor.row()->next()
3237 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3238 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3239 && ((old_cursor.row()->previous()
3240 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3241 || (old_cursor.row()->next()
3242 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3244 status = LyXText::NEED_MORE_REFRESH;
3247 if (old_cursor.row()->previous()) {
3248 refresh_row = old_cursor.row()->previous();
3249 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3251 cursor = old_cursor; // that undo can restore the right cursor position
3252 LyXParagraph * endpar = old_cursor.par()->next;
3253 if (endpar && endpar->GetDepth()) {
3254 while (endpar && endpar->GetDepth()) {
3255 endpar = endpar->LastPhysicalPar()->Next();
3258 SetUndo(bview->buffer(), Undo::DELETE,
3259 old_cursor.par()->previous,
3264 RemoveRow(old_cursor.row());
3265 if (OwnerParagraph() == old_cursor.par()) {
3266 OwnerParagraph(OwnerParagraph()->next);
3269 delete old_cursor.par();
3271 /* Breakagain the next par. Needed
3272 * because of the parindent that
3273 * can occur or dissappear. The
3274 * next row can change its height,
3275 * if there is another layout before */
3276 if (refresh_row->next()) {
3277 BreakAgain(bview, refresh_row->next());
3278 UpdateCounters(bview, refresh_row);
3280 SetHeightOfRow(bview, refresh_row);
3282 refresh_row = old_cursor.row()->next();
3283 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3286 cursor = old_cursor; // that undo can restore the right cursor position
3287 LyXParagraph * endpar = old_cursor.par()->next;
3288 if (endpar && endpar->GetDepth()) {
3289 while (endpar && endpar->GetDepth()) {
3290 endpar = endpar->LastPhysicalPar()->Next();
3293 SetUndo(bview->buffer(), Undo::DELETE,
3294 old_cursor.par()->previous,
3299 RemoveRow(old_cursor.row());
3301 if (OwnerParagraph() == old_cursor.par()) {
3302 OwnerParagraph(OwnerParagraph()->next);
3304 delete old_cursor.par();
3306 /* Breakagain the next par. Needed
3307 because of the parindent that can
3308 occur or dissappear.
3309 The next row can change its height,
3310 if there is another layout before
3313 BreakAgain(bview, refresh_row);
3314 UpdateCounters(bview, refresh_row->previous());
3320 SetCursorIntern(bview, cursor.par(), cursor.pos());
3322 if (sel_cursor.par() == old_cursor.par()
3323 && sel_cursor.pos() == sel_cursor.pos()) {
3324 // correct selection
3325 sel_cursor = cursor;
3330 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3331 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3333 SetCursorIntern(bview, cursor.par(), cursor.pos());
3334 sel_cursor = cursor;
3341 LyXParagraph * LyXText::GetParFromID(int id)
3343 LyXParagraph * result = FirstParagraph();
3344 while (result && result->id() != id)
3345 result = result->next;
3351 bool LyXText::TextUndo(BufferView * bview)
3355 // returns false if no undo possible
3356 Undo * undo = bview->buffer()->undostack.pop();
3360 bview->buffer()->redostack
3361 .push(CreateUndo(bview->buffer(), undo->kind,
3362 GetParFromID(undo->number_of_before_par),
3363 GetParFromID(undo->number_of_behind_par)));
3365 return TextHandleUndo(bview, undo);
3369 bool LyXText::TextRedo(BufferView * bview)
3373 // returns false if no redo possible
3374 Undo * undo = bview->buffer()->redostack.pop();
3378 bview->buffer()->undostack
3379 .push(CreateUndo(bview->buffer(), undo->kind,
3380 GetParFromID(undo->number_of_before_par),
3381 GetParFromID(undo->number_of_behind_par)));
3383 return TextHandleUndo(bview, undo);
3387 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3391 // returns false if no undo possible
3392 bool result = false;
3394 LyXParagraph * before =
3395 GetParFromID(undo->number_of_before_par);
3396 LyXParagraph * behind =
3397 GetParFromID(undo->number_of_behind_par);
3398 LyXParagraph * tmppar;
3399 LyXParagraph * tmppar2;
3400 LyXParagraph * endpar;
3401 LyXParagraph * tmppar5;
3403 // if there's no before take the beginning
3404 // of the document for redoing
3406 SetCursorIntern(bview, FirstParagraph(), 0);
3408 // replace the paragraphs with the undo informations
3410 LyXParagraph * tmppar3 = undo->par;
3411 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3412 LyXParagraph * tmppar4 = tmppar3;
3414 while (tmppar4->next)
3415 tmppar4 = tmppar4->next;
3416 } // get last undo par
3418 // now remove the old text if there is any
3419 if (before != behind || (!behind && !before)){
3421 tmppar5 = before->next;
3423 tmppar5 = OwnerParagraph();
3425 while (tmppar5 && tmppar5 != behind){
3427 tmppar5 = tmppar5->next;
3428 // a memory optimization for edit: Only layout information
3429 // is stored in the undo. So restore the text informations.
3430 if (undo->kind == Undo::EDIT) {
3431 tmppar2->setContentsFromPar(tmppar);
3432 tmppar->clearContents();
3433 tmppar2 = tmppar2->next;
3438 // put the new stuff in the list if there is one
3441 before->next = tmppar3;
3443 OwnerParagraph(tmppar3);
3444 tmppar3->previous = before;
3448 OwnerParagraph(behind);
3451 tmppar4->next = behind;
3453 behind->previous = tmppar4;
3457 // Set the cursor for redoing
3459 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3460 // check wether before points to a closed float and open it if necessary
3461 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3462 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3464 while (tmppar4->previous &&
3465 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3466 tmppar4 = tmppar4->previous;
3467 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3468 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3469 tmppar4 = tmppar4->next;
3474 // open a cosed footnote at the end if necessary
3475 if (behind && behind->previous &&
3476 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3477 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3478 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3479 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3480 behind = behind->next;
3484 // calculate the endpar for redoing the paragraphs.
3486 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3487 endpar = behind->LastPhysicalPar()->Next();
3489 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3493 tmppar = GetParFromID(undo->number_of_cursor_par);
3494 RedoParagraphs(bview, cursor, endpar);
3496 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3497 UpdateCounters(bview, cursor.row());
3507 void LyXText::FinishUndo()
3511 // makes sure the next operation will be stored
3512 undo_finished = true;
3516 void LyXText::FreezeUndo()
3520 // this is dangerous and for internal use only
3525 void LyXText::UnFreezeUndo()
3529 // this is dangerous and for internal use only
3530 undo_frozen = false;
3534 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3535 LyXParagraph const * before,
3536 LyXParagraph const * behind) const
3541 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3542 buf->redostack.clear();
3546 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3547 LyXParagraph const * before, LyXParagraph const * behind)
3551 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3555 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3556 LyXParagraph const * before,
3557 LyXParagraph const * behind) const
3562 int before_number = -1;
3563 int behind_number = -1;
3565 before_number = before->id();
3567 behind_number = behind->id();
3568 // Undo::EDIT and Undo::FINISH are
3569 // always finished. (no overlapping there)
3570 // overlapping only with insert and delete inside one paragraph:
3571 // Nobody wants all removed character
3572 // appear one by one when undoing.
3573 // EDIT is special since only layout information, not the
3574 // contents of a paragaph are stored.
3575 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3576 // check wether storing is needed
3577 if (!buf->undostack.empty() &&
3578 buf->undostack.top()->kind == kind &&
3579 buf->undostack.top()->number_of_before_par == before_number &&
3580 buf->undostack.top()->number_of_behind_par == behind_number ){
3585 // create a new Undo
3586 LyXParagraph * undopar;
3587 LyXParagraph * tmppar;
3588 LyXParagraph * tmppar2;
3590 LyXParagraph * start = 0;
3591 LyXParagraph * end = 0;
3594 start = before->next;
3596 start = FirstParagraph();
3598 end = behind->previous;
3600 end = FirstParagraph();
3606 && start != end->next
3607 && (before != behind || (!before && !behind))) {
3609 tmppar2 = tmppar->Clone();
3610 tmppar2->id(tmppar->id());
3612 // a memory optimization: Just store the layout information
3614 if (kind == Undo::EDIT){
3615 //tmppar2->text.clear();
3616 tmppar2->clearContents();
3621 while (tmppar != end && tmppar->next) {
3622 tmppar = tmppar->next;
3623 tmppar2->next = tmppar->Clone();
3624 tmppar2->next->id(tmppar->id());
3625 // a memory optimization: Just store the layout
3626 // information when only edit
3627 if (kind == Undo::EDIT){
3628 //tmppar2->next->text.clear();
3629 tmppar2->clearContents();
3631 tmppar2->next->previous = tmppar2;
3632 tmppar2 = tmppar2->next;
3636 undopar = 0; // nothing to replace (undo of delete maybe)
3638 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3639 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3641 Undo * undo = new Undo(kind,
3642 before_number, behind_number,
3643 cursor_par, cursor_pos,
3646 undo_finished = false;
3651 void LyXText::SetCursorParUndo(Buffer * buf)
3655 SetUndo(buf, Undo::FINISH,
3656 cursor.par()->ParFromPos(cursor.pos())->previous,
3657 cursor.par()->ParFromPos(cursor.pos())->next);
3662 void LyXText::RemoveTableRow(LyXCursor & cur) const
3668 // move to the previous row
3669 int cell_act = NumberOfCell(cur.par(), cur.pos());
3672 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3673 cur.pos(cur.pos() - 1);
3675 !cur.par()->table->IsFirstCell(cell_act)) {
3676 cur.pos(cur.pos() - 1);
3677 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3678 cur.pos(cur.pos() - 1);
3682 // now we have to pay attention if the actual table is the
3683 // main row of TableContRows and if yes to delete all of them
3688 // delete up to the next row
3689 while (cur.pos() < cur.par()->Last() &&
3691 || !cur.par()->table->IsFirstCell(cell_act))) {
3692 while (cur.pos() < cur.par()->Last() &&
3693 !cur.par()->IsNewline(cur.pos()))
3694 cur.par()->Erase(cur.pos());
3697 if (cur.pos() < cur.par()->Last())
3698 cur.par()->Erase(cur.pos());
3700 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3701 cur.pos(cur.pos() - 1);
3702 cur.par()->Erase(cur.pos()); // no newline at very end!
3704 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3705 !cur.par()->table->IsContRow(cell_org) &&
3706 cur.par()->table->IsContRow(cell));
3707 cur.par()->table->DeleteRow(cell_org);
3714 bool LyXText::IsEmptyTableCell() const
3716 LyXParagraph::size_type pos = cursor.pos() - 1;
3717 while (pos >= 0 && pos < cursor.par()->Last()
3718 && !cursor.par()->IsNewline(pos))
3720 return cursor.par()->IsNewline(pos + 1);
3725 void LyXText::toggleAppendix(BufferView * bview)
3727 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3728 bool start = !par->start_of_appendix;
3730 // ensure that we have only one start_of_appendix in this document
3731 LyXParagraph * tmp = FirstParagraph();
3732 for (; tmp; tmp = tmp->next)
3733 tmp->start_of_appendix = 0;
3734 par->start_of_appendix = start;
3736 // we can set the refreshing parameters now
3737 status = LyXText::NEED_MORE_REFRESH;
3739 refresh_row = 0; // not needed for full update
3740 UpdateCounters(bview, 0);
3741 SetCursor(bview, cursor.par(), cursor.pos());
3744 LyXParagraph * LyXText::OwnerParagraph() const
3747 return inset_owner->par;
3749 return bv_owner->buffer()->paragraph;
3753 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3756 inset_owner->par = p;
3758 bv_owner->buffer()->paragraph = p;