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"
27 #include "support/textutils.h"
29 #include "minibuffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
35 #include "BufferView.h"
38 #include "CutAndPaste.h"
43 //#define USE_OLD_CUT_AND_PASTE 1
49 LyXText::LyXText(BufferView * bv)
57 LyXText::LyXText(InsetText * inset)
72 status = LyXText::UNCHANGED;
73 // set cursor at the very top position
74 selection = true; /* these setting is necessary
75 because of the delete-empty-
76 paragraph mechanism in
79 LyXParagraph * par = OwnerParagraph();
80 current_font = GetFont(bv_owner->buffer(), par, 0);
82 InsertParagraph(bv_owner, par, lastrow);
85 SetCursor(bv_owner, firstrow->par(), 0);
87 current_font = LyXFont(LyXFont::ALL_SANE);
93 // no rebreak necessary
99 // Default layouttype for copy environment type
103 // Dump all rowinformation:
104 Row * tmprow = firstrow;
105 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
107 lyxerr << tmprow->baseline() << '\t'
108 << tmprow->par << '\t'
109 << tmprow->pos() << '\t'
110 << tmprow->height << '\t'
111 << tmprow->ascent_of_text << '\t'
112 << tmprow->fill << '\n';
113 tmprow = tmprow->next();
120 void LyXText::init(BufferView * bview)
125 LyXParagraph * par = OwnerParagraph();
126 current_font = GetFont(bview->buffer(), par, 0);
128 InsertParagraph(bview, par, lastrow);
131 SetCursorIntern(bview, firstrow->par(), 0);
133 // Dump all rowinformation:
134 Row * tmprow = firstrow;
135 lyxerr << "Width = " << width << endl;
136 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
138 lyxerr << tmprow->baseline() << '\t'
139 << tmprow->par() << '\t'
140 << tmprow->pos() << '\t'
141 << tmprow->height() << '\t'
142 << tmprow->ascent_of_text() << '\t'
143 << tmprow->fill() << '\n';
144 tmprow = tmprow->next();
152 // Delete all rows, this does not touch the paragraphs!
153 Row * tmprow = firstrow;
155 tmprow = firstrow->next();
163 void LyXText::owner(BufferView * bv)
165 if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
170 // Gets the fully instantiated font at a given position in a paragraph
171 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
172 // The difference is that this one is used for displaying, and thus we
173 // are allowed to make cosmetic improvements. For instance make footnotes
175 // If position is -1, we get the layout font of the paragraph.
176 // If position is -2, we get the font of the manual label of the paragraph.
177 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
178 LyXParagraph::size_type pos) const
180 LyXLayout const & layout =
181 textclasslist.Style(buf->params.textclass, par->GetLayout());
183 char par_depth = par->GetDepth();
184 // We specialize the 95% common case:
185 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
188 if (layout.labeltype == LABEL_MANUAL
189 && pos < BeginningOfMainBody(buf, par)) {
191 return par->GetFontSettings(buf->params, pos).
192 realize(layout.reslabelfont);
194 return par->GetFontSettings(buf->params, pos).
195 realize(layout.resfont);
198 // process layoutfont for pos == -1 and labelfont for pos < -1
200 return layout.resfont;
202 return layout.reslabelfont;
206 // The uncommon case need not be optimized as much
208 LyXFont layoutfont, tmpfont;
212 if (pos < BeginningOfMainBody(buf, par)) {
214 layoutfont = layout.labelfont;
217 layoutfont = layout.font;
219 tmpfont = par->GetFontSettings(buf->params, pos);
220 tmpfont.realize(layoutfont);
223 // process layoutfont for pos == -1 and labelfont for pos < -1
225 tmpfont = layout.font;
227 tmpfont = layout.labelfont;
230 // Resolve against environment font information
231 while (par && par_depth && !tmpfont.resolved()) {
232 par = par->DepthHook(par_depth - 1);
234 tmpfont.realize(textclasslist.
235 Style(buf->params.textclass,
236 par->GetLayout()).font);
237 par_depth = par->GetDepth();
241 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
243 // Cosmetic improvement: If this is an open footnote, make the font
245 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
246 && par->footnotekind == LyXParagraph::FOOTNOTE) {
254 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
255 LyXParagraph::size_type pos,
259 // Let the insets convert their font
260 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
261 if (par->GetInset(pos))
262 font = par->GetInset(pos)->ConvertFont(font);
265 LyXLayout const & layout =
266 textclasslist.Style(buf->params.textclass,
269 // Get concrete layout font to reduce against
272 if (pos < BeginningOfMainBody(buf, par))
273 layoutfont = layout.labelfont;
275 layoutfont = layout.font;
277 // Realize against environment font information
278 if (par->GetDepth()){
279 LyXParagraph * tp = par;
280 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
281 tp = tp->DepthHook(tp->GetDepth()-1);
283 layoutfont.realize(textclasslist.
284 Style(buf->params.textclass,
285 tp->GetLayout()).font);
289 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
291 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
292 && par->footnotekind == LyXParagraph::FOOTNOTE) {
293 layoutfont.decSize();
296 // Now, reduce font against full layout font
297 font.reduce(layoutfont);
299 par->SetFont(pos, font);
303 /* inserts a new row behind the specified row, increments
304 * the touched counters */
305 void LyXText::InsertRow(Row * row, LyXParagraph * par,
306 LyXParagraph::size_type pos) const
308 Row * tmprow = new Row;
311 tmprow->next(firstrow);
314 tmprow->previous(row);
315 tmprow->next(row->next());
320 tmprow->next()->previous(tmprow);
322 if (tmprow->previous())
323 tmprow->previous()->next(tmprow);
331 ++number_of_rows; // one more row
335 // removes the row and reset the touched counters
336 void LyXText::RemoveRow(Row * row) const
338 /* this must not happen before the currentrow for clear reasons.
339 so the trick is just to set the current row onto the previous
342 GetRow(row->par(), row->pos(), unused_y);
345 row->next()->previous(row->previous());
346 if (!row->previous()) {
347 firstrow = row->next();
349 row->previous()->next(row->next());
352 lastrow = row->previous();
354 height -= row->height(); // the text becomes smaller
357 --number_of_rows; // one row less
361 // remove all following rows of the paragraph of the specified row.
362 void LyXText::RemoveParagraph(Row * row) const
364 LyXParagraph * tmppar = row->par();
368 while (row && row->par() == tmppar) {
369 tmprow = row->next();
376 // insert the specified paragraph behind the specified row
377 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
380 InsertRow(row, par, 0); /* insert a new row, starting
383 SetCounter(bview->buffer(), par); // set the counters
385 // and now append the whole paragraph behind the new row
388 AppendParagraph(bview, firstrow);
390 row->next()->height(0);
391 AppendParagraph(bview, row->next());
396 void LyXText::ToggleFootnote(BufferView * bview)
398 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
400 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
402 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
404 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
405 CloseFootnote(bview);
410 void LyXText::OpenStuff(BufferView * bview)
412 if (cursor.pos() == 0 && cursor.par()->bibkey){
413 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
415 else if (cursor.pos() < cursor.par()->Last()
416 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
417 && cursor.par()->GetInset(cursor.pos())->Editable()) {
418 bview->owner()->getMiniBuffer()
419 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
420 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
421 SetCursorParUndo(bview->buffer());
422 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
424 ToggleFootnote(bview);
429 void LyXText::CloseFootnote(BufferView * bview)
431 LyXParagraph * tmppar;
432 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
434 // if the cursor is not in an open footnote, or
435 // there is no open footnote in this paragraph, just return.
436 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
439 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
440 bview->owner()->getMiniBuffer()
441 ->Set(_("Nothing to do"));
445 // ok, move the cursor right before the footnote
446 // just a little faster than using CursorRight()
448 cursor.par()->ParFromPos(cursor.pos()) != par;) {
449 cursor.pos(cursor.pos() + 1);
452 // now the cursor is at the beginning of the physical par
453 SetCursor(bview, cursor.par(),
455 cursor.par()->ParFromPos(cursor.pos())->size());
457 /* we are in a footnote, so let us move at the beginning */
458 /* this is just faster than using just CursorLeft() */
460 tmppar = cursor.par();
461 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
462 // just a little bit faster than movin the cursor
463 tmppar = tmppar->Previous();
465 SetCursor(bview, tmppar, tmppar->Last());
468 // the cursor must be exactly before the footnote
469 par = cursor.par()->ParFromPos(cursor.pos());
471 status = LyXText::NEED_MORE_REFRESH;
472 refresh_row = cursor.row();
473 refresh_y = cursor.y() - cursor.row()->baseline();
475 tmppar = cursor.par();
476 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
477 Row * row = cursor.row();
479 tmppar->CloseFootnote(cursor.pos());
481 while (tmppar != endpar) {
482 RemoveRow(row->next());
484 tmppar = row->next()->par();
489 AppendParagraph(bview, cursor.row());
491 SetCursor(bview, cursor.par(), cursor.pos());
495 if (cursor.row()->next())
496 SetHeightOfRow(bview, cursor.row()->next());
500 /* used in setlayout */
501 // Asger is not sure we want to do this...
502 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
505 LyXLayout const & layout =
506 textclasslist.Style(buf->params.textclass, par->GetLayout());
508 LyXFont layoutfont, tmpfont;
509 for (LyXParagraph::size_type pos = 0;
510 pos < par->Last(); ++pos) {
511 if (pos < BeginningOfMainBody(buf, par))
512 layoutfont = layout.labelfont;
514 layoutfont = layout.font;
516 tmpfont = par->GetFontSettings(buf->params, pos);
517 tmpfont.reduce(layoutfont);
518 par->SetFont(pos, tmpfont);
522 LyXParagraph * LyXText::SetLayout(BufferView * bview,
523 LyXCursor & cur, LyXCursor & sstart_cur,
524 LyXCursor & send_cur,
525 LyXTextClass::size_type layout)
527 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
528 LyXParagraph * undoendpar = endpar;
530 if (endpar && endpar->GetDepth()) {
531 while (endpar && endpar->GetDepth()) {
532 endpar = endpar->LastPhysicalPar()->Next();
536 endpar = endpar->Next(); // because of parindents etc.
539 SetUndo(bview->buffer(), Undo::EDIT,
540 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
543 /* ok we have a selection. This is always between sstart_cur
544 * and sel_end cursor */
547 LyXLayout const & lyxlayout =
548 textclasslist.Style(bview->buffer()->params.textclass, layout);
550 while (cur.par() != send_cur.par()) {
551 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
552 cur.par()->SetLayout(bview->buffer()->params, layout);
553 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
554 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
555 fppar->added_space_top = lyxlayout.fill_top ?
556 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
557 fppar->added_space_bottom = lyxlayout.fill_bottom ?
558 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
559 if (lyxlayout.margintype == MARGIN_MANUAL)
560 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
561 if (lyxlayout.labeltype != LABEL_BIBLIO
563 delete fppar->bibkey;
567 cur.par(cur.par()->Next());
569 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
570 cur.par()->SetLayout(bview->buffer()->params, layout);
571 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
572 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
573 fppar->added_space_top = lyxlayout.fill_top ?
574 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
575 fppar->added_space_bottom = lyxlayout.fill_bottom ?
576 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
577 if (lyxlayout.margintype == MARGIN_MANUAL)
578 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
579 if (lyxlayout.labeltype != LABEL_BIBLIO
581 delete fppar->bibkey;
588 // set layout over selection and make a total rebreak of those paragraphs
589 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
592 tmpcursor = cursor; /* store the current cursor */
594 #ifdef USE_OLD_SET_LAYOUT
595 // if there is no selection just set the layout
596 // of the current paragraph */
598 sel_start_cursor = cursor; // dummy selection
599 sel_end_cursor = cursor;
602 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
603 LyXParagraph * undoendpar = endpar;
605 if (endpar && endpar->GetDepth()) {
606 while (endpar && endpar->GetDepth()) {
607 endpar = endpar->LastPhysicalPar()->Next();
612 endpar = endpar->Next(); // because of parindents etc.
616 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
619 /* ok we have a selection. This is always between sel_start_cursor
620 * and sel_end cursor */
621 cursor = sel_start_cursor;
623 LyXLayout const & lyxlayout =
624 textclasslist.Style(bview->buffer()->params.textclass, layout);
626 while (cursor.par() != sel_end_cursor.par()) {
627 if (cursor.par()->footnoteflag ==
628 sel_start_cursor.par()->footnoteflag) {
629 cursor.par()->SetLayout(layout);
630 MakeFontEntriesLayoutSpecific(cursor.par());
631 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
632 fppar->added_space_top = lyxlayout.fill_top ?
633 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
634 fppar->added_space_bottom = lyxlayout.fill_bottom ?
635 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
636 if (lyxlayout.margintype == MARGIN_MANUAL)
637 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
638 if (lyxlayout.labeltype != LABEL_BIBLIO
640 delete fppar->bibkey;
644 cursor.par() = cursor.par()->Next();
646 if (cursor.par()->footnoteflag ==
647 sel_start_cursor.par()->footnoteflag) {
648 cursor.par()->SetLayout(layout);
649 MakeFontEntriesLayoutSpecific(cursor.par());
650 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
651 fppar->added_space_top = lyxlayout.fill_top ?
652 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
653 fppar->added_space_bottom = lyxlayout.fill_bottom ?
654 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
655 if (lyxlayout.margintype == MARGIN_MANUAL)
656 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
657 if (lyxlayout.labeltype != LABEL_BIBLIO
659 delete fppar->bibkey;
664 // if there is no selection just set the layout
665 // of the current paragraph */
667 sel_start_cursor = cursor; // dummy selection
668 sel_end_cursor = cursor;
671 endpar = SetLayout(bview, cursor, sel_start_cursor,
672 sel_end_cursor, layout);
674 RedoParagraphs(bview, sel_start_cursor, endpar);
676 // we have to reset the selection, because the
677 // geometry could have changed */
678 SetCursor(bview, sel_start_cursor.par(),
679 sel_start_cursor.pos(), false);
681 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
683 UpdateCounters(bview, cursor.row());
686 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
690 // increment depth over selection and
691 // make a total rebreak of those paragraphs
692 void LyXText::IncDepth(BufferView * bview)
694 // If there is no selection, just use the current paragraph
696 sel_start_cursor = cursor; // dummy selection
697 sel_end_cursor = cursor;
700 // We end at the next paragraph with depth 0
701 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
702 LyXParagraph * undoendpar = endpar;
704 if (endpar && endpar->GetDepth()) {
705 while (endpar && endpar->GetDepth()) {
706 endpar = endpar->LastPhysicalPar()->Next();
711 endpar = endpar->Next(); // because of parindents etc.
714 SetUndo(bview->buffer(), Undo::EDIT,
716 .par()->ParFromPos(sel_start_cursor.pos())->previous,
719 LyXCursor tmpcursor = cursor; // store the current cursor
721 // ok we have a selection. This is always between sel_start_cursor
722 // and sel_end cursor
723 cursor = sel_start_cursor;
725 bool anything_changed = false;
728 // NOTE: you can't change the depth of a bibliography entry
729 if (cursor.par()->footnoteflag ==
730 sel_start_cursor.par()->footnoteflag
731 && textclasslist.Style(bview->buffer()->params.textclass,
732 cursor.par()->GetLayout()
733 ).labeltype != LABEL_BIBLIO) {
734 LyXParagraph * prev =
735 cursor.par()->FirstPhysicalPar()->Previous();
737 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
738 || (prev->GetDepth() == cursor.par()->GetDepth()
739 && textclasslist.Style(bview->buffer()->params.textclass,
740 prev->GetLayout()).isEnvironment()))) {
741 cursor.par()->FirstPhysicalPar()->depth++;
742 anything_changed = true;
745 if (cursor.par() == sel_end_cursor.par())
747 cursor.par(cursor.par()->Next());
750 // if nothing changed set all depth to 0
751 if (!anything_changed) {
752 cursor = sel_start_cursor;
753 while (cursor.par() != sel_end_cursor.par()) {
754 cursor.par()->FirstPhysicalPar()->depth = 0;
755 cursor.par(cursor.par()->Next());
757 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
758 cursor.par()->FirstPhysicalPar()->depth = 0;
761 RedoParagraphs(bview, sel_start_cursor, endpar);
763 // we have to reset the selection, because the
764 // geometry could have changed
765 SetCursor(bview, sel_start_cursor.par(),
766 sel_start_cursor.pos());
768 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
769 UpdateCounters(bview, cursor.row());
772 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
776 // decrement depth over selection and
777 // make a total rebreak of those paragraphs
778 void LyXText::DecDepth(BufferView * bview)
780 // if there is no selection just set the layout
781 // of the current paragraph
783 sel_start_cursor = cursor; // dummy selection
784 sel_end_cursor = cursor;
787 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
788 LyXParagraph * undoendpar = endpar;
790 if (endpar && endpar->GetDepth()) {
791 while (endpar && endpar->GetDepth()) {
792 endpar = endpar->LastPhysicalPar()->Next();
797 endpar = endpar->Next(); // because of parindents etc.
800 SetUndo(bview->buffer(), Undo::EDIT,
802 .par()->ParFromPos(sel_start_cursor.pos())->previous,
805 LyXCursor tmpcursor = cursor; // store the current cursor
807 // ok we have a selection. This is always between sel_start_cursor
808 // and sel_end cursor
809 cursor = sel_start_cursor;
812 if (cursor.par()->footnoteflag ==
813 sel_start_cursor.par()->footnoteflag) {
814 if (cursor.par()->FirstPhysicalPar()->depth)
815 cursor.par()->FirstPhysicalPar()->depth--;
817 if (cursor.par() == sel_end_cursor.par())
819 cursor.par(cursor.par()->Next());
822 RedoParagraphs(bview, sel_start_cursor, endpar);
824 // we have to reset the selection, because the
825 // geometry could have changed
826 SetCursor(bview, sel_start_cursor.par(),
827 sel_start_cursor.pos());
829 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
830 UpdateCounters(bview, cursor.row());
833 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
837 // set font over selection and make a total rebreak of those paragraphs
838 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
840 // if there is no selection just set the current_font
842 // Determine basis font
844 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
846 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
848 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
849 // Update current font
850 real_current_font.update(font,
851 bview->buffer()->params.language_info,
854 // Reduce to implicit settings
855 current_font = real_current_font;
856 current_font.reduce(layoutfont);
857 // And resolve it completely
858 real_current_font.realize(layoutfont);
862 LyXCursor tmpcursor = cursor; // store the current cursor
864 // ok we have a selection. This is always between sel_start_cursor
865 // and sel_end cursor
867 SetUndo(bview->buffer(), Undo::EDIT,
868 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
869 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
870 cursor = sel_start_cursor;
871 while (cursor.par() != sel_end_cursor.par() ||
872 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
873 && cursor.pos() < sel_end_cursor.pos()))
875 if (cursor.pos() < cursor.par()->Last()
876 && cursor.par()->footnoteflag
877 == sel_start_cursor.par()->footnoteflag) {
878 // an open footnote should behave
880 LyXFont newfont = GetFont(bview->buffer(),
881 cursor.par(), cursor.pos());
883 bview->buffer()->params.language_info,
885 SetCharFont(bview->buffer(),
886 cursor.par(), cursor.pos(), newfont);
887 cursor.pos(cursor.pos() + 1);
890 cursor.par(cursor.par()->Next());
894 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
896 // we have to reset the selection, because the
897 // geometry could have changed
898 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
900 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
903 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
904 tmpcursor.boundary());
908 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
910 Row * tmprow = cur.row();
911 long y = cur.y() - tmprow->baseline();
913 SetHeightOfRow(bview, tmprow);
914 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
915 // find the first row of the paragraph
916 if (first_phys_par != tmprow->par())
917 while (tmprow->previous()
918 && tmprow->previous()->par() != first_phys_par) {
919 tmprow = tmprow->previous();
920 y -= tmprow->height();
921 SetHeightOfRow(bview, tmprow);
923 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
924 tmprow = tmprow->previous();
925 y -= tmprow->height();
926 SetHeightOfRow(bview, tmprow);
929 // we can set the refreshing parameters now
930 status = LyXText::NEED_MORE_REFRESH;
932 refresh_row = tmprow;
933 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
937 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
939 Row * tmprow = cur.row();
941 long y = cur.y() - tmprow->baseline();
942 SetHeightOfRow(bview, tmprow);
943 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
944 // find the first row of the paragraph
945 if (first_phys_par != tmprow->par())
946 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
947 tmprow = tmprow->previous();
948 y -= tmprow->height();
950 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
951 tmprow = tmprow->previous();
952 y -= tmprow->height();
955 // we can set the refreshing parameters now
956 if (status == LyXText::UNCHANGED || y < refresh_y) {
958 refresh_row = tmprow;
960 status = LyXText::NEED_MORE_REFRESH;
961 SetCursor(bview, cur.par(), cur.pos());
965 /* deletes and inserts again all paragaphs between the cursor
966 * and the specified par
967 * This function is needed after SetLayout and SetFont etc. */
968 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
969 LyXParagraph const * endpar) const
972 LyXParagraph * tmppar = 0, * first_phys_par = 0;
974 Row * tmprow = cur.row();
976 long y = cur.y() - tmprow->baseline();
978 if (!tmprow->previous()){
979 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
981 first_phys_par = tmprow->par()->FirstPhysicalPar();
982 // find the first row of the paragraph
983 if (first_phys_par != tmprow->par())
984 while (tmprow->previous() &&
985 (tmprow->previous()->par() != first_phys_par)) {
986 tmprow = tmprow->previous();
987 y -= tmprow->height();
989 while (tmprow->previous()
990 && tmprow->previous()->par() == first_phys_par) {
991 tmprow = tmprow->previous();
992 y -= tmprow->height();
996 // we can set the refreshing parameters now
997 status = LyXText::NEED_MORE_REFRESH;
999 refresh_row = tmprow->previous(); /* the real refresh row will
1000 be deleted, so I store
1001 the previous here */
1004 tmppar = tmprow->next()->par();
1007 while (tmppar != endpar) {
1008 RemoveRow(tmprow->next());
1010 tmppar = tmprow->next()->par();
1015 // remove the first one
1016 tmprow2 = tmprow; /* this is because tmprow->previous()
1018 tmprow = tmprow->previous();
1021 tmppar = first_phys_par;
1025 InsertParagraph(bview, tmppar, tmprow);
1028 while (tmprow->next() && tmprow->next()->par() == tmppar)
1029 tmprow = tmprow->next();
1030 tmppar = tmppar->Next();
1032 } while (tmppar != endpar);
1034 // this is because of layout changes
1036 refresh_y -= refresh_row->height();
1037 SetHeightOfRow(bview, refresh_row);
1039 refresh_row = firstrow;
1041 SetHeightOfRow(bview, refresh_row);
1044 if (tmprow && tmprow->next())
1045 SetHeightOfRow(bview, tmprow->next());
1049 bool LyXText::FullRebreak(BufferView * bview)
1051 if (need_break_row) {
1052 BreakAgain(bview, need_break_row);
1060 /* important for the screen */
1063 /* the cursor set functions have a special mechanism. When they
1064 * realize, that you left an empty paragraph, they will delete it.
1065 * They also delete the corresponding row */
1067 // need the selection cursor:
1068 void LyXText::SetSelection()
1071 last_sel_cursor = sel_cursor;
1072 sel_start_cursor = sel_cursor;
1073 sel_end_cursor = sel_cursor;
1078 // first the toggling area
1079 if (cursor.y() < last_sel_cursor.y()
1080 || (cursor.y() == last_sel_cursor.y()
1081 && cursor.x() < last_sel_cursor.x())) {
1082 toggle_end_cursor = last_sel_cursor;
1083 toggle_cursor = cursor;
1085 toggle_end_cursor = cursor;
1086 toggle_cursor = last_sel_cursor;
1089 last_sel_cursor = cursor;
1091 // and now the whole selection
1093 if (sel_cursor.par() == cursor.par())
1094 if (sel_cursor.pos() < cursor.pos()) {
1095 sel_end_cursor = cursor;
1096 sel_start_cursor = sel_cursor;
1098 sel_end_cursor = sel_cursor;
1099 sel_start_cursor = cursor;
1101 else if (sel_cursor.y() < cursor.y() ||
1102 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1103 sel_end_cursor = cursor;
1104 sel_start_cursor = sel_cursor;
1107 sel_end_cursor = sel_cursor;
1108 sel_start_cursor = cursor;
1111 // a selection with no contents is not a selection
1112 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1113 sel_start_cursor.pos() == sel_end_cursor.pos())
1118 string LyXText::selectionAsString(Buffer const * buffer) const
1120 if (!selection) return string();
1123 // Special handling if the whole selection is within one paragraph
1124 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1125 result += sel_start_cursor.par()->String(buffer,
1126 sel_start_cursor.pos(),
1127 sel_end_cursor.pos());
1131 // The selection spans more than one paragraph
1133 // First paragraph in selection
1134 result += sel_start_cursor.par()->String(buffer,
1135 sel_start_cursor.pos(),
1136 sel_start_cursor.par()->Last())
1139 // The paragraphs in between (if any)
1140 LyXCursor tmpcur(sel_start_cursor);
1141 tmpcur.par(tmpcur.par()->Next());
1142 while (tmpcur.par() != sel_end_cursor.par()) {
1143 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1144 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1147 // Last paragraph in selection
1148 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1154 void LyXText::ClearSelection() const
1161 void LyXText::CursorHome(BufferView * bview) const
1163 SetCursor(bview, cursor.par(), cursor.row()->pos());
1167 void LyXText::CursorEnd(BufferView * bview) const
1169 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1170 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1172 if (cursor.par()->Last() &&
1173 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1174 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1175 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1177 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1180 if (cursor.par()->table) {
1181 int cell = NumberOfCell(cursor.par(), cursor.pos());
1182 if (cursor.par()->table->RowHasContRow(cell) &&
1183 cursor.par()->table->CellHasContRow(cell)<0) {
1184 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1185 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1187 if (cursor.par()->Last() &&
1188 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1189 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1190 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1192 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1200 void LyXText::CursorTop(BufferView * bview) const
1202 while (cursor.par()->Previous())
1203 cursor.par(cursor.par()->Previous());
1204 SetCursor(bview, cursor.par(), 0);
1208 void LyXText::CursorBottom(BufferView * bview) const
1210 while (cursor.par()->Next())
1211 cursor.par(cursor.par()->Next());
1212 SetCursor(bview, cursor.par(), cursor.par()->Last());
1216 /* returns a pointer to the row near the specified y-coordinate
1217 * (relative to the whole text). y is set to the real beginning
1219 Row * LyXText::GetRowNearY(long & y) const
1221 Row * tmprow = firstrow;
1224 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1225 tmpy += tmprow->height();
1226 tmprow = tmprow->next();
1229 y = tmpy; // return the real y
1234 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1236 // If the mask is completely neutral, tell user
1237 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1238 // Could only happen with user style
1239 bview->owner()->getMiniBuffer()
1240 ->Set(_("No font change defined. Use Character under"
1241 " the Layout menu to define font change."));
1245 // Try implicit word selection
1246 // If there is a change in the language the implicit word selection
1248 LyXCursor resetCursor = cursor;
1249 bool implicitSelection = (font.language() == ignore_language)
1250 ? SelectWordWhenUnderCursor(bview) : false;
1253 SetFont(bview, font, toggleall);
1255 /* Implicit selections are cleared afterwards and cursor is set to the
1256 original position. */
1257 if (implicitSelection) {
1259 cursor = resetCursor;
1260 SetCursor(bview, cursor.par(), cursor.pos());
1261 sel_cursor = cursor;
1266 LyXParagraph::size_type
1267 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1269 if (textclasslist.Style(buf->params.textclass,
1270 par->GetLayout()).labeltype != LABEL_MANUAL)
1273 return par->BeginningOfMainBody();
1277 /* if there is a selection, reset every environment you can find
1278 * in the selection, otherwise just the environment you are in */
1279 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1281 LyXParagraph * tmppar, * firsttmppar;
1285 /* is is only allowed, if the cursor is IN an open footnote.
1286 * Otherwise it is too dangerous */
1287 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1290 SetUndo(bview->buffer(), Undo::FINISH,
1291 cursor.par()->PreviousBeforeFootnote()->previous,
1292 cursor.par()->NextAfterFootnote()->next);
1294 /* ok, move to the beginning of the footnote. */
1295 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1296 cursor.par(cursor.par()->Previous());
1298 SetCursor(bview, cursor.par(), cursor.par()->Last());
1299 /* this is just faster than using CursorLeft(); */
1301 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1302 tmppar = firsttmppar;
1303 /* tmppar is now the paragraph right before the footnote */
1305 bool first_footnote_par_is_not_empty = tmppar->next->size();
1308 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1309 tmppar = tmppar->next; /* I use next instead of Next(),
1310 * because there cannot be any
1311 * footnotes in a footnote
1313 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1315 /* remember the captions and empty paragraphs */
1316 if ((textclasslist.Style(bview->buffer()->params.textclass,
1317 tmppar->GetLayout())
1318 .labeltype == LABEL_SENSITIVE)
1320 tmppar->SetLayout(bview->buffer()->params, 0);
1323 // now we will paste the ex-footnote, if the layouts allow it
1324 // first restore the layout of the paragraph right behind
1327 tmppar->next->MakeSameLayout(cursor.par());
1330 if ((!tmppar->GetLayout() && !tmppar->table)
1332 && (!tmppar->Next()->Last()
1333 || tmppar->Next()->HasSameLayout(tmppar)))) {
1334 if (tmppar->Next()->Last()
1335 && tmppar->Next()->IsLineSeparator(0))
1336 tmppar->Next()->Erase(0);
1337 tmppar->PasteParagraph(bview->buffer()->params);
1340 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1341 * by the pasting of the beginning */
1343 /* then the beginning */
1344 /* if there is no space between the text and the footnote, so we insert
1346 * (only if the previous par and the footnotepar are not empty!) */
1347 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1348 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1349 if (firsttmppar->size()
1350 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1351 && first_footnote_par_is_not_empty) {
1352 firsttmppar->next->InsertChar(0, ' ');
1354 firsttmppar->PasteParagraph(bview->buffer()->params);
1357 /* now redo the paragaphs */
1358 RedoParagraphs(bview, cursor, tmppar);
1360 SetCursor(bview, cursor.par(), cursor.pos());
1362 /* sometimes it can happen, that there is a counter change */
1363 Row * row = cursor.row();
1364 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1366 UpdateCounters(bview, row);
1373 /* the DTP switches for paragraphs. LyX will store them in the
1374 * first physicla paragraph. When a paragraph is broken, the top settings
1375 * rest, the bottom settings are given to the new one. So I can make shure,
1376 * they do not duplicate themself and you cannnot make dirty things with
1379 void LyXText::SetParagraph(BufferView * bview,
1380 bool line_top, bool line_bottom,
1381 bool pagebreak_top, bool pagebreak_bottom,
1382 VSpace const & space_top,
1383 VSpace const & space_bottom,
1385 string labelwidthstring,
1388 LyXCursor tmpcursor = cursor;
1390 sel_start_cursor = cursor;
1391 sel_end_cursor = cursor;
1394 // make sure that the depth behind the selection are restored, too
1395 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1396 LyXParagraph * undoendpar = endpar;
1398 if (endpar && endpar->GetDepth()) {
1399 while (endpar && endpar->GetDepth()) {
1400 endpar = endpar->LastPhysicalPar()->Next();
1401 undoendpar = endpar;
1405 endpar = endpar->Next(); // because of parindents etc.
1408 SetUndo(bview->buffer(), Undo::EDIT,
1410 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1414 LyXParagraph * tmppar = sel_end_cursor.par();
1415 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1416 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1417 status = LyXText::NEED_MORE_REFRESH;
1418 refresh_row = cursor.row();
1419 refresh_y = cursor.y() - cursor.row()->baseline();
1420 if (cursor.par()->footnoteflag ==
1421 sel_start_cursor.par()->footnoteflag) {
1422 cursor.par()->line_top = line_top;
1423 cursor.par()->line_bottom = line_bottom;
1424 cursor.par()->pagebreak_top = pagebreak_top;
1425 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1426 cursor.par()->added_space_top = space_top;
1427 cursor.par()->added_space_bottom = space_bottom;
1428 // does the layout allow the new alignment?
1429 if (align == LYX_ALIGN_LAYOUT)
1430 align = textclasslist
1431 .Style(bview->buffer()->params.textclass,
1432 cursor.par()->GetLayout()).align;
1433 if (align & textclasslist
1434 .Style(bview->buffer()->params.textclass,
1435 cursor.par()->GetLayout()).alignpossible) {
1436 if (align == textclasslist
1437 .Style(bview->buffer()->params.textclass,
1438 cursor.par()->GetLayout()).align)
1439 cursor.par()->align = LYX_ALIGN_LAYOUT;
1441 cursor.par()->align = align;
1443 cursor.par()->SetLabelWidthString(labelwidthstring);
1444 cursor.par()->noindent = noindent;
1447 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1450 RedoParagraphs(bview, sel_start_cursor, endpar);
1453 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1454 sel_cursor = cursor;
1455 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1457 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1461 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1463 char const * widthp,
1464 int alignment, bool hfill,
1465 bool start_minipage)
1467 LyXCursor tmpcursor = cursor;
1468 LyXParagraph * tmppar;
1470 sel_start_cursor = cursor;
1471 sel_end_cursor = cursor;
1474 // make sure that the depth behind the selection are restored, too
1475 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1476 LyXParagraph * undoendpar = endpar;
1478 if (endpar && endpar->GetDepth()) {
1479 while (endpar && endpar->GetDepth()) {
1480 endpar = endpar->LastPhysicalPar()->Next();
1481 undoendpar = endpar;
1485 endpar = endpar->Next(); // because of parindents etc.
1488 SetUndo(bview->buffer(), Undo::EDIT,
1490 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1493 tmppar = sel_end_cursor.par();
1494 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1495 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1496 status = LyXText::NEED_MORE_REFRESH;
1497 refresh_row = cursor.row();
1498 refresh_y = cursor.y() - cursor.row()->baseline();
1499 if (cursor.par()->footnoteflag ==
1500 sel_start_cursor.par()->footnoteflag) {
1501 if (type == LyXParagraph::PEXTRA_NONE) {
1502 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1503 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1504 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1507 cursor.par()->SetPExtraType(bview->buffer()->params,
1508 type, width, widthp);
1509 cursor.par()->pextra_hfill = hfill;
1510 cursor.par()->pextra_start_minipage = start_minipage;
1511 cursor.par()->pextra_alignment = alignment;
1514 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1516 RedoParagraphs(bview, sel_start_cursor, endpar);
1518 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1519 sel_cursor = cursor;
1520 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1522 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1526 char loweralphaCounter(int n)
1528 if (n < 1 || n > 26)
1534 char alphaCounter(int n)
1536 if (n < 1 || n > 26)
1542 char hebrewCounter(int n)
1544 static const char hebrew[22] = {
1545 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1546 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1547 '÷', 'ø', 'ù', 'ú'
1549 if (n < 1 || n > 22)
1555 static char const * romanCounter(int n)
1557 static char const * roman[20] = {
1558 "i", "ii", "iii", "iv", "v",
1559 "vi", "vii", "viii", "ix", "x",
1560 "xi", "xii", "xiii", "xiv", "xv",
1561 "xvi", "xvii", "xviii", "xix", "xx"
1563 if (n < 1 || n > 20)
1569 // set the counter of a paragraph. This includes the labels
1570 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1572 // this is only relevant for the beginning of paragraph
1573 par = par->FirstPhysicalPar();
1575 LyXLayout const & layout =
1576 textclasslist.Style(buf->params.textclass,
1579 LyXTextClass const & textclass =
1580 textclasslist.TextClass(buf->params.textclass);
1582 /* copy the prev-counters to this one, unless this is the start of a
1583 footnote or of a bibliography or the very first paragraph */
1585 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1586 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1587 && par->footnotekind == LyXParagraph::FOOTNOTE)
1588 && !(textclasslist.Style(buf->params.textclass,
1589 par->Previous()->GetLayout()
1590 ).labeltype != LABEL_BIBLIO
1591 && layout.labeltype == LABEL_BIBLIO)) {
1592 for (int i = 0; i < 10; ++i) {
1593 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1595 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1596 if (!par->appendix && par->start_of_appendix){
1597 par->appendix = true;
1598 for (int i = 0; i < 10; ++i) {
1599 par->setCounter(i, 0);
1602 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1603 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1606 for (int i = 0; i < 10; ++i) {
1607 par->setCounter(i, 0);
1609 par->appendix = par->start_of_appendix;
1614 // if this is an open marginnote and this is the first
1615 // entry in the marginnote and the enclosing
1616 // environment is an enum/item then correct for the
1617 // LaTeX behaviour (ARRae)
1618 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1619 && par->footnotekind == LyXParagraph::MARGIN
1621 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1622 && (par->PreviousBeforeFootnote()
1623 && textclasslist.Style(buf->params.textclass,
1624 par->PreviousBeforeFootnote()->GetLayout()
1625 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1626 // Any itemize or enumerate environment in a marginnote
1627 // that is embedded in an itemize or enumerate
1628 // paragraph is seen by LaTeX as being at a deeper
1629 // level within that enclosing itemization/enumeration
1630 // even if there is a "standard" layout at the start of
1636 /* Maybe we have to increment the enumeration depth.
1637 * BUT, enumeration in a footnote is considered in isolation from its
1638 * surrounding paragraph so don't increment if this is the
1639 * first line of the footnote
1640 * AND, bibliographies can't have their depth changed ie. they
1641 * are always of depth 0
1644 && par->Previous()->GetDepth() < par->GetDepth()
1645 && textclasslist.Style(buf->params.textclass,
1646 par->Previous()->GetLayout()
1647 ).labeltype == LABEL_COUNTER_ENUMI
1648 && par->enumdepth < 3
1649 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1650 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1651 && par->footnotekind == LyXParagraph::FOOTNOTE)
1652 && layout.labeltype != LABEL_BIBLIO) {
1656 /* Maybe we have to decrement the enumeration depth, see note above */
1658 && par->Previous()->GetDepth() > par->GetDepth()
1659 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1660 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1661 && par->footnotekind == LyXParagraph::FOOTNOTE)
1662 && layout.labeltype != LABEL_BIBLIO) {
1663 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1664 par->setCounter(6 + par->enumdepth,
1665 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1666 /* reset the counters.
1667 * A depth change is like a breaking layout
1669 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1670 par->setCounter(i, 0);
1673 if (!par->labelstring.empty()) {
1674 par->labelstring.erase();
1677 if (layout.margintype == MARGIN_MANUAL) {
1678 if (par->labelwidthstring.empty()) {
1679 par->SetLabelWidthString(layout.labelstring());
1682 par->SetLabelWidthString(string());
1685 /* is it a layout that has an automatic label ? */
1686 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1688 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1689 if (i >= 0 && i<= buf->params.secnumdepth) {
1690 par->incCounter(i); // increment the counter
1692 // Is there a label? Useful for Chapter layout
1693 if (!par->appendix){
1694 if (!layout.labelstring().empty())
1695 par->labelstring = layout.labelstring();
1697 par->labelstring.erase();
1699 if (!layout.labelstring_appendix().empty())
1700 par->labelstring = layout.labelstring_appendix();
1702 par->labelstring.erase();
1706 std::ostringstream s;
1710 if (!par->appendix) {
1711 switch (2 * LABEL_FIRST_COUNTER -
1712 textclass.maxcounter() + i) {
1713 case LABEL_COUNTER_CHAPTER:
1714 s << par->getCounter(i);
1716 case LABEL_COUNTER_SECTION:
1717 s << par->getCounter(i - 1) << '.'
1718 << par->getCounter(i);
1720 case LABEL_COUNTER_SUBSECTION:
1721 s << par->getCounter(i - 2) << '.'
1722 << par->getCounter(i - 1) << '.'
1723 << par->getCounter(i);
1725 case LABEL_COUNTER_SUBSUBSECTION:
1726 s << par->getCounter(i - 3) << '.'
1727 << par->getCounter(i - 2) << '.'
1728 << par->getCounter(i - 1) << '.'
1729 << par->getCounter(i);
1732 case LABEL_COUNTER_PARAGRAPH:
1733 s << par->getCounter(i - 4) << '.'
1734 << par->getCounter(i - 3) << '.'
1735 << par->getCounter(i - 2) << '.'
1736 << par->getCounter(i - 1) << '.'
1737 << par->getCounter(i);
1739 case LABEL_COUNTER_SUBPARAGRAPH:
1740 s << par->getCounter(i - 5) << '.'
1741 << par->getCounter(i - 4) << '.'
1742 << par->getCounter(i - 3) << '.'
1743 << par->getCounter(i - 2) << '.'
1744 << par->getCounter(i - 1) << '.'
1745 << par->getCounter(i);
1749 s << par->getCounter(i) << '.';
1752 } else { // appendix
1753 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1754 case LABEL_COUNTER_CHAPTER:
1755 if (par->isRightToLeftPar(buf->params))
1756 s << hebrewCounter(par->getCounter(i));
1758 s << alphaCounter(par->getCounter(i));
1760 case LABEL_COUNTER_SECTION:
1761 if (par->isRightToLeftPar(buf->params))
1762 s << hebrewCounter(par->getCounter(i - 1));
1764 s << alphaCounter(par->getCounter(i - 1));
1767 << par->getCounter(i);
1770 case LABEL_COUNTER_SUBSECTION:
1771 if (par->isRightToLeftPar(buf->params))
1772 s << hebrewCounter(par->getCounter(i - 2));
1774 s << alphaCounter(par->getCounter(i - 2));
1777 << par->getCounter(i-1) << '.'
1778 << par->getCounter(i);
1781 case LABEL_COUNTER_SUBSUBSECTION:
1782 if (par->isRightToLeftPar(buf->params))
1783 s << hebrewCounter(par->getCounter(i-3));
1785 s << alphaCounter(par->getCounter(i-3));
1788 << par->getCounter(i-2) << '.'
1789 << par->getCounter(i-1) << '.'
1790 << par->getCounter(i);
1793 case LABEL_COUNTER_PARAGRAPH:
1794 if (par->isRightToLeftPar(buf->params))
1795 s << hebrewCounter(par->getCounter(i-4));
1797 s << alphaCounter(par->getCounter(i-4));
1800 << par->getCounter(i-3) << '.'
1801 << par->getCounter(i-2) << '.'
1802 << par->getCounter(i-1) << '.'
1803 << par->getCounter(i);
1806 case LABEL_COUNTER_SUBPARAGRAPH:
1807 if (par->isRightToLeftPar(buf->params))
1808 s << hebrewCounter(par->getCounter(i-5));
1810 s << alphaCounter(par->getCounter(i-5));
1813 << par->getCounter(i-4) << '.'
1814 << par->getCounter(i-3) << '.'
1815 << par->getCounter(i-2) << '.'
1816 << par->getCounter(i-1) << '.'
1817 << par->getCounter(i);
1821 // Can this ever be reached? And in the
1822 // case it is, how can this be correct?
1824 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1830 par->labelstring += s.str().c_str();
1831 // We really want to remove the c_str as soon as
1835 char * tmps = s.str();
1836 par->labelstring += tmps;
1840 for (i++; i < 10; ++i) {
1841 // reset the following counters
1842 par->setCounter(i, 0);
1844 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1845 for (i++; i < 10; ++i) {
1846 // reset the following counters
1847 par->setCounter(i, 0);
1849 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1850 par->incCounter(i + par->enumdepth);
1851 int number = par->getCounter(i + par->enumdepth);
1854 std::ostringstream s;
1858 switch (par->enumdepth) {
1860 if (par->isRightToLeftPar(buf->params))
1862 << hebrewCounter(number)
1866 << loweralphaCounter(number)
1870 if (par->isRightToLeftPar(buf->params))
1871 s << '.' << romanCounter(number);
1873 s << romanCounter(number) << '.';
1876 if (par->isRightToLeftPar(buf->params))
1878 << alphaCounter(number);
1880 s << alphaCounter(number)
1884 if (par->isRightToLeftPar(buf->params))
1891 par->labelstring = s.str().c_str();
1892 // we really want to get rid of that c_str()
1895 char * tmps = s.str();
1896 par->labelstring = tmps;
1900 for (i += par->enumdepth + 1; i < 10; ++i)
1901 par->setCounter(i, 0); /* reset the following counters */
1904 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1905 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1907 int number = par->getCounter(i);
1909 par->bibkey = new InsetBibKey();
1910 par->bibkey->setCounter(number);
1911 par->labelstring = layout.labelstring();
1913 // In biblio should't be following counters but...
1915 string s = layout.labelstring();
1917 // the caption hack:
1919 if (layout.labeltype == LABEL_SENSITIVE) {
1920 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1921 && (par->footnotekind == LyXParagraph::FIG
1922 || par->footnotekind == LyXParagraph::WIDE_FIG))
1923 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1924 ? ":øåéà " : "Figure:";
1925 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1926 && (par->footnotekind == LyXParagraph::TAB
1927 || par->footnotekind == LyXParagraph::WIDE_TAB))
1928 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1929 ? ":äìáè" : "Table:";
1930 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1931 && par->footnotekind == LyXParagraph::ALGORITHM)
1932 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1933 ? ":Ãúéøåâìà " : "Algorithm:";
1935 /* par->SetLayout(0);
1936 s = layout->labelstring; */
1937 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1938 ? " :úåòîùî øñç" : "Senseless: ";
1941 par->labelstring = s;
1943 /* reset the enumeration counter. They are always resetted
1944 * when there is any other layout between */
1945 for (int i = 6 + par->enumdepth; i < 10; ++i)
1946 par->setCounter(i, 0);
1951 /* Updates all counters BEHIND the row. Changed paragraphs
1952 * with a dynamic left margin will be rebroken. */
1953 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1961 if (row->par()->next
1962 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1963 par = row->par()->LastPhysicalPar()->Next();
1965 par = row->par()->next;
1970 while (row->par() != par)
1973 SetCounter(bview->buffer(), par);
1975 /* now check for the headline layouts. remember that they
1976 * have a dynamic left margin */
1978 && ( textclasslist.Style(bview->buffer()->params.textclass,
1979 par->layout).margintype == MARGIN_DYNAMIC
1980 || textclasslist.Style(bview->buffer()->params.textclass,
1981 par->layout).labeltype == LABEL_SENSITIVE)
1984 /* Rebreak the paragraph */
1985 RemoveParagraph(row);
1986 AppendParagraph(bview, row);
1988 /* think about the damned open footnotes! */
1989 while (par->Next() &&
1990 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1991 || par->Next()->IsDummy())){
1993 if (par->IsDummy()) {
1994 while (row->par() != par)
1996 RemoveParagraph(row);
1997 AppendParagraph(bview, row);
2002 par = par->LastPhysicalPar()->Next();
2008 /* insets an inset. */
2009 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2011 if (!cursor.par()->InsertInsetAllowed(inset))
2013 SetUndo(bview->buffer(), Undo::INSERT,
2014 cursor.par()->ParFromPos(cursor.pos())->previous,
2015 cursor.par()->ParFromPos(cursor.pos())->next);
2016 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2017 cursor.par()->InsertInset(cursor.pos(), inset);
2018 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2019 * The character will not be inserted a
2024 void LyXText::copyEnvironmentType()
2026 copylayouttype = cursor.par()->GetLayout();
2030 void LyXText::pasteEnvironmentType(BufferView * bview)
2032 SetLayout(bview, copylayouttype);
2036 void LyXText::CutSelection(BufferView * bview, bool doclear)
2038 // Stuff what we got on the clipboard. Even if there is no selection.
2040 // There is a problem with having the stuffing here in that the
2041 // larger the selection the slower LyX will get. This can be
2042 // solved by running the line below only when the selection has
2043 // finished. The solution used currently just works, to make it
2044 // faster we need to be more clever and probably also have more
2045 // calls to stuffClipboard. (Lgb)
2046 bview->stuffClipboard(selectionAsString(bview->buffer()));
2048 // This doesn't make sense, if there is no selection
2052 // OK, we have a selection. This is always between sel_start_cursor
2053 // and sel_end cursor
2054 LyXParagraph * tmppar;
2056 // Check whether there are half footnotes in the selection
2057 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2058 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2059 tmppar = sel_start_cursor.par();
2060 while (tmppar != sel_end_cursor.par()){
2061 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2062 WriteAlert(_("Impossible operation"),
2063 _("Don't know what to do with half floats."),
2067 tmppar = tmppar->Next();
2072 /* table stuff -- begin */
2073 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2074 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2075 WriteAlert(_("Impossible operation"),
2076 _("Don't know what to do with half tables."),
2080 sel_start_cursor.par()->table->Reinit();
2082 /* table stuff -- end */
2084 // make sure that the depth behind the selection are restored, too
2085 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2086 LyXParagraph * undoendpar = endpar;
2088 if (endpar && endpar->GetDepth()) {
2089 while (endpar && endpar->GetDepth()) {
2090 endpar = endpar->LastPhysicalPar()->Next();
2091 undoendpar = endpar;
2093 } else if (endpar) {
2094 endpar = endpar->Next(); // because of parindents etc.
2097 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2098 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2102 // there are two cases: cut only within one paragraph or
2103 // more than one paragraph
2104 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2105 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2106 // only within one paragraph
2107 endpar = sel_start_cursor.par();
2108 int pos = sel_end_cursor.pos();
2109 cap.cutSelection(sel_start_cursor.par(), &endpar,
2110 sel_start_cursor.pos(), pos,
2111 bview->buffer()->params.textclass, doclear);
2112 sel_end_cursor.pos(pos);
2114 endpar = sel_end_cursor.par();
2116 int pos = sel_end_cursor.pos();
2117 cap.cutSelection(sel_start_cursor.par(), &endpar,
2118 sel_start_cursor.pos(), pos,
2119 bview->buffer()->params.textclass, doclear);
2121 sel_end_cursor.par(endpar);
2122 sel_end_cursor.pos(pos);
2123 cursor.pos(sel_end_cursor.pos());
2125 endpar = endpar->Next();
2127 // sometimes necessary
2129 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2131 RedoParagraphs(bview, sel_start_cursor, endpar);
2134 cursor = sel_start_cursor;
2135 SetCursor(bview, cursor.par(), cursor.pos());
2136 sel_cursor = cursor;
2137 UpdateCounters(bview, cursor.row());
2141 void LyXText::CopySelection(BufferView * bview)
2143 // Stuff what we got on the clipboard. Even if there is no selection.
2145 // There is a problem with having the stuffing here in that the
2146 // larger the selection the slower LyX will get. This can be
2147 // solved by running the line below only when the selection has
2148 // finished. The solution used currently just works, to make it
2149 // faster we need to be more clever and probably also have more
2150 // calls to stuffClipboard. (Lgb)
2151 bview->stuffClipboard(selectionAsString(bview->buffer()));
2153 // this doesnt make sense, if there is no selection
2157 // ok we have a selection. This is always between sel_start_cursor
2158 // and sel_end cursor
2159 LyXParagraph * tmppar;
2161 /* check wether there are half footnotes in the selection */
2162 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2163 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2164 tmppar = sel_start_cursor.par();
2165 while (tmppar != sel_end_cursor.par()) {
2166 if (tmppar->footnoteflag !=
2167 sel_end_cursor.par()->footnoteflag) {
2168 WriteAlert(_("Impossible operation"),
2169 _("Don't know what to do"
2170 " with half floats."),
2174 tmppar = tmppar->Next();
2179 /* table stuff -- begin */
2180 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2181 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2182 WriteAlert(_("Impossible operation"),
2183 _("Don't know what to do with half tables."),
2188 /* table stuff -- end */
2191 // copy behind a space if there is one
2192 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2193 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2194 && (sel_start_cursor.par() != sel_end_cursor.par()
2195 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2196 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2200 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2201 sel_start_cursor.pos(), sel_end_cursor.pos(),
2202 bview->buffer()->params.textclass);
2206 void LyXText::PasteSelection(BufferView * bview)
2210 // this does not make sense, if there is nothing to paste
2211 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2214 SetUndo(bview->buffer(), Undo::INSERT,
2215 cursor.par()->ParFromPos(cursor.pos())->previous,
2216 cursor.par()->ParFromPos(cursor.pos())->next);
2218 LyXParagraph * endpar;
2219 LyXParagraph * actpar = cursor.par();
2221 int pos = cursor.pos();
2222 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2224 RedoParagraphs(bview, cursor, endpar);
2226 SetCursor(bview, cursor.par(), cursor.pos());
2229 sel_cursor = cursor;
2230 SetCursor(bview, actpar, pos);
2232 UpdateCounters(bview, cursor.row());
2236 // returns a pointer to the very first LyXParagraph
2237 LyXParagraph * LyXText::FirstParagraph() const
2239 return OwnerParagraph();
2243 // returns true if the specified string is at the specified position
2244 bool LyXText::IsStringInText(LyXParagraph * par,
2245 LyXParagraph::size_type pos,
2246 char const * str) const
2250 while (pos + i < par->Last() && str[i] &&
2251 str[i] == par->GetChar(pos + i)) {
2261 // sets the selection over the number of characters of string, no check!!
2262 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2264 sel_cursor = cursor;
2265 for (int i = 0; string[i]; ++i)
2271 // simple replacing. The font of the first selected character is used
2272 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2274 SetCursorParUndo(bview->buffer());
2277 if (!selection) { // create a dummy selection
2278 sel_end_cursor = cursor;
2279 sel_start_cursor = cursor;
2282 // Get font setting before we cut
2283 LyXParagraph::size_type pos = sel_end_cursor.pos();
2284 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2285 sel_start_cursor.pos());
2287 // Insert the new string
2288 for (int i = 0; str[i]; ++i) {
2289 sel_end_cursor.par()->InsertChar(pos, str[i]);
2290 sel_end_cursor.par()->SetFont(pos, font);
2294 // Cut the selection
2295 CutSelection(bview);
2301 // if the string can be found: return true and set the cursor to
2303 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2305 LyXParagraph * par = cursor.par();
2306 LyXParagraph::size_type pos = cursor.pos();
2307 while (par && !IsStringInText(par, pos, str)) {
2308 if (pos < par->Last() - 1)
2316 SetCursor(bview, par, pos);
2324 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2326 LyXParagraph * par = cursor.par();
2327 int pos = cursor.pos();
2333 // We skip empty paragraphs (Asger)
2335 par = par->Previous();
2337 pos = par->Last() - 1;
2338 } while (par && pos < 0);
2340 } while (par && !IsStringInText(par, pos, string));
2343 SetCursor(bview, par, pos);
2350 // needed to insert the selection
2351 void LyXText::InsertStringA(BufferView * bview, string const & str)
2353 LyXParagraph * par = cursor.par();
2354 LyXParagraph::size_type pos = cursor.pos();
2355 LyXParagraph::size_type a = 0;
2357 LyXParagraph * endpar = cursor.par()->Next();
2359 SetCursorParUndo(bview->buffer());
2362 textclasslist.Style(bview->buffer()->params.textclass,
2363 cursor.par()->GetLayout()).isEnvironment();
2364 // only to be sure, should not be neccessary
2367 // insert the string, don't insert doublespace
2368 string::size_type i = 0;
2369 while (i < str.length()) {
2370 if (str[i] != '\n') {
2372 && i + 1 < str.length() && str[i + 1] != ' '
2373 && pos && par->GetChar(pos - 1)!= ' ') {
2374 par->InsertChar(pos,' ');
2375 par->SetFont(pos, current_font);
2378 } else if (par->table) {
2379 if (str[i] == '\t') {
2380 while((pos < par->size()) &&
2381 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2383 if (pos < par->size())
2385 else // no more fields to fill skip the rest
2387 } else if ((str[i] != 13) &&
2388 ((str[i] & 127) >= ' ')) {
2389 par->InsertChar(pos, str[i]);
2390 par->SetFont(pos, current_font);
2394 } else if (str[i] == ' ') {
2395 InsetSpecialChar * new_inset =
2396 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2397 if (par->InsertInsetAllowed(new_inset)) {
2398 par->InsertChar(pos, LyXParagraph::META_INSET);
2399 par->SetFont(pos, current_font);
2400 par->InsertInset(pos, new_inset);
2405 } else if (str[i] == '\t') {
2406 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2407 InsetSpecialChar * new_inset =
2408 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2409 if (par->InsertInsetAllowed(new_inset)) {
2410 par->InsertChar(pos, LyXParagraph::META_INSET);
2411 par->SetFont(pos, current_font);
2412 par->InsertInset(pos, new_inset);
2418 } else if (str[i] != 13 &&
2419 // Ignore unprintables
2420 (str[i] & 127) >= ' ') {
2421 par->InsertChar(pos, str[i]);
2422 par->SetFont(pos, current_font);
2428 if ((i + 1) >= str.length()) {
2429 if (pos < par->size())
2433 while((pos < par->size()) &&
2434 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2437 cell = NumberOfCell(par, pos);
2438 while((pos < par->size()) &&
2439 !(par->table->IsFirstCell(cell))) {
2441 while((pos < par->size()) &&
2442 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2445 cell = NumberOfCell(par, pos);
2447 if (pos >= par->size())
2448 // no more fields to fill skip the rest
2452 if (!par->size()) { // par is empty
2453 InsetSpecialChar * new_inset =
2454 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2455 if (par->InsertInsetAllowed(new_inset)) {
2456 par->InsertChar(pos, LyXParagraph::META_INSET);
2457 par->SetFont(pos, current_font);
2458 par->InsertInset(pos, new_inset);
2464 par->BreakParagraph(bview->buffer()->params, pos, flag);
2474 RedoParagraphs(bview, cursor, endpar);
2475 SetCursor(bview, cursor.par(), cursor.pos());
2476 sel_cursor = cursor;
2477 SetCursor(bview, par, pos);
2482 /* turns double-CR to single CR, others where converted into one blank and 13s
2483 * that are ignored .Double spaces are also converted into one. Spaces at
2484 * the beginning of a paragraph are forbidden. tabs are converted into one
2485 * space. then InsertStringA is called */
2486 void LyXText::InsertStringB(BufferView * bview, string const & s)
2489 LyXParagraph * par = cursor.par();
2490 string::size_type i = 1;
2491 while (i < str.length()) {
2492 if (str[i] == '\t' && !par->table)
2494 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2496 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2497 if (str[i + 1] != '\n') {
2498 if (str[i - 1] != ' ')
2503 while (i + 1 < str.length()
2504 && (str[i + 1] == ' '
2505 || str[i + 1] == '\t'
2506 || str[i + 1] == '\n'
2507 || str[i + 1] == 13)) {
2514 InsertStringA(bview, str);
2518 bool LyXText::GotoNextError(BufferView * bview) const
2520 LyXCursor res = cursor;
2522 if (res.pos() < res.par()->Last() - 1) {
2523 res.pos(res.pos() + 1);
2525 res.par(res.par()->Next());
2529 } while (res.par() &&
2530 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2531 && res.par()->GetInset(res.pos())->AutoDelete()));
2534 SetCursor(bview, res.par(), res.pos());
2541 bool LyXText::GotoNextNote(BufferView * bview) const
2543 LyXCursor res = cursor;
2545 if (res.pos() < res.par()->Last() - 1) {
2546 res.pos(res.pos() + 1);
2548 res.par(res.par()->Next());
2552 } while (res.par() &&
2553 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2554 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2557 SetCursor(bview, res.par(), res.pos());
2564 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2565 LyXParagraph::size_type pos)
2567 LyXCursor tmpcursor;
2570 /* table stuff -- begin*/
2573 CheckParagraphInTable(bview, par, pos);
2577 /* table stuff -- end*/
2580 LyXParagraph::size_type z;
2581 Row * row = GetRow(par, pos, y);
2583 // is there a break one row above
2584 if (row->previous() && row->previous()->par() == row->par()) {
2585 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2586 if ( z >= row->pos()) {
2587 // set the dimensions of the row above
2588 y -= row->previous()->height();
2590 refresh_row = row->previous();
2591 status = LyXText::NEED_MORE_REFRESH;
2593 BreakAgain(bview, row->previous());
2595 // set the cursor again. Otherwise
2596 // dangling pointers are possible
2597 SetCursor(bview, cursor.par(), cursor.pos());
2598 sel_cursor = cursor;
2603 int tmpheight = row->height();
2604 LyXParagraph::size_type tmplast = RowLast(row);
2608 BreakAgain(bview, row);
2609 if (row->height() == tmpheight && RowLast(row) == tmplast)
2610 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2612 status = LyXText::NEED_MORE_REFRESH;
2614 // check the special right address boxes
2615 if (textclasslist.Style(bview->buffer()->params.textclass,
2616 par->GetLayout()).margintype
2617 == MARGIN_RIGHT_ADDRESS_BOX) {
2624 RedoDrawingOfParagraph(bview, tmpcursor);
2630 // set the cursor again. Otherwise dangling pointers are possible
2631 // also set the selection
2635 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2636 sel_cursor = cursor;
2637 SetCursorIntern(bview, sel_start_cursor.par(),
2638 sel_start_cursor.pos());
2639 sel_start_cursor = cursor;
2640 SetCursorIntern(bview, sel_end_cursor.par(),
2641 sel_end_cursor.pos());
2642 sel_end_cursor = cursor;
2643 SetCursorIntern(bview, last_sel_cursor.par(),
2644 last_sel_cursor.pos());
2645 last_sel_cursor = cursor;
2648 SetCursorIntern(bview, cursor.par(), cursor.pos());
2652 // returns 0 if inset wasn't found
2653 int LyXText::UpdateInset(BufferView * bview, Inset * inset)
2655 // first check the current paragraph
2656 int pos = cursor.par()->GetPositionOfInset(inset);
2658 CheckParagraph(bview, cursor.par(), pos);
2662 // check every paragraph
2664 LyXParagraph * par = FirstParagraph();
2666 // make sure the paragraph is open
2667 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2668 pos = par->GetPositionOfInset(inset);
2670 CheckParagraph(bview, par, pos);
2681 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2682 LyXParagraph::size_type pos,
2683 bool setfont, bool boundary) const
2685 LyXCursor old_cursor = cursor;
2686 SetCursorIntern(bview, par, pos, setfont, boundary);
2687 DeleteEmptyParagraphMechanism(bview, old_cursor);
2691 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2692 LyXParagraph::size_type pos, bool boundary) const
2694 // correct the cursor position if impossible
2695 if (pos > par->Last()){
2696 LyXParagraph * tmppar = par->ParFromPos(pos);
2697 pos = par->PositionInParFromPos(pos);
2700 if (par->IsDummy() && par->previous &&
2701 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2702 while (par->previous &&
2703 ((par->previous->IsDummy() &&
2704 (par->previous->previous->footnoteflag ==
2705 LyXParagraph::CLOSED_FOOTNOTE)) ||
2706 (par->previous->footnoteflag ==
2707 LyXParagraph::CLOSED_FOOTNOTE))) {
2708 par = par->previous ;
2709 if (par->IsDummy() &&
2710 (par->previous->footnoteflag ==
2711 LyXParagraph::CLOSED_FOOTNOTE))
2712 pos += par->size() + 1;
2714 if (par->previous) {
2715 par = par->previous;
2717 pos += par->size() + 1;
2722 cur.boundary(boundary);
2724 /* get the cursor y position in text */
2726 Row * row = GetRow(par, pos, y);
2727 /* y is now the beginning of the cursor row */
2728 y += row->baseline();
2729 /* y is now the cursor baseline */
2732 /* now get the cursors x position */
2734 float fill_separator, fill_hfill, fill_label_hfill;
2735 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2737 LyXParagraph::size_type cursor_vpos = 0;
2738 LyXParagraph::size_type last = RowLastPrintable(row);
2740 if (pos > last + 1) // This shouldn't happen.
2742 else if (pos < row->pos())
2745 if (last < row->pos())
2746 cursor_vpos = row->pos();
2747 else if (pos > last && !boundary)
2748 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2749 ? row->pos() : last + 1;
2750 else if (pos > row->pos() &&
2751 (pos > last || boundary ||
2752 (row->par()->table && row->par()->IsNewline(pos))))
2753 /// Place cursor after char at (logical) position pos - 1
2754 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2755 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2757 /// Place cursor before char at (logical) position pos
2758 cursor_vpos = (bidi_level(pos) % 2 == 0)
2759 ? log2vis(pos) : log2vis(pos) + 1;
2762 /* table stuff -- begin*/
2763 if (row->par()->table) {
2764 int cell = NumberOfCell(row->par(), row->pos());
2766 x += row->par()->table->GetBeginningOfTextInCell(cell);
2767 for (LyXParagraph::size_type vpos = row->pos();
2768 vpos < cursor_vpos; ++vpos) {
2769 pos = vis2log(vpos);
2770 if (row->par()->IsNewline(pos)) {
2771 x = x_old + row->par()->table->WidthOfColumn(cell);
2774 x += row->par()->table->GetBeginningOfTextInCell(cell);
2776 x += SingleWidth(bview, row->par(), pos);
2780 /* table stuff -- end*/
2782 LyXParagraph::size_type main_body =
2783 BeginningOfMainBody(bview->buffer(), row->par());
2784 if ((main_body > 0) &&
2785 ((main_body-1 > last) ||
2786 !row->par()->IsLineSeparator(main_body-1)))
2789 for (LyXParagraph::size_type vpos = row->pos();
2790 vpos < cursor_vpos; ++vpos) {
2791 pos = vis2log(vpos);
2792 if (main_body > 0 && pos == main_body-1) {
2793 x += fill_label_hfill +
2794 lyxfont::width(textclasslist.Style(
2795 bview->buffer()->params.textclass,
2796 row->par()->GetLayout())
2798 GetFont(bview->buffer(), row->par(), -2));
2799 if (row->par()->IsLineSeparator(main_body-1))
2800 x -= SingleWidth(bview, row->par(),main_body-1);
2802 if (HfillExpansion(bview->buffer(), row, pos)) {
2803 x += SingleWidth(bview, row->par(), pos);
2804 if (pos >= main_body)
2807 x += fill_label_hfill;
2808 } else if (row->par()->IsSeparator(pos)) {
2809 x += SingleWidth(bview, row->par(), pos);
2810 if (pos >= main_body)
2811 x += fill_separator;
2813 x += SingleWidth(bview, row->par(), pos);
2825 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2826 LyXParagraph::size_type pos,
2827 bool setfont, bool boundary) const
2829 SetCursor(bview, cursor, par, pos, boundary);
2830 // #warning Remove this when verified working (Jug 20000413)
2832 // correct the cursor position if impossible
2833 if (pos > par->Last()){
2834 LyXParagraph * tmppar = par->ParFromPos(pos);
2835 pos = par->PositionInParFromPos(pos);
2838 if (par->IsDummy() && par->previous &&
2839 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2840 while (par->previous &&
2841 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2842 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2843 par = par->previous ;
2844 if (par->IsDummy() &&
2845 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2846 pos += par->size() + 1;
2848 if (par->previous) {
2849 par = par->previous;
2851 pos += par->size() + 1;
2857 /* get the cursor y position in text */
2859 Row * row = GetRow(par, pos, y);
2860 /* y is now the beginning of the cursor row */
2861 y += row->baseline();
2862 /* y is now the cursor baseline */
2865 /* now get the cursors x position */
2867 float fill_separator, fill_hfill, fill_label_hfill;
2868 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2869 LyXParagraph::size_type cursor_vpos;
2870 LyXParagraph::size_type last = RowLastPrintable(row);
2872 if (pos > last + 1) // This shouldn't happen.
2875 if (last < row->pos())
2877 else if (pos > last ||
2878 (pos - 1 >= row->pos() &&
2879 (row->par()->IsSeparator(pos) ||
2880 (row->par()->table && row->par()->IsNewline(pos))
2882 /// Place cursor after char at (logical) position pos-1
2883 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2884 ? log2vis(pos-1) + 1 : log2vis(pos-1);
2886 /// Place cursor before char at (logical) position pos
2887 cursor_vpos = (bidi_level(pos) % 2 == 0)
2888 ? log2vis(pos) : log2vis(pos) + 1;
2891 /* table stuff -- begin*/
2892 if (row->par()->table) {
2893 int cell = NumberOfCell(row->par(), row->pos());
2895 x += row->par()->table->GetBeginningOfTextInCell(cell);
2896 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2897 pos = vis2log(vpos);
2898 if (row->par()->IsNewline(pos)) {
2899 x = x_old + row->par()->table->WidthOfColumn(cell);
2902 x += row->par()->table->GetBeginningOfTextInCell(cell);
2904 x += SingleWidth(row->par(), pos);
2908 /* table stuff -- end*/
2910 LyXParagraph::size_type main_body =
2911 BeginningOfMainBody(row->par());
2912 if (main_body > 0 &&
2913 (main_body-1 > last ||
2914 !row->par()->IsLineSeparator(main_body-1)))
2917 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2918 pos = vis2log(vpos);
2919 if (main_body > 0 && pos == main_body-1) {
2920 x += fill_label_hfill +
2921 lyxfont::width(textclasslist
2922 .Style(bview->buffer()->params.textclass,
2923 row->par()->GetLayout())
2925 GetFont(row->par(), -2));
2926 if (row->par()->IsLineSeparator(main_body-1))
2927 x -= SingleWidth(row->par(), main_body-1);
2929 if (HfillExpansion(row, pos)) {
2930 x += SingleWidth(row->par(), pos);
2931 if (pos >= main_body)
2934 x += fill_label_hfill;
2936 else if (row->par()->IsSeparator(pos)) {
2937 x += SingleWidth(row->par(), pos);
2938 if (pos >= main_body)
2939 x += fill_separator;
2941 x += SingleWidth(row->par(), pos);
2948 cursor.x_fix = cursor.x;
2952 SetCurrentFont(bview);
2955 void LyXText::SetCurrentFont(BufferView * bview) const
2957 LyXParagraph::size_type pos = cursor.pos();
2958 if (cursor.boundary() && pos > 0)
2962 if (pos == cursor.par()->Last() ||
2963 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2965 else if (cursor.par()->IsSeparator(pos)) {
2966 if (pos > cursor.row()->pos() &&
2967 bidi_level(pos) % 2 ==
2968 bidi_level(pos - 1) % 2)
2970 else if (pos + 1 < cursor.par()->Last())
2975 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2976 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2980 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2982 LyXCursor old_cursor = cursor;
2984 /* get the row first */
2986 Row * row = GetRowNearY(y);
2987 cursor.par(row->par());
2990 int column = GetColumnNearX(bview, row, x, bound);
2991 cursor.pos(row->pos() + column);
2993 cursor.y(y + row->baseline());
2995 cursor.boundary(bound);
2996 SetCurrentFont(bview);
2997 DeleteEmptyParagraphMechanism(bview, old_cursor);
3001 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3002 int x, long y) const
3004 /* get the row first */
3006 Row * row = GetRowNearY(y);
3008 int column = GetColumnNearX(bview, row, x, bound);
3010 cur.par(row->par());
3011 cur.pos(row->pos() + column);
3013 cur.y(y + row->baseline());
3015 cur.boundary(bound);
3019 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3021 CursorLeftIntern(bview, internal);
3023 if (cursor.par()->table) {
3024 int cell = NumberOfCell(cursor.par(), cursor.pos());
3025 if (cursor.par()->table->IsContRow(cell)
3026 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3034 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3036 if (cursor.pos() > 0) {
3037 bool boundary = cursor.boundary();
3038 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3039 if (!internal && !boundary &&
3040 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3041 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3042 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3043 LyXParagraph * par = cursor.par()->Previous();
3044 LyXParagraph::size_type pos = par->Last();
3045 SetCursor(bview, par, pos);
3046 if (IsBoundary(bview->buffer(), par, pos))
3047 SetCursor(bview, par, pos, false, true);
3052 void LyXText::CursorRight(BufferView * bview, bool internal) const
3054 CursorRightIntern(bview, internal);
3056 if (cursor.par()->table) {
3057 int cell = NumberOfCell(cursor.par(), cursor.pos());
3058 if (cursor.par()->table->IsContRow(cell) &&
3059 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3067 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3069 if (cursor.pos() < cursor.par()->Last()) {
3070 if (!internal && cursor.boundary() &&
3071 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3072 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3074 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3075 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3076 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3078 } else if (cursor.par()->Next())
3079 SetCursor(bview, cursor.par()->Next(), 0);
3083 void LyXText::CursorUp(BufferView * bview) const
3085 SetCursorFromCoordinates(bview, cursor.x_fix(),
3086 cursor.y() - cursor.row()->baseline() - 1);
3088 if (cursor.par()->table) {
3089 int cell = NumberOfCell(cursor.par(), cursor.pos());
3090 if (cursor.par()->table->IsContRow(cell) &&
3091 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3099 void LyXText::CursorDown(BufferView * bview) const
3102 if (cursor.par()->table &&
3103 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3104 !cursor.par()->next)
3108 SetCursorFromCoordinates(bview, cursor.x_fix(),
3109 cursor.y() - cursor.row()->baseline()
3110 + cursor.row()->height() + 1);
3112 if (cursor.par()->table) {
3113 int cell = NumberOfCell(cursor.par(), cursor.pos());
3114 int cell_above = cursor.par()->table->GetCellAbove(cell);
3115 while(cursor.par()->table &&
3116 cursor.par()->table->IsContRow(cell) &&
3117 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3118 SetCursorFromCoordinates(bview, cursor.x_fix(),
3119 cursor.y() - cursor.row()->baseline()
3120 + cursor.row()->height() + 1);
3121 if (cursor.par()->table) {
3122 cell = NumberOfCell(cursor.par(), cursor.pos());
3123 cell_above = cursor.par()->table->GetCellAbove(cell);
3131 void LyXText::CursorUpParagraph(BufferView * bview) const
3133 if (cursor.pos() > 0) {
3134 SetCursor(bview, cursor.par(), 0);
3136 else if (cursor.par()->Previous()) {
3137 SetCursor(bview, cursor.par()->Previous(), 0);
3142 void LyXText::CursorDownParagraph(BufferView * bview) const
3144 if (cursor.par()->Next()) {
3145 SetCursor(bview, cursor.par()->Next(), 0);
3147 SetCursor(bview, cursor.par(), cursor.par()->Last());
3152 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3153 LyXCursor const & old_cursor) const
3155 // Would be wrong to delete anything if we have a selection.
3156 if (selection) return;
3158 // We allow all kinds of "mumbo-jumbo" when freespacing.
3159 if (textclasslist.Style(bview->buffer()->params.textclass,
3160 old_cursor.par()->GetLayout()).free_spacing)
3163 bool deleted = false;
3165 /* Ok I'll put some comments here about what is missing.
3166 I have fixed BackSpace (and thus Delete) to not delete
3167 double-spaces automagically. I have also changed Cut,
3168 Copy and Paste to hopefully do some sensible things.
3169 There are still some small problems that can lead to
3170 double spaces stored in the document file or space at
3171 the beginning of paragraphs. This happens if you have
3172 the cursor betwenn to spaces and then save. Or if you
3173 cut and paste and the selection have a space at the
3174 beginning and then save right after the paste. I am
3175 sure none of these are very hard to fix, but I will
3176 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3177 that I can get some feedback. (Lgb)
3180 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3181 // delete the LineSeparator.
3184 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3185 // delete the LineSeparator.
3188 // If the pos around the old_cursor were spaces, delete one of them.
3189 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3190 // Only if the cursor has really moved
3192 if (old_cursor.pos() > 0
3193 && old_cursor.pos() < old_cursor.par()->Last()
3194 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3195 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3196 old_cursor.par()->Erase(old_cursor.pos() - 1);
3197 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3199 if (old_cursor.par() == cursor.par() &&
3200 cursor.pos() > old_cursor.pos()) {
3201 SetCursorIntern(bview, cursor.par(),
3204 SetCursorIntern(bview, cursor.par(),
3210 // Do not delete empty paragraphs with keepempty set.
3211 if ((textclasslist.Style(bview->buffer()->params.textclass,
3212 old_cursor.par()->GetLayout())).keepempty)
3215 LyXCursor tmpcursor;
3217 if (old_cursor.par() != cursor.par()) {
3218 if ( (old_cursor.par()->Last() == 0
3219 || (old_cursor.par()->Last() == 1
3220 && old_cursor.par()->IsLineSeparator(0)))
3221 && old_cursor.par()->FirstPhysicalPar()
3222 == old_cursor.par()->LastPhysicalPar()) {
3223 // ok, we will delete anything
3225 // make sure that you do not delete any environments
3226 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3227 !(old_cursor.row()->previous()
3228 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3229 && !(old_cursor.row()->next()
3230 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3231 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3232 && ((old_cursor.row()->previous()
3233 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3234 || (old_cursor.row()->next()
3235 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3237 status = LyXText::NEED_MORE_REFRESH;
3240 if (old_cursor.row()->previous()) {
3241 refresh_row = old_cursor.row()->previous();
3242 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3244 cursor = old_cursor; // that undo can restore the right cursor position
3245 LyXParagraph * endpar = old_cursor.par()->next;
3246 if (endpar && endpar->GetDepth()) {
3247 while (endpar && endpar->GetDepth()) {
3248 endpar = endpar->LastPhysicalPar()->Next();
3251 SetUndo(bview->buffer(), Undo::DELETE,
3252 old_cursor.par()->previous,
3257 RemoveRow(old_cursor.row());
3258 if (OwnerParagraph() == old_cursor.par()) {
3259 OwnerParagraph(OwnerParagraph()->next);
3262 delete old_cursor.par();
3264 /* Breakagain the next par. Needed
3265 * because of the parindent that
3266 * can occur or dissappear. The
3267 * next row can change its height,
3268 * if there is another layout before */
3269 if (refresh_row->next()) {
3270 BreakAgain(bview, refresh_row->next());
3271 UpdateCounters(bview, refresh_row);
3273 SetHeightOfRow(bview, refresh_row);
3275 refresh_row = old_cursor.row()->next();
3276 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3279 cursor = old_cursor; // that undo can restore the right cursor position
3280 LyXParagraph * endpar = old_cursor.par()->next;
3281 if (endpar && endpar->GetDepth()) {
3282 while (endpar && endpar->GetDepth()) {
3283 endpar = endpar->LastPhysicalPar()->Next();
3286 SetUndo(bview->buffer(), Undo::DELETE,
3287 old_cursor.par()->previous,
3292 RemoveRow(old_cursor.row());
3294 if (OwnerParagraph() == old_cursor.par()) {
3295 OwnerParagraph(OwnerParagraph()->next);
3297 delete old_cursor.par();
3299 /* Breakagain the next par. Needed
3300 because of the parindent that can
3301 occur or dissappear.
3302 The next row can change its height,
3303 if there is another layout before
3306 BreakAgain(bview, refresh_row);
3307 UpdateCounters(bview, refresh_row->previous());
3313 SetCursorIntern(bview, cursor.par(), cursor.pos());
3315 if (sel_cursor.par() == old_cursor.par()
3316 && sel_cursor.pos() == sel_cursor.pos()) {
3317 // correct selection
3318 sel_cursor = cursor;
3323 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3324 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3326 SetCursorIntern(bview, cursor.par(), cursor.pos());
3327 sel_cursor = cursor;
3334 LyXParagraph * LyXText::GetParFromID(int id)
3336 LyXParagraph * result = FirstParagraph();
3337 while (result && result->id() != id)
3338 result = result->next;
3344 bool LyXText::TextUndo(BufferView * bview)
3348 // returns false if no undo possible
3349 Undo * undo = bview->buffer()->undostack.pop();
3353 bview->buffer()->redostack
3354 .push(CreateUndo(bview->buffer(), undo->kind,
3355 GetParFromID(undo->number_of_before_par),
3356 GetParFromID(undo->number_of_behind_par)));
3358 return TextHandleUndo(bview, undo);
3362 bool LyXText::TextRedo(BufferView * bview)
3366 // returns false if no redo possible
3367 Undo * undo = bview->buffer()->redostack.pop();
3371 bview->buffer()->undostack
3372 .push(CreateUndo(bview->buffer(), undo->kind,
3373 GetParFromID(undo->number_of_before_par),
3374 GetParFromID(undo->number_of_behind_par)));
3376 return TextHandleUndo(bview, undo);
3380 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3384 // returns false if no undo possible
3385 bool result = false;
3387 LyXParagraph * before =
3388 GetParFromID(undo->number_of_before_par);
3389 LyXParagraph * behind =
3390 GetParFromID(undo->number_of_behind_par);
3391 LyXParagraph * tmppar;
3392 LyXParagraph * tmppar2;
3393 LyXParagraph * endpar;
3394 LyXParagraph * tmppar5;
3396 // if there's no before take the beginning
3397 // of the document for redoing
3399 SetCursorIntern(bview, FirstParagraph(), 0);
3401 // replace the paragraphs with the undo informations
3403 LyXParagraph * tmppar3 = undo->par;
3404 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3405 LyXParagraph * tmppar4 = tmppar3;
3407 while (tmppar4->next)
3408 tmppar4 = tmppar4->next;
3409 } // get last undo par
3411 // now remove the old text if there is any
3412 if (before != behind || (!behind && !before)){
3414 tmppar5 = before->next;
3416 tmppar5 = OwnerParagraph();
3418 while (tmppar5 && tmppar5 != behind){
3420 tmppar5 = tmppar5->next;
3421 // a memory optimization for edit: Only layout information
3422 // is stored in the undo. So restore the text informations.
3423 if (undo->kind == Undo::EDIT) {
3424 tmppar2->setContentsFromPar(tmppar);
3425 tmppar->clearContents();
3426 tmppar2 = tmppar2->next;
3431 // put the new stuff in the list if there is one
3434 before->next = tmppar3;
3436 OwnerParagraph(tmppar3);
3437 tmppar3->previous = before;
3441 OwnerParagraph(behind);
3444 tmppar4->next = behind;
3446 behind->previous = tmppar4;
3450 // Set the cursor for redoing
3452 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3453 // check wether before points to a closed float and open it if necessary
3454 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3455 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3457 while (tmppar4->previous &&
3458 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3459 tmppar4 = tmppar4->previous;
3460 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3461 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3462 tmppar4 = tmppar4->next;
3467 // open a cosed footnote at the end if necessary
3468 if (behind && behind->previous &&
3469 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3470 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3471 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3472 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3473 behind = behind->next;
3477 // calculate the endpar for redoing the paragraphs.
3479 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3480 endpar = behind->LastPhysicalPar()->Next();
3482 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3486 tmppar = GetParFromID(undo->number_of_cursor_par);
3487 RedoParagraphs(bview, cursor, endpar);
3489 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3490 UpdateCounters(bview, cursor.row());
3500 void LyXText::FinishUndo()
3504 // makes sure the next operation will be stored
3505 undo_finished = true;
3509 void LyXText::FreezeUndo()
3513 // this is dangerous and for internal use only
3518 void LyXText::UnFreezeUndo()
3522 // this is dangerous and for internal use only
3523 undo_frozen = false;
3527 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3528 LyXParagraph const * before,
3529 LyXParagraph const * behind) const
3534 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3535 buf->redostack.clear();
3539 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3540 LyXParagraph const * before, LyXParagraph const * behind)
3544 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3548 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3549 LyXParagraph const * before,
3550 LyXParagraph const * behind) const
3555 int before_number = -1;
3556 int behind_number = -1;
3558 before_number = before->id();
3560 behind_number = behind->id();
3561 // Undo::EDIT and Undo::FINISH are
3562 // always finished. (no overlapping there)
3563 // overlapping only with insert and delete inside one paragraph:
3564 // Nobody wants all removed character
3565 // appear one by one when undoing.
3566 // EDIT is special since only layout information, not the
3567 // contents of a paragaph are stored.
3568 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3569 // check wether storing is needed
3570 if (!buf->undostack.empty() &&
3571 buf->undostack.top()->kind == kind &&
3572 buf->undostack.top()->number_of_before_par == before_number &&
3573 buf->undostack.top()->number_of_behind_par == behind_number ){
3578 // create a new Undo
3579 LyXParagraph * undopar;
3580 LyXParagraph * tmppar;
3581 LyXParagraph * tmppar2;
3583 LyXParagraph * start = 0;
3584 LyXParagraph * end = 0;
3587 start = before->next;
3589 start = FirstParagraph();
3591 end = behind->previous;
3593 end = FirstParagraph();
3599 && start != end->next
3600 && (before != behind || (!before && !behind))) {
3602 tmppar2 = tmppar->Clone();
3603 tmppar2->id(tmppar->id());
3605 // a memory optimization: Just store the layout information
3607 if (kind == Undo::EDIT){
3608 //tmppar2->text.clear();
3609 tmppar2->clearContents();
3614 while (tmppar != end && tmppar->next) {
3615 tmppar = tmppar->next;
3616 tmppar2->next = tmppar->Clone();
3617 tmppar2->next->id(tmppar->id());
3618 // a memory optimization: Just store the layout
3619 // information when only edit
3620 if (kind == Undo::EDIT){
3621 //tmppar2->next->text.clear();
3622 tmppar2->clearContents();
3624 tmppar2->next->previous = tmppar2;
3625 tmppar2 = tmppar2->next;
3629 undopar = 0; // nothing to replace (undo of delete maybe)
3631 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3632 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3634 Undo * undo = new Undo(kind,
3635 before_number, behind_number,
3636 cursor_par, cursor_pos,
3639 undo_finished = false;
3644 void LyXText::SetCursorParUndo(Buffer * buf)
3648 SetUndo(buf, Undo::FINISH,
3649 cursor.par()->ParFromPos(cursor.pos())->previous,
3650 cursor.par()->ParFromPos(cursor.pos())->next);
3655 void LyXText::RemoveTableRow(LyXCursor & cur) const
3661 // move to the previous row
3662 int cell_act = NumberOfCell(cur.par(), cur.pos());
3665 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3666 cur.pos(cur.pos() - 1);
3668 !cur.par()->table->IsFirstCell(cell_act)) {
3669 cur.pos(cur.pos() - 1);
3670 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3671 cur.pos(cur.pos() - 1);
3675 // now we have to pay attention if the actual table is the
3676 // main row of TableContRows and if yes to delete all of them
3681 // delete up to the next row
3682 while (cur.pos() < cur.par()->Last() &&
3684 || !cur.par()->table->IsFirstCell(cell_act))) {
3685 while (cur.pos() < cur.par()->Last() &&
3686 !cur.par()->IsNewline(cur.pos()))
3687 cur.par()->Erase(cur.pos());
3690 if (cur.pos() < cur.par()->Last())
3691 cur.par()->Erase(cur.pos());
3693 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3694 cur.pos(cur.pos() - 1);
3695 cur.par()->Erase(cur.pos()); // no newline at very end!
3697 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3698 !cur.par()->table->IsContRow(cell_org) &&
3699 cur.par()->table->IsContRow(cell));
3700 cur.par()->table->DeleteRow(cell_org);
3707 bool LyXText::IsEmptyTableCell() const
3709 LyXParagraph::size_type pos = cursor.pos() - 1;
3710 while (pos >= 0 && pos < cursor.par()->Last()
3711 && !cursor.par()->IsNewline(pos))
3713 return cursor.par()->IsNewline(pos + 1);
3718 void LyXText::toggleAppendix(BufferView * bview)
3720 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3721 bool start = !par->start_of_appendix;
3723 // ensure that we have only one start_of_appendix in this document
3724 LyXParagraph * tmp = FirstParagraph();
3725 for (; tmp; tmp = tmp->next)
3726 tmp->start_of_appendix = 0;
3727 par->start_of_appendix = start;
3729 // we can set the refreshing parameters now
3730 status = LyXText::NEED_MORE_REFRESH;
3732 refresh_row = 0; // not needed for full update
3733 UpdateCounters(bview, 0);
3734 SetCursor(bview, cursor.par(), cursor.pos());
3737 LyXParagraph * LyXText::OwnerParagraph() const
3740 return inset_owner->par;
3742 return bv_owner->buffer()->paragraph;
3746 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3749 inset_owner->par = p;
3751 bv_owner->buffer()->paragraph = p;