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 << "Baseline Paragraph Pos Height Ascent Fill\n";
137 lyxerr << tmprow->baseline() << '\t'
138 << tmprow->par() << '\t'
139 << tmprow->pos() << '\t'
140 << tmprow->height() << '\t'
141 << tmprow->ascent_of_text() << '\t'
142 << tmprow->fill() << '\n';
143 tmprow = tmprow->next();
151 // Delete all rows, this does not touch the paragraphs!
152 Row * tmprow = firstrow;
154 tmprow = firstrow->next();
162 void LyXText::owner(BufferView * bv)
164 if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
169 // Gets the fully instantiated font at a given position in a paragraph
170 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
171 // The difference is that this one is used for displaying, and thus we
172 // are allowed to make cosmetic improvements. For instance make footnotes
174 // If position is -1, we get the layout font of the paragraph.
175 // If position is -2, we get the font of the manual label of the paragraph.
176 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
177 LyXParagraph::size_type pos) const
179 LyXLayout const & layout =
180 textclasslist.Style(buf->params.textclass, par->GetLayout());
182 char par_depth = par->GetDepth();
183 // We specialize the 95% common case:
184 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
187 if (layout.labeltype == LABEL_MANUAL
188 && pos < BeginningOfMainBody(buf, par)) {
190 return par->GetFontSettings(buf->params, pos).
191 realize(layout.reslabelfont);
193 return par->GetFontSettings(buf->params, pos).
194 realize(layout.resfont);
197 // process layoutfont for pos == -1 and labelfont for pos < -1
199 return layout.resfont;
201 return layout.reslabelfont;
205 // The uncommon case need not be optimized as much
207 LyXFont layoutfont, tmpfont;
211 if (pos < BeginningOfMainBody(buf, par)) {
213 layoutfont = layout.labelfont;
216 layoutfont = layout.font;
218 tmpfont = par->GetFontSettings(buf->params, pos);
219 tmpfont.realize(layoutfont);
222 // process layoutfont for pos == -1 and labelfont for pos < -1
224 tmpfont = layout.font;
226 tmpfont = layout.labelfont;
229 // Resolve against environment font information
230 while (par && par_depth && !tmpfont.resolved()) {
231 par = par->DepthHook(par_depth - 1);
233 tmpfont.realize(textclasslist.
234 Style(buf->params.textclass,
235 par->GetLayout()).font);
236 par_depth = par->GetDepth();
240 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
242 // Cosmetic improvement: If this is an open footnote, make the font
244 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
245 && par->footnotekind == LyXParagraph::FOOTNOTE) {
253 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
254 LyXParagraph::size_type pos,
258 // Let the insets convert their font
259 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
260 if (par->GetInset(pos))
261 font = par->GetInset(pos)->ConvertFont(font);
264 LyXLayout const & layout =
265 textclasslist.Style(buf->params.textclass,
268 // Get concrete layout font to reduce against
271 if (pos < BeginningOfMainBody(buf, par))
272 layoutfont = layout.labelfont;
274 layoutfont = layout.font;
276 // Realize against environment font information
277 if (par->GetDepth()){
278 LyXParagraph * tp = par;
279 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
280 tp = tp->DepthHook(tp->GetDepth()-1);
282 layoutfont.realize(textclasslist.
283 Style(buf->params.textclass,
284 tp->GetLayout()).font);
288 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
290 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
291 && par->footnotekind == LyXParagraph::FOOTNOTE) {
292 layoutfont.decSize();
295 // Now, reduce font against full layout font
296 font.reduce(layoutfont);
298 par->SetFont(pos, font);
302 /* inserts a new row behind the specified row, increments
303 * the touched counters */
304 void LyXText::InsertRow(Row * row, LyXParagraph * par,
305 LyXParagraph::size_type pos) const
307 Row * tmprow = new Row;
310 tmprow->next(firstrow);
313 tmprow->previous(row);
314 tmprow->next(row->next());
319 tmprow->next()->previous(tmprow);
321 if (tmprow->previous())
322 tmprow->previous()->next(tmprow);
330 ++number_of_rows; // one more row
334 // removes the row and reset the touched counters
335 void LyXText::RemoveRow(Row * row) const
337 /* this must not happen before the currentrow for clear reasons.
338 so the trick is just to set the current row onto the previous
341 GetRow(row->par(), row->pos(), unused_y);
344 row->next()->previous(row->previous());
345 if (!row->previous()) {
346 firstrow = row->next();
348 row->previous()->next(row->next());
351 lastrow = row->previous();
353 height -= row->height(); // the text becomes smaller
356 --number_of_rows; // one row less
360 // remove all following rows of the paragraph of the specified row.
361 void LyXText::RemoveParagraph(Row * row) const
363 LyXParagraph * tmppar = row->par();
367 while (row && row->par() == tmppar) {
368 tmprow = row->next();
375 // insert the specified paragraph behind the specified row
376 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
379 InsertRow(row, par, 0); /* insert a new row, starting
382 SetCounter(bview->buffer(), par); // set the counters
384 // and now append the whole paragraph behind the new row
387 AppendParagraph(bview, firstrow);
389 row->next()->height(0);
390 AppendParagraph(bview, row->next());
395 void LyXText::ToggleFootnote(BufferView * bview)
397 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
399 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
401 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
403 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
404 CloseFootnote(bview);
409 void LyXText::OpenStuff(BufferView * bview)
411 if (cursor.pos() == 0 && cursor.par()->bibkey){
412 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
414 else if (cursor.pos() < cursor.par()->Last()
415 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
416 && cursor.par()->GetInset(cursor.pos())->Editable()) {
417 bview->owner()->getMiniBuffer()
418 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
419 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
420 SetCursorParUndo(bview->buffer());
421 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
423 ToggleFootnote(bview);
428 void LyXText::CloseFootnote(BufferView * bview)
430 LyXParagraph * tmppar;
431 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
433 // if the cursor is not in an open footnote, or
434 // there is no open footnote in this paragraph, just return.
435 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
438 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
439 bview->owner()->getMiniBuffer()
440 ->Set(_("Nothing to do"));
444 // ok, move the cursor right before the footnote
445 // just a little faster than using CursorRight()
447 cursor.par()->ParFromPos(cursor.pos()) != par;) {
448 cursor.pos(cursor.pos() + 1);
451 // now the cursor is at the beginning of the physical par
452 SetCursor(bview, cursor.par(),
454 cursor.par()->ParFromPos(cursor.pos())->size());
456 /* we are in a footnote, so let us move at the beginning */
457 /* this is just faster than using just CursorLeft() */
459 tmppar = cursor.par();
460 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
461 // just a little bit faster than movin the cursor
462 tmppar = tmppar->Previous();
464 SetCursor(bview, tmppar, tmppar->Last());
467 // the cursor must be exactly before the footnote
468 par = cursor.par()->ParFromPos(cursor.pos());
470 status = LyXText::NEED_MORE_REFRESH;
471 refresh_row = cursor.row();
472 refresh_y = cursor.y() - cursor.row()->baseline();
474 tmppar = cursor.par();
475 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
476 Row * row = cursor.row();
478 tmppar->CloseFootnote(cursor.pos());
480 while (tmppar != endpar) {
481 RemoveRow(row->next());
483 tmppar = row->next()->par();
488 AppendParagraph(bview, cursor.row());
490 SetCursor(bview, cursor.par(), cursor.pos());
494 if (cursor.row()->next())
495 SetHeightOfRow(bview, cursor.row()->next());
499 /* used in setlayout */
500 // Asger is not sure we want to do this...
501 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
504 LyXLayout const & layout =
505 textclasslist.Style(buf->params.textclass, par->GetLayout());
507 LyXFont layoutfont, tmpfont;
508 for (LyXParagraph::size_type pos = 0;
509 pos < par->Last(); ++pos) {
510 if (pos < BeginningOfMainBody(buf, par))
511 layoutfont = layout.labelfont;
513 layoutfont = layout.font;
515 tmpfont = par->GetFontSettings(buf->params, pos);
516 tmpfont.reduce(layoutfont);
517 par->SetFont(pos, tmpfont);
521 LyXParagraph * LyXText::SetLayout(BufferView * bview,
522 LyXCursor & cur, LyXCursor & sstart_cur,
523 LyXCursor & send_cur,
524 LyXTextClass::size_type layout)
526 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
527 LyXParagraph * undoendpar = endpar;
529 if (endpar && endpar->GetDepth()) {
530 while (endpar && endpar->GetDepth()) {
531 endpar = endpar->LastPhysicalPar()->Next();
535 endpar = endpar->Next(); // because of parindents etc.
538 SetUndo(bview->buffer(), Undo::EDIT,
539 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
542 /* ok we have a selection. This is always between sstart_cur
543 * and sel_end cursor */
546 LyXLayout const & lyxlayout =
547 textclasslist.Style(bview->buffer()->params.textclass, layout);
549 while (cur.par() != send_cur.par()) {
550 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
551 cur.par()->SetLayout(bview->buffer()->params, layout);
552 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
553 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
554 fppar->added_space_top = lyxlayout.fill_top ?
555 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
556 fppar->added_space_bottom = lyxlayout.fill_bottom ?
557 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
558 if (lyxlayout.margintype == MARGIN_MANUAL)
559 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
560 if (lyxlayout.labeltype != LABEL_BIBLIO
562 delete fppar->bibkey;
566 cur.par(cur.par()->Next());
568 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
569 cur.par()->SetLayout(bview->buffer()->params, layout);
570 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
571 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
572 fppar->added_space_top = lyxlayout.fill_top ?
573 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
574 fppar->added_space_bottom = lyxlayout.fill_bottom ?
575 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
576 if (lyxlayout.margintype == MARGIN_MANUAL)
577 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
578 if (lyxlayout.labeltype != LABEL_BIBLIO
580 delete fppar->bibkey;
587 // set layout over selection and make a total rebreak of those paragraphs
588 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
591 tmpcursor = cursor; /* store the current cursor */
593 #ifdef USE_OLD_SET_LAYOUT
594 // if there is no selection just set the layout
595 // of the current paragraph */
597 sel_start_cursor = cursor; // dummy selection
598 sel_end_cursor = cursor;
601 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
602 LyXParagraph * undoendpar = endpar;
604 if (endpar && endpar->GetDepth()) {
605 while (endpar && endpar->GetDepth()) {
606 endpar = endpar->LastPhysicalPar()->Next();
611 endpar = endpar->Next(); // because of parindents etc.
615 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
618 /* ok we have a selection. This is always between sel_start_cursor
619 * and sel_end cursor */
620 cursor = sel_start_cursor;
622 LyXLayout const & lyxlayout =
623 textclasslist.Style(bview->buffer()->params.textclass, layout);
625 while (cursor.par() != sel_end_cursor.par()) {
626 if (cursor.par()->footnoteflag ==
627 sel_start_cursor.par()->footnoteflag) {
628 cursor.par()->SetLayout(layout);
629 MakeFontEntriesLayoutSpecific(cursor.par());
630 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
631 fppar->added_space_top = lyxlayout.fill_top ?
632 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
633 fppar->added_space_bottom = lyxlayout.fill_bottom ?
634 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
635 if (lyxlayout.margintype == MARGIN_MANUAL)
636 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
637 if (lyxlayout.labeltype != LABEL_BIBLIO
639 delete fppar->bibkey;
643 cursor.par() = cursor.par()->Next();
645 if (cursor.par()->footnoteflag ==
646 sel_start_cursor.par()->footnoteflag) {
647 cursor.par()->SetLayout(layout);
648 MakeFontEntriesLayoutSpecific(cursor.par());
649 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
650 fppar->added_space_top = lyxlayout.fill_top ?
651 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
652 fppar->added_space_bottom = lyxlayout.fill_bottom ?
653 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
654 if (lyxlayout.margintype == MARGIN_MANUAL)
655 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
656 if (lyxlayout.labeltype != LABEL_BIBLIO
658 delete fppar->bibkey;
663 // if there is no selection just set the layout
664 // of the current paragraph */
666 sel_start_cursor = cursor; // dummy selection
667 sel_end_cursor = cursor;
670 endpar = SetLayout(bview, cursor, sel_start_cursor,
671 sel_end_cursor, layout);
673 RedoParagraphs(bview, sel_start_cursor, endpar);
675 // we have to reset the selection, because the
676 // geometry could have changed */
677 SetCursor(bview, sel_start_cursor.par(),
678 sel_start_cursor.pos(), false);
680 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
682 UpdateCounters(bview, cursor.row());
685 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
689 // increment depth over selection and
690 // make a total rebreak of those paragraphs
691 void LyXText::IncDepth(BufferView * bview)
693 // If there is no selection, just use the current paragraph
695 sel_start_cursor = cursor; // dummy selection
696 sel_end_cursor = cursor;
699 // We end at the next paragraph with depth 0
700 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
701 LyXParagraph * undoendpar = endpar;
703 if (endpar && endpar->GetDepth()) {
704 while (endpar && endpar->GetDepth()) {
705 endpar = endpar->LastPhysicalPar()->Next();
710 endpar = endpar->Next(); // because of parindents etc.
713 SetUndo(bview->buffer(), Undo::EDIT,
715 .par()->ParFromPos(sel_start_cursor.pos())->previous,
718 LyXCursor tmpcursor = cursor; // store the current cursor
720 // ok we have a selection. This is always between sel_start_cursor
721 // and sel_end cursor
722 cursor = sel_start_cursor;
724 bool anything_changed = false;
727 // NOTE: you can't change the depth of a bibliography entry
728 if (cursor.par()->footnoteflag ==
729 sel_start_cursor.par()->footnoteflag
730 && textclasslist.Style(bview->buffer()->params.textclass,
731 cursor.par()->GetLayout()
732 ).labeltype != LABEL_BIBLIO) {
733 LyXParagraph * prev =
734 cursor.par()->FirstPhysicalPar()->Previous();
736 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
737 || (prev->GetDepth() == cursor.par()->GetDepth()
738 && textclasslist.Style(bview->buffer()->params.textclass,
739 prev->GetLayout()).isEnvironment()))) {
740 cursor.par()->FirstPhysicalPar()->depth++;
741 anything_changed = true;
744 if (cursor.par() == sel_end_cursor.par())
746 cursor.par(cursor.par()->Next());
749 // if nothing changed set all depth to 0
750 if (!anything_changed) {
751 cursor = sel_start_cursor;
752 while (cursor.par() != sel_end_cursor.par()) {
753 cursor.par()->FirstPhysicalPar()->depth = 0;
754 cursor.par(cursor.par()->Next());
756 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
757 cursor.par()->FirstPhysicalPar()->depth = 0;
760 RedoParagraphs(bview, sel_start_cursor, endpar);
762 // we have to reset the selection, because the
763 // geometry could have changed
764 SetCursor(bview, sel_start_cursor.par(),
765 sel_start_cursor.pos());
767 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
768 UpdateCounters(bview, cursor.row());
771 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
775 // decrement depth over selection and
776 // make a total rebreak of those paragraphs
777 void LyXText::DecDepth(BufferView * bview)
779 // if there is no selection just set the layout
780 // of the current paragraph
782 sel_start_cursor = cursor; // dummy selection
783 sel_end_cursor = cursor;
786 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
787 LyXParagraph * undoendpar = endpar;
789 if (endpar && endpar->GetDepth()) {
790 while (endpar && endpar->GetDepth()) {
791 endpar = endpar->LastPhysicalPar()->Next();
796 endpar = endpar->Next(); // because of parindents etc.
799 SetUndo(bview->buffer(), Undo::EDIT,
801 .par()->ParFromPos(sel_start_cursor.pos())->previous,
804 LyXCursor tmpcursor = cursor; // store the current cursor
806 // ok we have a selection. This is always between sel_start_cursor
807 // and sel_end cursor
808 cursor = sel_start_cursor;
811 if (cursor.par()->footnoteflag ==
812 sel_start_cursor.par()->footnoteflag) {
813 if (cursor.par()->FirstPhysicalPar()->depth)
814 cursor.par()->FirstPhysicalPar()->depth--;
816 if (cursor.par() == sel_end_cursor.par())
818 cursor.par(cursor.par()->Next());
821 RedoParagraphs(bview, sel_start_cursor, endpar);
823 // we have to reset the selection, because the
824 // geometry could have changed
825 SetCursor(bview, sel_start_cursor.par(),
826 sel_start_cursor.pos());
828 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
829 UpdateCounters(bview, cursor.row());
832 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
836 // set font over selection and make a total rebreak of those paragraphs
837 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
839 // if there is no selection just set the current_font
841 // Determine basis font
843 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
845 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
847 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
848 // Update current font
849 real_current_font.update(font,
850 bview->buffer()->params.language_info,
853 // Reduce to implicit settings
854 current_font = real_current_font;
855 current_font.reduce(layoutfont);
856 // And resolve it completely
857 real_current_font.realize(layoutfont);
861 LyXCursor tmpcursor = cursor; // store the current cursor
863 // ok we have a selection. This is always between sel_start_cursor
864 // and sel_end cursor
866 SetUndo(bview->buffer(), Undo::EDIT,
867 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
868 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
869 cursor = sel_start_cursor;
870 while (cursor.par() != sel_end_cursor.par() ||
871 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
872 && cursor.pos() < sel_end_cursor.pos()))
874 if (cursor.pos() < cursor.par()->Last()
875 && cursor.par()->footnoteflag
876 == sel_start_cursor.par()->footnoteflag) {
877 // an open footnote should behave
879 LyXFont newfont = GetFont(bview->buffer(),
880 cursor.par(), cursor.pos());
882 bview->buffer()->params.language_info,
884 SetCharFont(bview->buffer(),
885 cursor.par(), cursor.pos(), newfont);
886 cursor.pos(cursor.pos() + 1);
889 cursor.par(cursor.par()->Next());
893 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
895 // we have to reset the selection, because the
896 // geometry could have changed
897 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
899 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
902 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
903 tmpcursor.boundary());
907 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
909 Row * tmprow = cur.row();
910 long y = cur.y() - tmprow->baseline();
912 SetHeightOfRow(bview, tmprow);
913 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
914 // find the first row of the paragraph
915 if (first_phys_par != tmprow->par())
916 while (tmprow->previous()
917 && tmprow->previous()->par() != first_phys_par) {
918 tmprow = tmprow->previous();
919 y -= tmprow->height();
920 SetHeightOfRow(bview, tmprow);
922 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
923 tmprow = tmprow->previous();
924 y -= tmprow->height();
925 SetHeightOfRow(bview, tmprow);
928 // we can set the refreshing parameters now
929 status = LyXText::NEED_MORE_REFRESH;
931 refresh_row = tmprow;
932 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
936 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
938 Row * tmprow = cur.row();
940 long y = cur.y() - tmprow->baseline();
941 SetHeightOfRow(bview, tmprow);
942 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
943 // find the first row of the paragraph
944 if (first_phys_par != tmprow->par())
945 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
946 tmprow = tmprow->previous();
947 y -= tmprow->height();
949 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
950 tmprow = tmprow->previous();
951 y -= tmprow->height();
954 // we can set the refreshing parameters now
955 if (status == LyXText::UNCHANGED || y < refresh_y) {
957 refresh_row = tmprow;
959 status = LyXText::NEED_MORE_REFRESH;
960 SetCursor(bview, cur.par(), cur.pos());
964 /* deletes and inserts again all paragaphs between the cursor
965 * and the specified par
966 * This function is needed after SetLayout and SetFont etc. */
967 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
968 LyXParagraph const * endpar) const
971 LyXParagraph * tmppar = 0, * first_phys_par = 0;
973 Row * tmprow = cur.row();
975 long y = cur.y() - tmprow->baseline();
977 if (!tmprow->previous()){
978 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
980 first_phys_par = tmprow->par()->FirstPhysicalPar();
981 // find the first row of the paragraph
982 if (first_phys_par != tmprow->par())
983 while (tmprow->previous() &&
984 (tmprow->previous()->par() != first_phys_par)) {
985 tmprow = tmprow->previous();
986 y -= tmprow->height();
988 while (tmprow->previous()
989 && tmprow->previous()->par() == first_phys_par) {
990 tmprow = tmprow->previous();
991 y -= tmprow->height();
995 // we can set the refreshing parameters now
996 status = LyXText::NEED_MORE_REFRESH;
998 refresh_row = tmprow->previous(); /* the real refresh row will
999 be deleted, so I store
1000 the previous here */
1003 tmppar = tmprow->next()->par();
1006 while (tmppar != endpar) {
1007 RemoveRow(tmprow->next());
1009 tmppar = tmprow->next()->par();
1014 // remove the first one
1015 tmprow2 = tmprow; /* this is because tmprow->previous()
1017 tmprow = tmprow->previous();
1020 tmppar = first_phys_par;
1024 InsertParagraph(bview, tmppar, tmprow);
1027 while (tmprow->next() && tmprow->next()->par() == tmppar)
1028 tmprow = tmprow->next();
1029 tmppar = tmppar->Next();
1031 } while (tmppar != endpar);
1033 // this is because of layout changes
1035 refresh_y -= refresh_row->height();
1036 SetHeightOfRow(bview, refresh_row);
1038 refresh_row = firstrow;
1040 SetHeightOfRow(bview, refresh_row);
1043 if (tmprow && tmprow->next())
1044 SetHeightOfRow(bview, tmprow->next());
1048 bool LyXText::FullRebreak(BufferView * bview)
1050 if (need_break_row) {
1051 BreakAgain(bview, need_break_row);
1059 /* important for the screen */
1062 /* the cursor set functions have a special mechanism. When they
1063 * realize, that you left an empty paragraph, they will delete it.
1064 * They also delete the corresponding row */
1066 // need the selection cursor:
1067 void LyXText::SetSelection(BufferView * bview)
1070 last_sel_cursor = sel_cursor;
1071 sel_start_cursor = sel_cursor;
1072 sel_end_cursor = sel_cursor;
1077 // first the toggling area
1078 if (cursor.y() < last_sel_cursor.y()
1079 || (cursor.y() == last_sel_cursor.y()
1080 && cursor.x() < last_sel_cursor.x())) {
1081 toggle_end_cursor = last_sel_cursor;
1082 toggle_cursor = cursor;
1084 toggle_end_cursor = cursor;
1085 toggle_cursor = last_sel_cursor;
1088 last_sel_cursor = cursor;
1090 // and now the whole selection
1092 if (sel_cursor.par() == cursor.par())
1093 if (sel_cursor.pos() < cursor.pos()) {
1094 sel_end_cursor = cursor;
1095 sel_start_cursor = sel_cursor;
1097 sel_end_cursor = sel_cursor;
1098 sel_start_cursor = cursor;
1100 else if (sel_cursor.y() < cursor.y() ||
1101 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1102 sel_end_cursor = cursor;
1103 sel_start_cursor = sel_cursor;
1106 sel_end_cursor = sel_cursor;
1107 sel_start_cursor = cursor;
1110 // a selection with no contents is not a selection
1111 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1112 sel_start_cursor.pos() == sel_end_cursor.pos())
1117 string LyXText::selectionAsString(Buffer const * buffer) const
1119 if (!selection) return string();
1122 // Special handling if the whole selection is within one paragraph
1123 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1124 result += sel_start_cursor.par()->String(buffer,
1125 sel_start_cursor.pos(),
1126 sel_end_cursor.pos());
1130 // The selection spans more than one paragraph
1132 // First paragraph in selection
1133 result += sel_start_cursor.par()->String(buffer,
1134 sel_start_cursor.pos(),
1135 sel_start_cursor.par()->Last())
1138 // The paragraphs in between (if any)
1139 LyXCursor tmpcur(sel_start_cursor);
1140 tmpcur.par(tmpcur.par()->Next());
1141 while (tmpcur.par() != sel_end_cursor.par()) {
1142 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1143 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1146 // Last paragraph in selection
1147 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1153 void LyXText::ClearSelection() const
1160 void LyXText::CursorHome(BufferView * bview) const
1162 SetCursor(bview, cursor.par(), cursor.row()->pos());
1166 void LyXText::CursorEnd(BufferView * bview) const
1168 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1169 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1171 if (cursor.par()->Last() &&
1172 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1173 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1174 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1176 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1179 if (cursor.par()->table) {
1180 int cell = NumberOfCell(cursor.par(), cursor.pos());
1181 if (cursor.par()->table->RowHasContRow(cell) &&
1182 cursor.par()->table->CellHasContRow(cell)<0) {
1183 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1184 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1186 if (cursor.par()->Last() &&
1187 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1188 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1189 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1191 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1199 void LyXText::CursorTop(BufferView * bview) const
1201 while (cursor.par()->Previous())
1202 cursor.par(cursor.par()->Previous());
1203 SetCursor(bview, cursor.par(), 0);
1207 void LyXText::CursorBottom(BufferView * bview) const
1209 while (cursor.par()->Next())
1210 cursor.par(cursor.par()->Next());
1211 SetCursor(bview, cursor.par(), cursor.par()->Last());
1215 /* returns a pointer to the row near the specified y-coordinate
1216 * (relative to the whole text). y is set to the real beginning
1218 Row * LyXText::GetRowNearY(long & y) const
1220 Row * tmprow = firstrow;
1223 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1224 tmpy += tmprow->height();
1225 tmprow = tmprow->next();
1228 y = tmpy; // return the real y
1233 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1235 // If the mask is completely neutral, tell user
1236 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1237 // Could only happen with user style
1238 bview->owner()->getMiniBuffer()
1239 ->Set(_("No font change defined. Use Character under"
1240 " the Layout menu to define font change."));
1244 // Try implicit word selection
1245 // If there is a change in the language the implicit word selection
1247 LyXCursor resetCursor = cursor;
1248 bool implicitSelection = (font.language() == ignore_language)
1249 ? SelectWordWhenUnderCursor(bview) : false;
1252 SetFont(bview, font, toggleall);
1254 /* Implicit selections are cleared afterwards and cursor is set to the
1255 original position. */
1256 if (implicitSelection) {
1258 cursor = resetCursor;
1259 SetCursor(bview, cursor.par(), cursor.pos());
1260 sel_cursor = cursor;
1265 LyXParagraph::size_type
1266 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1268 if (textclasslist.Style(buf->params.textclass,
1269 par->GetLayout()).labeltype != LABEL_MANUAL)
1272 return par->BeginningOfMainBody();
1276 /* if there is a selection, reset every environment you can find
1277 * in the selection, otherwise just the environment you are in */
1278 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1280 LyXParagraph * tmppar, * firsttmppar;
1284 /* is is only allowed, if the cursor is IN an open footnote.
1285 * Otherwise it is too dangerous */
1286 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1289 SetUndo(bview->buffer(), Undo::FINISH,
1290 cursor.par()->PreviousBeforeFootnote()->previous,
1291 cursor.par()->NextAfterFootnote()->next);
1293 /* ok, move to the beginning of the footnote. */
1294 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1295 cursor.par(cursor.par()->Previous());
1297 SetCursor(bview, cursor.par(), cursor.par()->Last());
1298 /* this is just faster than using CursorLeft(); */
1300 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1301 tmppar = firsttmppar;
1302 /* tmppar is now the paragraph right before the footnote */
1304 bool first_footnote_par_is_not_empty = tmppar->next->size();
1307 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1308 tmppar = tmppar->next; /* I use next instead of Next(),
1309 * because there cannot be any
1310 * footnotes in a footnote
1312 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1314 /* remember the captions and empty paragraphs */
1315 if ((textclasslist.Style(bview->buffer()->params.textclass,
1316 tmppar->GetLayout())
1317 .labeltype == LABEL_SENSITIVE)
1319 tmppar->SetLayout(bview->buffer()->params, 0);
1322 // now we will paste the ex-footnote, if the layouts allow it
1323 // first restore the layout of the paragraph right behind
1326 tmppar->next->MakeSameLayout(cursor.par());
1329 if ((!tmppar->GetLayout() && !tmppar->table)
1331 && (!tmppar->Next()->Last()
1332 || tmppar->Next()->HasSameLayout(tmppar)))) {
1333 if (tmppar->Next()->Last()
1334 && tmppar->Next()->IsLineSeparator(0))
1335 tmppar->Next()->Erase(0);
1336 tmppar->PasteParagraph(bview->buffer()->params);
1339 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1340 * by the pasting of the beginning */
1342 /* then the beginning */
1343 /* if there is no space between the text and the footnote, so we insert
1345 * (only if the previous par and the footnotepar are not empty!) */
1346 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1347 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1348 if (firsttmppar->size()
1349 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1350 && first_footnote_par_is_not_empty) {
1351 firsttmppar->next->InsertChar(0, ' ');
1353 firsttmppar->PasteParagraph(bview->buffer()->params);
1356 /* now redo the paragaphs */
1357 RedoParagraphs(bview, cursor, tmppar);
1359 SetCursor(bview, cursor.par(), cursor.pos());
1361 /* sometimes it can happen, that there is a counter change */
1362 Row * row = cursor.row();
1363 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1365 UpdateCounters(bview, row);
1372 /* the DTP switches for paragraphs. LyX will store them in the
1373 * first physicla paragraph. When a paragraph is broken, the top settings
1374 * rest, the bottom settings are given to the new one. So I can make shure,
1375 * they do not duplicate themself and you cannnot make dirty things with
1378 void LyXText::SetParagraph(BufferView * bview,
1379 bool line_top, bool line_bottom,
1380 bool pagebreak_top, bool pagebreak_bottom,
1381 VSpace const & space_top,
1382 VSpace const & space_bottom,
1384 string labelwidthstring,
1387 LyXCursor tmpcursor = cursor;
1389 sel_start_cursor = cursor;
1390 sel_end_cursor = cursor;
1393 // make sure that the depth behind the selection are restored, too
1394 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1395 LyXParagraph * undoendpar = endpar;
1397 if (endpar && endpar->GetDepth()) {
1398 while (endpar && endpar->GetDepth()) {
1399 endpar = endpar->LastPhysicalPar()->Next();
1400 undoendpar = endpar;
1404 endpar = endpar->Next(); // because of parindents etc.
1407 SetUndo(bview->buffer(), Undo::EDIT,
1409 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1413 LyXParagraph * tmppar = sel_end_cursor.par();
1414 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1415 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1416 status = LyXText::NEED_MORE_REFRESH;
1417 refresh_row = cursor.row();
1418 refresh_y = cursor.y() - cursor.row()->baseline();
1419 if (cursor.par()->footnoteflag ==
1420 sel_start_cursor.par()->footnoteflag) {
1421 cursor.par()->line_top = line_top;
1422 cursor.par()->line_bottom = line_bottom;
1423 cursor.par()->pagebreak_top = pagebreak_top;
1424 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1425 cursor.par()->added_space_top = space_top;
1426 cursor.par()->added_space_bottom = space_bottom;
1427 // does the layout allow the new alignment?
1428 if (align == LYX_ALIGN_LAYOUT)
1429 align = textclasslist
1430 .Style(bview->buffer()->params.textclass,
1431 cursor.par()->GetLayout()).align;
1432 if (align & textclasslist
1433 .Style(bview->buffer()->params.textclass,
1434 cursor.par()->GetLayout()).alignpossible) {
1435 if (align == textclasslist
1436 .Style(bview->buffer()->params.textclass,
1437 cursor.par()->GetLayout()).align)
1438 cursor.par()->align = LYX_ALIGN_LAYOUT;
1440 cursor.par()->align = align;
1442 cursor.par()->SetLabelWidthString(labelwidthstring);
1443 cursor.par()->noindent = noindent;
1446 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1449 RedoParagraphs(bview, sel_start_cursor, endpar);
1452 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1453 sel_cursor = cursor;
1454 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1455 SetSelection(bview);
1456 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1460 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1462 char const * widthp,
1463 int alignment, bool hfill,
1464 bool start_minipage)
1466 LyXCursor tmpcursor = cursor;
1467 LyXParagraph * tmppar;
1469 sel_start_cursor = cursor;
1470 sel_end_cursor = cursor;
1473 // make sure that the depth behind the selection are restored, too
1474 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1475 LyXParagraph * undoendpar = endpar;
1477 if (endpar && endpar->GetDepth()) {
1478 while (endpar && endpar->GetDepth()) {
1479 endpar = endpar->LastPhysicalPar()->Next();
1480 undoendpar = endpar;
1484 endpar = endpar->Next(); // because of parindents etc.
1487 SetUndo(bview->buffer(), Undo::EDIT,
1489 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1492 tmppar = sel_end_cursor.par();
1493 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1494 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1495 status = LyXText::NEED_MORE_REFRESH;
1496 refresh_row = cursor.row();
1497 refresh_y = cursor.y() - cursor.row()->baseline();
1498 if (cursor.par()->footnoteflag ==
1499 sel_start_cursor.par()->footnoteflag) {
1500 if (type == LyXParagraph::PEXTRA_NONE) {
1501 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1502 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1503 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1506 cursor.par()->SetPExtraType(bview->buffer()->params,
1507 type, width, widthp);
1508 cursor.par()->pextra_hfill = hfill;
1509 cursor.par()->pextra_start_minipage = start_minipage;
1510 cursor.par()->pextra_alignment = alignment;
1513 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1515 RedoParagraphs(bview, sel_start_cursor, endpar);
1517 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1518 sel_cursor = cursor;
1519 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1520 SetSelection(bview);
1521 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1525 char loweralphaCounter(int n)
1527 if (n < 1 || n > 26)
1533 char alphaCounter(int n)
1535 if (n < 1 || n > 26)
1541 char hebrewCounter(int n)
1543 static const char hebrew[22] = {
1544 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1545 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1546 '÷', 'ø', 'ù', 'ú'
1548 if (n < 1 || n > 22)
1554 static char const * romanCounter(int n)
1556 static char const * roman[20] = {
1557 "i", "ii", "iii", "iv", "v",
1558 "vi", "vii", "viii", "ix", "x",
1559 "xi", "xii", "xiii", "xiv", "xv",
1560 "xvi", "xvii", "xviii", "xix", "xx"
1562 if (n < 1 || n > 20)
1568 // set the counter of a paragraph. This includes the labels
1569 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1571 // this is only relevant for the beginning of paragraph
1572 par = par->FirstPhysicalPar();
1574 LyXLayout const & layout =
1575 textclasslist.Style(buf->params.textclass,
1578 LyXTextClass const & textclass =
1579 textclasslist.TextClass(buf->params.textclass);
1581 /* copy the prev-counters to this one, unless this is the start of a
1582 footnote or of a bibliography or the very first paragraph */
1584 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1585 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1586 && par->footnotekind == LyXParagraph::FOOTNOTE)
1587 && !(textclasslist.Style(buf->params.textclass,
1588 par->Previous()->GetLayout()
1589 ).labeltype != LABEL_BIBLIO
1590 && layout.labeltype == LABEL_BIBLIO)) {
1591 for (int i = 0; i < 10; ++i) {
1592 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1594 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1595 if (!par->appendix && par->start_of_appendix){
1596 par->appendix = true;
1597 for (int i = 0; i < 10; ++i) {
1598 par->setCounter(i, 0);
1601 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1602 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1605 for (int i = 0; i < 10; ++i) {
1606 par->setCounter(i, 0);
1608 par->appendix = par->start_of_appendix;
1613 // if this is an open marginnote and this is the first
1614 // entry in the marginnote and the enclosing
1615 // environment is an enum/item then correct for the
1616 // LaTeX behaviour (ARRae)
1617 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1618 && par->footnotekind == LyXParagraph::MARGIN
1620 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1621 && (par->PreviousBeforeFootnote()
1622 && textclasslist.Style(buf->params.textclass,
1623 par->PreviousBeforeFootnote()->GetLayout()
1624 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1625 // Any itemize or enumerate environment in a marginnote
1626 // that is embedded in an itemize or enumerate
1627 // paragraph is seen by LaTeX as being at a deeper
1628 // level within that enclosing itemization/enumeration
1629 // even if there is a "standard" layout at the start of
1635 /* Maybe we have to increment the enumeration depth.
1636 * BUT, enumeration in a footnote is considered in isolation from its
1637 * surrounding paragraph so don't increment if this is the
1638 * first line of the footnote
1639 * AND, bibliographies can't have their depth changed ie. they
1640 * are always of depth 0
1643 && par->Previous()->GetDepth() < par->GetDepth()
1644 && textclasslist.Style(buf->params.textclass,
1645 par->Previous()->GetLayout()
1646 ).labeltype == LABEL_COUNTER_ENUMI
1647 && par->enumdepth < 3
1648 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1649 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1650 && par->footnotekind == LyXParagraph::FOOTNOTE)
1651 && layout.labeltype != LABEL_BIBLIO) {
1655 /* Maybe we have to decrement the enumeration depth, see note above */
1657 && par->Previous()->GetDepth() > par->GetDepth()
1658 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1659 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1660 && par->footnotekind == LyXParagraph::FOOTNOTE)
1661 && layout.labeltype != LABEL_BIBLIO) {
1662 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1663 par->setCounter(6 + par->enumdepth,
1664 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1665 /* reset the counters.
1666 * A depth change is like a breaking layout
1668 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1669 par->setCounter(i, 0);
1672 if (!par->labelstring.empty()) {
1673 par->labelstring.erase();
1676 if (layout.margintype == MARGIN_MANUAL) {
1677 if (par->labelwidthstring.empty()) {
1678 par->SetLabelWidthString(layout.labelstring());
1681 par->SetLabelWidthString(string());
1684 /* is it a layout that has an automatic label ? */
1685 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1687 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1688 if (i >= 0 && i<= buf->params.secnumdepth) {
1689 par->incCounter(i); // increment the counter
1691 // Is there a label? Useful for Chapter layout
1692 if (!par->appendix){
1693 if (!layout.labelstring().empty())
1694 par->labelstring = layout.labelstring();
1696 par->labelstring.erase();
1698 if (!layout.labelstring_appendix().empty())
1699 par->labelstring = layout.labelstring_appendix();
1701 par->labelstring.erase();
1705 std::ostringstream s;
1709 if (!par->appendix) {
1710 switch (2 * LABEL_FIRST_COUNTER -
1711 textclass.maxcounter() + i) {
1712 case LABEL_COUNTER_CHAPTER:
1713 s << par->getCounter(i);
1715 case LABEL_COUNTER_SECTION:
1716 s << par->getCounter(i - 1) << '.'
1717 << par->getCounter(i);
1719 case LABEL_COUNTER_SUBSECTION:
1720 s << par->getCounter(i - 2) << '.'
1721 << par->getCounter(i - 1) << '.'
1722 << par->getCounter(i);
1724 case LABEL_COUNTER_SUBSUBSECTION:
1725 s << par->getCounter(i - 3) << '.'
1726 << par->getCounter(i - 2) << '.'
1727 << par->getCounter(i - 1) << '.'
1728 << par->getCounter(i);
1731 case LABEL_COUNTER_PARAGRAPH:
1732 s << par->getCounter(i - 4) << '.'
1733 << par->getCounter(i - 3) << '.'
1734 << par->getCounter(i - 2) << '.'
1735 << par->getCounter(i - 1) << '.'
1736 << par->getCounter(i);
1738 case LABEL_COUNTER_SUBPARAGRAPH:
1739 s << par->getCounter(i - 5) << '.'
1740 << par->getCounter(i - 4) << '.'
1741 << par->getCounter(i - 3) << '.'
1742 << par->getCounter(i - 2) << '.'
1743 << par->getCounter(i - 1) << '.'
1744 << par->getCounter(i);
1748 s << par->getCounter(i) << '.';
1751 } else { // appendix
1752 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1753 case LABEL_COUNTER_CHAPTER:
1754 if (par->isRightToLeftPar(buf->params))
1755 s << hebrewCounter(par->getCounter(i));
1757 s << alphaCounter(par->getCounter(i));
1759 case LABEL_COUNTER_SECTION:
1760 if (par->isRightToLeftPar(buf->params))
1761 s << hebrewCounter(par->getCounter(i - 1));
1763 s << alphaCounter(par->getCounter(i - 1));
1766 << par->getCounter(i);
1769 case LABEL_COUNTER_SUBSECTION:
1770 if (par->isRightToLeftPar(buf->params))
1771 s << hebrewCounter(par->getCounter(i - 2));
1773 s << alphaCounter(par->getCounter(i - 2));
1776 << par->getCounter(i-1) << '.'
1777 << par->getCounter(i);
1780 case LABEL_COUNTER_SUBSUBSECTION:
1781 if (par->isRightToLeftPar(buf->params))
1782 s << hebrewCounter(par->getCounter(i-3));
1784 s << alphaCounter(par->getCounter(i-3));
1787 << par->getCounter(i-2) << '.'
1788 << par->getCounter(i-1) << '.'
1789 << par->getCounter(i);
1792 case LABEL_COUNTER_PARAGRAPH:
1793 if (par->isRightToLeftPar(buf->params))
1794 s << hebrewCounter(par->getCounter(i-4));
1796 s << alphaCounter(par->getCounter(i-4));
1799 << par->getCounter(i-3) << '.'
1800 << par->getCounter(i-2) << '.'
1801 << par->getCounter(i-1) << '.'
1802 << par->getCounter(i);
1805 case LABEL_COUNTER_SUBPARAGRAPH:
1806 if (par->isRightToLeftPar(buf->params))
1807 s << hebrewCounter(par->getCounter(i-5));
1809 s << alphaCounter(par->getCounter(i-5));
1812 << par->getCounter(i-4) << '.'
1813 << par->getCounter(i-3) << '.'
1814 << par->getCounter(i-2) << '.'
1815 << par->getCounter(i-1) << '.'
1816 << par->getCounter(i);
1820 // Can this ever be reached? And in the
1821 // case it is, how can this be correct?
1823 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1829 par->labelstring += s.str().c_str();
1830 // We really want to remove the c_str as soon as
1834 char * tmps = s.str();
1835 par->labelstring += tmps;
1839 for (i++; i < 10; ++i) {
1840 // reset the following counters
1841 par->setCounter(i, 0);
1843 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1844 for (i++; i < 10; ++i) {
1845 // reset the following counters
1846 par->setCounter(i, 0);
1848 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1849 par->incCounter(i + par->enumdepth);
1850 int number = par->getCounter(i + par->enumdepth);
1853 std::ostringstream s;
1857 switch (par->enumdepth) {
1859 if (par->isRightToLeftPar(buf->params))
1861 << hebrewCounter(number)
1865 << loweralphaCounter(number)
1869 if (par->isRightToLeftPar(buf->params))
1870 s << '.' << romanCounter(number);
1872 s << romanCounter(number) << '.';
1875 if (par->isRightToLeftPar(buf->params))
1877 << alphaCounter(number);
1879 s << alphaCounter(number)
1883 if (par->isRightToLeftPar(buf->params))
1890 par->labelstring = s.str().c_str();
1891 // we really want to get rid of that c_str()
1894 char * tmps = s.str();
1895 par->labelstring = tmps;
1899 for (i += par->enumdepth + 1; i < 10; ++i)
1900 par->setCounter(i, 0); /* reset the following counters */
1903 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1904 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1906 int number = par->getCounter(i);
1908 par->bibkey = new InsetBibKey();
1909 par->bibkey->setCounter(number);
1910 par->labelstring = layout.labelstring();
1912 // In biblio should't be following counters but...
1914 string s = layout.labelstring();
1916 // the caption hack:
1918 if (layout.labeltype == LABEL_SENSITIVE) {
1919 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1920 && (par->footnotekind == LyXParagraph::FIG
1921 || par->footnotekind == LyXParagraph::WIDE_FIG))
1922 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1923 ? ":øåéà " : "Figure:";
1924 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1925 && (par->footnotekind == LyXParagraph::TAB
1926 || par->footnotekind == LyXParagraph::WIDE_TAB))
1927 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1928 ? ":äìáè" : "Table:";
1929 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1930 && par->footnotekind == LyXParagraph::ALGORITHM)
1931 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1932 ? ":Ãúéøåâìà " : "Algorithm:";
1934 /* par->SetLayout(0);
1935 s = layout->labelstring; */
1936 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1937 ? " :úåòîùî øñç" : "Senseless: ";
1940 par->labelstring = s;
1942 /* reset the enumeration counter. They are always resetted
1943 * when there is any other layout between */
1944 for (int i = 6 + par->enumdepth; i < 10; ++i)
1945 par->setCounter(i, 0);
1950 /* Updates all counters BEHIND the row. Changed paragraphs
1951 * with a dynamic left margin will be rebroken. */
1952 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1960 if (row->par()->next
1961 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1962 par = row->par()->LastPhysicalPar()->Next();
1964 par = row->par()->next;
1969 while (row->par() != par)
1972 SetCounter(bview->buffer(), par);
1974 /* now check for the headline layouts. remember that they
1975 * have a dynamic left margin */
1977 && ( textclasslist.Style(bview->buffer()->params.textclass,
1978 par->layout).margintype == MARGIN_DYNAMIC
1979 || textclasslist.Style(bview->buffer()->params.textclass,
1980 par->layout).labeltype == LABEL_SENSITIVE)
1983 /* Rebreak the paragraph */
1984 RemoveParagraph(row);
1985 AppendParagraph(bview, row);
1987 /* think about the damned open footnotes! */
1988 while (par->Next() &&
1989 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1990 || par->Next()->IsDummy())){
1992 if (par->IsDummy()) {
1993 while (row->par() != par)
1995 RemoveParagraph(row);
1996 AppendParagraph(bview, row);
2001 par = par->LastPhysicalPar()->Next();
2007 /* insets an inset. */
2008 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2010 if (!cursor.par()->InsertInsetAllowed(inset))
2012 SetUndo(bview->buffer(), Undo::INSERT,
2013 cursor.par()->ParFromPos(cursor.pos())->previous,
2014 cursor.par()->ParFromPos(cursor.pos())->next);
2015 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2016 cursor.par()->InsertInset(cursor.pos(), inset);
2017 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2018 * The character will not be inserted a
2023 #ifdef USE_OLD_CUT_AND_PASTE
2024 // this is for the simple cut and paste mechanism
2025 static LyXParagraph * simple_cut_buffer = 0;
2026 static char simple_cut_buffer_textclass = 0;
2028 void DeleteSimpleCutBuffer()
2030 if (!simple_cut_buffer)
2032 LyXParagraph * tmppar;
2034 while (simple_cut_buffer) {
2035 tmppar = simple_cut_buffer;
2036 simple_cut_buffer = simple_cut_buffer()->next;
2039 simple_cut_buffer = 0;
2043 void LyXText::copyEnvironmentType()
2045 copylayouttype = cursor.par()->GetLayout();
2049 void LyXText::pasteEnvironmentType(BufferView * bview)
2051 SetLayout(bview, copylayouttype);
2055 void LyXText::CutSelection(BufferView * bview, bool doclear)
2058 // Stuff what we got on the clipboard. Even if there is no selection.
2060 // There is a problem with having the stuffing here in that the
2061 // larger the selection the slower LyX will get. This can be
2062 // solved by running the line below only when the selection has
2063 // finished. The solution used currently just works, to make it
2064 // faster we need to be more clever and probably also have more
2065 // calls to stuffClipboard. (Lgb)
2066 bview->stuffClipboard(selectionAsString(bview->buffer()));
2068 // This doesn't make sense, if there is no selection
2072 // OK, we have a selection. This is always between sel_start_cursor
2073 // and sel_end cursor
2074 LyXParagraph * tmppar;
2076 // Check whether there are half footnotes in the selection
2077 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2078 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2079 tmppar = sel_start_cursor.par();
2080 while (tmppar != sel_end_cursor.par()){
2081 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2082 WriteAlert(_("Impossible operation"),
2083 _("Don't know what to do with half floats."),
2087 tmppar = tmppar->Next();
2092 /* table stuff -- begin */
2093 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2094 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2095 WriteAlert(_("Impossible operation"),
2096 _("Don't know what to do with half tables."),
2100 sel_start_cursor.par()->table->Reinit();
2102 /* table stuff -- end */
2105 // make sure that the depth behind the selection are restored, too
2106 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2107 LyXParagraph * undoendpar = endpar;
2109 if (endpar && endpar->GetDepth()) {
2110 while (endpar && endpar->GetDepth()) {
2111 endpar = endpar->LastPhysicalPar()->Next();
2112 undoendpar = endpar;
2114 } else if (endpar) {
2115 endpar = endpar->Next(); // because of parindents etc.
2118 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2119 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2123 // there are two cases: cut only within one paragraph or
2124 // more than one paragraph
2125 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2126 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2127 // only within one paragraph
2128 endpar = sel_start_cursor.par();
2129 int pos = sel_end_cursor.pos();
2130 cap.cutSelection(sel_start_cursor.par(), &endpar,
2131 sel_start_cursor.pos(), pos,
2132 bview->buffer()->params.textclass, doclear);
2133 sel_end_cursor.pos(pos);
2135 endpar = sel_end_cursor.par();
2137 int pos = sel_end_cursor.pos();
2138 cap.cutSelection(sel_start_cursor.par(), &endpar,
2139 sel_start_cursor.pos(), pos,
2140 bview->buffer()->params.textclass, doclear);
2142 sel_end_cursor.par(endpar);
2143 sel_end_cursor.pos(pos);
2144 cursor.pos(sel_end_cursor.pos());
2146 endpar = endpar->Next();
2148 // sometimes necessary
2150 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2152 RedoParagraphs(bview, sel_start_cursor, endpar);
2155 cursor = sel_start_cursor;
2156 SetCursor(bview, cursor.par(), cursor.pos());
2157 sel_cursor = cursor;
2158 UpdateCounters(bview, cursor.row());
2162 void LyXText::CopySelection(BufferView * bview)
2164 // Stuff what we got on the clipboard. Even if there is no selection.
2166 // There is a problem with having the stuffing here in that the
2167 // larger the selection the slower LyX will get. This can be
2168 // solved by running the line below only when the selection has
2169 // finished. The solution used currently just works, to make it
2170 // faster we need to be more clever and probably also have more
2171 // calls to stuffClipboard. (Lgb)
2172 bview->stuffClipboard(selectionAsString(bview->buffer()));
2174 // this doesnt make sense, if there is no selection
2178 // ok we have a selection. This is always between sel_start_cursor
2179 // and sel_end cursor
2180 LyXParagraph * tmppar;
2182 /* check wether there are half footnotes in the selection */
2183 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2184 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2185 tmppar = sel_start_cursor.par();
2186 while (tmppar != sel_end_cursor.par()) {
2187 if (tmppar->footnoteflag !=
2188 sel_end_cursor.par()->footnoteflag) {
2189 WriteAlert(_("Impossible operation"),
2190 _("Don't know what to do"
2191 " with half floats."),
2195 tmppar = tmppar->Next();
2200 /* table stuff -- begin */
2201 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2202 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2203 WriteAlert(_("Impossible operation"),
2204 _("Don't know what to do with half tables."),
2209 /* table stuff -- end */
2212 // copy behind a space if there is one
2213 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2214 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2215 && (sel_start_cursor.par() != sel_end_cursor.par()
2216 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2217 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2221 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2222 sel_start_cursor.pos(), sel_end_cursor.pos(),
2223 bview->buffer()->params.textclass);
2227 void LyXText::PasteSelection(BufferView * bview)
2231 // this does not make sense, if there is nothing to paste
2232 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2235 SetUndo(bview->buffer(), Undo::INSERT,
2236 cursor.par()->ParFromPos(cursor.pos())->previous,
2237 cursor.par()->ParFromPos(cursor.pos())->next);
2239 LyXParagraph * endpar;
2240 LyXParagraph * actpar = cursor.par();
2242 int pos = cursor.pos();
2243 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2245 RedoParagraphs(bview, cursor, endpar);
2247 SetCursor(bview, cursor.par(), cursor.pos());
2250 sel_cursor = cursor;
2251 SetCursor(bview, actpar, pos);
2252 SetSelection(bview);
2253 UpdateCounters(bview, cursor.row());
2257 // returns a pointer to the very first LyXParagraph
2258 LyXParagraph * LyXText::FirstParagraph() const
2260 return OwnerParagraph();
2264 // returns true if the specified string is at the specified position
2265 bool LyXText::IsStringInText(LyXParagraph * par,
2266 LyXParagraph::size_type pos,
2267 char const * str) const
2271 while (pos + i < par->Last() && str[i] &&
2272 str[i] == par->GetChar(pos + i)) {
2282 // sets the selection over the number of characters of string, no check!!
2283 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2285 sel_cursor = cursor;
2286 for (int i = 0; string[i]; ++i)
2288 SetSelection(bview);
2292 // simple replacing. The font of the first selected character is used
2293 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2295 SetCursorParUndo(bview->buffer());
2298 if (!selection) { // create a dummy selection
2299 sel_end_cursor = cursor;
2300 sel_start_cursor = cursor;
2303 // Get font setting before we cut
2304 LyXParagraph::size_type pos = sel_end_cursor.pos();
2305 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2306 sel_start_cursor.pos());
2308 // Insert the new string
2309 for (int i = 0; str[i]; ++i) {
2310 sel_end_cursor.par()->InsertChar(pos, str[i]);
2311 sel_end_cursor.par()->SetFont(pos, font);
2315 // Cut the selection
2316 CutSelection(bview);
2322 // if the string can be found: return true and set the cursor to
2324 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2326 LyXParagraph * par = cursor.par();
2327 LyXParagraph::size_type pos = cursor.pos();
2328 while (par && !IsStringInText(par, pos, str)) {
2329 if (pos < par->Last() - 1)
2337 SetCursor(bview, par, pos);
2345 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2347 LyXParagraph * par = cursor.par();
2348 int pos = cursor.pos();
2354 // We skip empty paragraphs (Asger)
2356 par = par->Previous();
2358 pos = par->Last() - 1;
2359 } while (par && pos < 0);
2361 } while (par && !IsStringInText(par, pos, string));
2364 SetCursor(bview, par, pos);
2371 // needed to insert the selection
2372 void LyXText::InsertStringA(BufferView * bview, string const & str)
2374 LyXParagraph * par = cursor.par();
2375 LyXParagraph::size_type pos = cursor.pos();
2376 LyXParagraph::size_type a = 0;
2378 LyXParagraph * endpar = cursor.par()->Next();
2380 SetCursorParUndo(bview->buffer());
2383 textclasslist.Style(bview->buffer()->params.textclass,
2384 cursor.par()->GetLayout()).isEnvironment();
2385 // only to be sure, should not be neccessary
2388 // insert the string, don't insert doublespace
2389 string::size_type i = 0;
2390 while (i < str.length()) {
2391 if (str[i] != '\n') {
2393 && i + 1 < str.length() && str[i + 1] != ' '
2394 && pos && par->GetChar(pos - 1)!= ' ') {
2395 par->InsertChar(pos,' ');
2396 par->SetFont(pos, current_font);
2399 } else if (par->table) {
2400 if (str[i] == '\t') {
2401 while((pos < par->size()) &&
2402 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2404 if (pos < par->size())
2406 else // no more fields to fill skip the rest
2408 } else if ((str[i] != 13) &&
2409 ((str[i] & 127) >= ' ')) {
2410 par->InsertChar(pos, str[i]);
2411 par->SetFont(pos, current_font);
2415 } else if (str[i] == ' ') {
2416 InsetSpecialChar * new_inset =
2417 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2418 if (par->InsertInsetAllowed(new_inset)) {
2419 par->InsertChar(pos, LyXParagraph::META_INSET);
2420 par->SetFont(pos, current_font);
2421 par->InsertInset(pos, new_inset);
2426 } else if (str[i] == '\t') {
2427 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2428 InsetSpecialChar * new_inset =
2429 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2430 if (par->InsertInsetAllowed(new_inset)) {
2431 par->InsertChar(pos, LyXParagraph::META_INSET);
2432 par->SetFont(pos, current_font);
2433 par->InsertInset(pos, new_inset);
2439 } else if (str[i] != 13 &&
2440 // Ignore unprintables
2441 (str[i] & 127) >= ' ') {
2442 par->InsertChar(pos, str[i]);
2443 par->SetFont(pos, current_font);
2449 if ((i + 1) >= str.length()) {
2450 if (pos < par->size())
2454 while((pos < par->size()) &&
2455 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2458 cell = NumberOfCell(par, pos);
2459 while((pos < par->size()) &&
2460 !(par->table->IsFirstCell(cell))) {
2462 while((pos < par->size()) &&
2463 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2466 cell = NumberOfCell(par, pos);
2468 if (pos >= par->size())
2469 // no more fields to fill skip the rest
2473 if (!par->size()) { // par is empty
2474 InsetSpecialChar * new_inset =
2475 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2476 if (par->InsertInsetAllowed(new_inset)) {
2477 par->InsertChar(pos, LyXParagraph::META_INSET);
2478 par->SetFont(pos, current_font);
2479 par->InsertInset(pos, new_inset);
2485 par->BreakParagraph(bview->buffer()->params, pos, flag);
2495 RedoParagraphs(bview, cursor, endpar);
2496 SetCursor(bview, cursor.par(), cursor.pos());
2497 sel_cursor = cursor;
2498 SetCursor(bview, par, pos);
2499 SetSelection(bview);
2503 /* turns double-CR to single CR, others where converted into one blank and 13s
2504 * that are ignored .Double spaces are also converted into one. Spaces at
2505 * the beginning of a paragraph are forbidden. tabs are converted into one
2506 * space. then InsertStringA is called */
2507 void LyXText::InsertStringB(BufferView * bview, string const & s)
2510 LyXParagraph * par = cursor.par();
2511 string::size_type i = 1;
2512 while (i < str.length()) {
2513 if (str[i] == '\t' && !par->table)
2515 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2517 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2518 if (str[i + 1] != '\n') {
2519 if (str[i - 1] != ' ')
2524 while (i + 1 < str.length()
2525 && (str[i + 1] == ' '
2526 || str[i + 1] == '\t'
2527 || str[i + 1] == '\n'
2528 || str[i + 1] == 13)) {
2535 InsertStringA(bview, str);
2539 bool LyXText::GotoNextError(BufferView * bview) const
2541 LyXCursor res = cursor;
2543 if (res.pos() < res.par()->Last() - 1) {
2544 res.pos(res.pos() + 1);
2546 res.par(res.par()->Next());
2550 } while (res.par() &&
2551 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2552 && res.par()->GetInset(res.pos())->AutoDelete()));
2555 SetCursor(bview, res.par(), res.pos());
2562 bool LyXText::GotoNextNote(BufferView * bview) const
2564 LyXCursor res = cursor;
2566 if (res.pos() < res.par()->Last() - 1) {
2567 res.pos(res.pos() + 1);
2569 res.par(res.par()->Next());
2573 } while (res.par() &&
2574 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2575 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2578 SetCursor(bview, res.par(), res.pos());
2585 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2586 LyXParagraph::size_type pos)
2588 LyXCursor tmpcursor;
2591 /* table stuff -- begin*/
2594 CheckParagraphInTable(bview, par, pos);
2598 /* table stuff -- end*/
2601 LyXParagraph::size_type z;
2602 Row * row = GetRow(par, pos, y);
2604 // is there a break one row above
2605 if (row->previous() && row->previous()->par() == row->par()) {
2606 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2607 if ( z >= row->pos()) {
2608 // set the dimensions of the row above
2609 y -= row->previous()->height();
2611 refresh_row = row->previous();
2612 status = LyXText::NEED_MORE_REFRESH;
2614 BreakAgain(bview, row->previous());
2616 // set the cursor again. Otherwise
2617 // dangling pointers are possible
2618 SetCursor(bview, cursor.par(), cursor.pos());
2619 sel_cursor = cursor;
2624 int tmpheight = row->height();
2625 LyXParagraph::size_type tmplast = RowLast(row);
2629 BreakAgain(bview, row);
2630 if (row->height() == tmpheight && RowLast(row) == tmplast)
2631 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2633 status = LyXText::NEED_MORE_REFRESH;
2635 // check the special right address boxes
2636 if (textclasslist.Style(bview->buffer()->params.textclass,
2637 par->GetLayout()).margintype
2638 == MARGIN_RIGHT_ADDRESS_BOX) {
2645 RedoDrawingOfParagraph(bview, tmpcursor);
2651 // set the cursor again. Otherwise dangling pointers are possible
2652 // also set the selection
2656 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2657 sel_cursor = cursor;
2658 SetCursorIntern(bview, sel_start_cursor.par(),
2659 sel_start_cursor.pos());
2660 sel_start_cursor = cursor;
2661 SetCursorIntern(bview, sel_end_cursor.par(),
2662 sel_end_cursor.pos());
2663 sel_end_cursor = cursor;
2664 SetCursorIntern(bview, last_sel_cursor.par(),
2665 last_sel_cursor.pos());
2666 last_sel_cursor = cursor;
2669 SetCursorIntern(bview, cursor.par(), cursor.pos());
2673 // returns 0 if inset wasn't found
2674 int LyXText::UpdateInset(BufferView * bview, Inset * inset)
2676 // first check the current paragraph
2677 int pos = cursor.par()->GetPositionOfInset(inset);
2679 CheckParagraph(bview, cursor.par(), pos);
2683 // check every paragraph
2685 LyXParagraph * par = FirstParagraph();
2687 // make sure the paragraph is open
2688 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2689 pos = par->GetPositionOfInset(inset);
2691 CheckParagraph(bview, par, pos);
2702 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2703 LyXParagraph::size_type pos,
2704 bool setfont, bool boundary) const
2706 LyXCursor old_cursor = cursor;
2707 SetCursorIntern(bview, par, pos, setfont, boundary);
2708 DeleteEmptyParagraphMechanism(bview, old_cursor);
2712 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2713 LyXParagraph::size_type pos, bool boundary) const
2715 // correct the cursor position if impossible
2716 if (pos > par->Last()){
2717 LyXParagraph * tmppar = par->ParFromPos(pos);
2718 pos = par->PositionInParFromPos(pos);
2721 if (par->IsDummy() && par->previous &&
2722 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2723 while (par->previous &&
2724 ((par->previous->IsDummy() &&
2725 (par->previous->previous->footnoteflag ==
2726 LyXParagraph::CLOSED_FOOTNOTE)) ||
2727 (par->previous->footnoteflag ==
2728 LyXParagraph::CLOSED_FOOTNOTE))) {
2729 par = par->previous ;
2730 if (par->IsDummy() &&
2731 (par->previous->footnoteflag ==
2732 LyXParagraph::CLOSED_FOOTNOTE))
2733 pos += par->size() + 1;
2735 if (par->previous) {
2736 par = par->previous;
2738 pos += par->size() + 1;
2743 cur.boundary(boundary);
2745 /* get the cursor y position in text */
2747 Row * row = GetRow(par, pos, y);
2748 /* y is now the beginning of the cursor row */
2749 y += row->baseline();
2750 /* y is now the cursor baseline */
2753 /* now get the cursors x position */
2755 float fill_separator, fill_hfill, fill_label_hfill;
2756 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2758 LyXParagraph::size_type cursor_vpos = 0;
2759 LyXParagraph::size_type last = RowLastPrintable(row);
2761 if (pos > last + 1) // This shouldn't happen.
2763 else if (pos < row->pos())
2766 if (last < row->pos())
2767 cursor_vpos = row->pos();
2768 else if (pos > last && !boundary)
2769 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2770 ? row->pos() : last + 1;
2771 else if (pos > row->pos() &&
2772 (pos > last || boundary ||
2773 (row->par()->table && row->par()->IsNewline(pos))))
2774 /// Place cursor after char at (logical) position pos - 1
2775 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2776 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2778 /// Place cursor before char at (logical) position pos
2779 cursor_vpos = (bidi_level(pos) % 2 == 0)
2780 ? log2vis(pos) : log2vis(pos) + 1;
2783 /* table stuff -- begin*/
2784 if (row->par()->table) {
2785 int cell = NumberOfCell(row->par(), row->pos());
2787 x += row->par()->table->GetBeginningOfTextInCell(cell);
2788 for (LyXParagraph::size_type vpos = row->pos();
2789 vpos < cursor_vpos; ++vpos) {
2790 pos = vis2log(vpos);
2791 if (row->par()->IsNewline(pos)) {
2792 x = x_old + row->par()->table->WidthOfColumn(cell);
2795 x += row->par()->table->GetBeginningOfTextInCell(cell);
2797 x += SingleWidth(bview, row->par(), pos);
2801 /* table stuff -- end*/
2803 LyXParagraph::size_type main_body =
2804 BeginningOfMainBody(bview->buffer(), row->par());
2805 if ((main_body > 0) &&
2806 ((main_body-1 > last) ||
2807 !row->par()->IsLineSeparator(main_body-1)))
2810 for (LyXParagraph::size_type vpos = row->pos();
2811 vpos < cursor_vpos; ++vpos) {
2812 pos = vis2log(vpos);
2813 if (main_body > 0 && pos == main_body-1) {
2814 x += fill_label_hfill +
2815 lyxfont::width(textclasslist.Style(
2816 bview->buffer()->params.textclass,
2817 row->par()->GetLayout())
2819 GetFont(bview->buffer(), row->par(), -2));
2820 if (row->par()->IsLineSeparator(main_body-1))
2821 x -= SingleWidth(bview, row->par(),main_body-1);
2823 if (HfillExpansion(bview->buffer(), row, pos)) {
2824 x += SingleWidth(bview, row->par(), pos);
2825 if (pos >= main_body)
2828 x += fill_label_hfill;
2829 } else if (row->par()->IsSeparator(pos)) {
2830 x += SingleWidth(bview, row->par(), pos);
2831 if (pos >= main_body)
2832 x += fill_separator;
2834 x += SingleWidth(bview, row->par(), pos);
2846 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2847 LyXParagraph::size_type pos,
2848 bool setfont, bool boundary) const
2850 SetCursor(bview, cursor, par, pos, boundary);
2851 // #warning Remove this when verified working (Jug 20000413)
2853 // correct the cursor position if impossible
2854 if (pos > par->Last()){
2855 LyXParagraph * tmppar = par->ParFromPos(pos);
2856 pos = par->PositionInParFromPos(pos);
2859 if (par->IsDummy() && par->previous &&
2860 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2861 while (par->previous &&
2862 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2863 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2864 par = par->previous ;
2865 if (par->IsDummy() &&
2866 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2867 pos += par->size() + 1;
2869 if (par->previous) {
2870 par = par->previous;
2872 pos += par->size() + 1;
2878 /* get the cursor y position in text */
2880 Row * row = GetRow(par, pos, y);
2881 /* y is now the beginning of the cursor row */
2882 y += row->baseline();
2883 /* y is now the cursor baseline */
2886 /* now get the cursors x position */
2888 float fill_separator, fill_hfill, fill_label_hfill;
2889 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2890 LyXParagraph::size_type cursor_vpos;
2891 LyXParagraph::size_type last = RowLastPrintable(row);
2893 if (pos > last + 1) // This shouldn't happen.
2896 if (last < row->pos())
2898 else if (pos > last ||
2899 (pos - 1 >= row->pos() &&
2900 (row->par()->IsSeparator(pos) ||
2901 (row->par()->table && row->par()->IsNewline(pos))
2903 /// Place cursor after char at (logical) position pos-1
2904 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2905 ? log2vis(pos-1) + 1 : log2vis(pos-1);
2907 /// Place cursor before char at (logical) position pos
2908 cursor_vpos = (bidi_level(pos) % 2 == 0)
2909 ? log2vis(pos) : log2vis(pos) + 1;
2912 /* table stuff -- begin*/
2913 if (row->par()->table) {
2914 int cell = NumberOfCell(row->par(), row->pos());
2916 x += row->par()->table->GetBeginningOfTextInCell(cell);
2917 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2918 pos = vis2log(vpos);
2919 if (row->par()->IsNewline(pos)) {
2920 x = x_old + row->par()->table->WidthOfColumn(cell);
2923 x += row->par()->table->GetBeginningOfTextInCell(cell);
2925 x += SingleWidth(row->par(), pos);
2929 /* table stuff -- end*/
2931 LyXParagraph::size_type main_body =
2932 BeginningOfMainBody(row->par());
2933 if (main_body > 0 &&
2934 (main_body-1 > last ||
2935 !row->par()->IsLineSeparator(main_body-1)))
2938 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
2939 pos = vis2log(vpos);
2940 if (main_body > 0 && pos == main_body-1) {
2941 x += fill_label_hfill +
2942 lyxfont::width(textclasslist
2943 .Style(bview->buffer()->params.textclass,
2944 row->par()->GetLayout())
2946 GetFont(row->par(), -2));
2947 if (row->par()->IsLineSeparator(main_body-1))
2948 x -= SingleWidth(row->par(), main_body-1);
2950 if (HfillExpansion(row, pos)) {
2951 x += SingleWidth(row->par(), pos);
2952 if (pos >= main_body)
2955 x += fill_label_hfill;
2957 else if (row->par()->IsSeparator(pos)) {
2958 x += SingleWidth(row->par(), pos);
2959 if (pos >= main_body)
2960 x += fill_separator;
2962 x += SingleWidth(row->par(), pos);
2969 cursor.x_fix = cursor.x;
2973 SetCurrentFont(bview);
2976 void LyXText::SetCurrentFont(BufferView * bview) const
2978 LyXParagraph::size_type pos = cursor.pos();
2979 if (cursor.boundary() && pos > 0)
2983 if (pos == cursor.par()->Last() ||
2984 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2986 else if (cursor.par()->IsSeparator(pos)) {
2987 if (pos > cursor.row()->pos() &&
2988 bidi_level(pos) % 2 ==
2989 bidi_level(pos - 1) % 2)
2991 else if (pos + 1 < cursor.par()->Last())
2996 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2997 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3001 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3003 LyXCursor old_cursor = cursor;
3005 /* get the row first */
3007 Row * row = GetRowNearY(y);
3008 cursor.par(row->par());
3011 int column = GetColumnNearX(bview, row, x, bound);
3012 cursor.pos(row->pos() + column);
3014 cursor.y(y + row->baseline());
3016 cursor.boundary(bound);
3017 SetCurrentFont(bview);
3018 DeleteEmptyParagraphMechanism(bview, old_cursor);
3022 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3023 int x, long y) const
3025 /* get the row first */
3027 Row * row = GetRowNearY(y);
3029 int column = GetColumnNearX(bview, row, x, bound);
3031 cur.par(row->par());
3032 cur.pos(row->pos() + column);
3034 cur.y(y + row->baseline());
3036 cur.boundary(bound);
3040 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3042 CursorLeftIntern(bview, internal);
3044 if (cursor.par()->table) {
3045 int cell = NumberOfCell(cursor.par(), cursor.pos());
3046 if (cursor.par()->table->IsContRow(cell)
3047 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3055 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3057 if (cursor.pos() > 0) {
3058 bool boundary = cursor.boundary();
3059 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3060 if (!internal && !boundary &&
3061 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3062 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3063 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3064 LyXParagraph * par = cursor.par()->Previous();
3065 LyXParagraph::size_type pos = par->Last();
3066 SetCursor(bview, par, pos);
3067 if (IsBoundary(bview->buffer(), par, pos))
3068 SetCursor(bview, par, pos, false, true);
3073 void LyXText::CursorRight(BufferView * bview, bool internal) const
3075 CursorRightIntern(bview, internal);
3077 if (cursor.par()->table) {
3078 int cell = NumberOfCell(cursor.par(), cursor.pos());
3079 if (cursor.par()->table->IsContRow(cell) &&
3080 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3088 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3090 if (cursor.pos() < cursor.par()->Last()) {
3091 if (!internal && cursor.boundary() &&
3092 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3093 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3095 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3096 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3097 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3099 } else if (cursor.par()->Next())
3100 SetCursor(bview, cursor.par()->Next(), 0);
3104 void LyXText::CursorUp(BufferView * bview) const
3106 SetCursorFromCoordinates(bview, cursor.x_fix(),
3107 cursor.y() - cursor.row()->baseline() - 1);
3109 if (cursor.par()->table) {
3110 int cell = NumberOfCell(cursor.par(), cursor.pos());
3111 if (cursor.par()->table->IsContRow(cell) &&
3112 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3120 void LyXText::CursorDown(BufferView * bview) const
3123 if (cursor.par()->table &&
3124 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3125 !cursor.par()->next)
3129 SetCursorFromCoordinates(bview, cursor.x_fix(),
3130 cursor.y() - cursor.row()->baseline()
3131 + cursor.row()->height() + 1);
3133 if (cursor.par()->table) {
3134 int cell = NumberOfCell(cursor.par(), cursor.pos());
3135 int cell_above = cursor.par()->table->GetCellAbove(cell);
3136 while(cursor.par()->table &&
3137 cursor.par()->table->IsContRow(cell) &&
3138 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3139 SetCursorFromCoordinates(bview, cursor.x_fix(),
3140 cursor.y() - cursor.row()->baseline()
3141 + cursor.row()->height() + 1);
3142 if (cursor.par()->table) {
3143 cell = NumberOfCell(cursor.par(), cursor.pos());
3144 cell_above = cursor.par()->table->GetCellAbove(cell);
3152 void LyXText::CursorUpParagraph(BufferView * bview) const
3154 if (cursor.pos() > 0) {
3155 SetCursor(bview, cursor.par(), 0);
3157 else if (cursor.par()->Previous()) {
3158 SetCursor(bview, cursor.par()->Previous(), 0);
3163 void LyXText::CursorDownParagraph(BufferView * bview) const
3165 if (cursor.par()->Next()) {
3166 SetCursor(bview, cursor.par()->Next(), 0);
3168 SetCursor(bview, cursor.par(), cursor.par()->Last());
3173 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3174 LyXCursor const & old_cursor) const
3176 // Would be wrong to delete anything if we have a selection.
3177 if (selection) return;
3179 // We allow all kinds of "mumbo-jumbo" when freespacing.
3180 if (textclasslist.Style(bview->buffer()->params.textclass,
3181 old_cursor.par()->GetLayout()).free_spacing)
3184 bool deleted = false;
3186 /* Ok I'll put some comments here about what is missing.
3187 I have fixed BackSpace (and thus Delete) to not delete
3188 double-spaces automagically. I have also changed Cut,
3189 Copy and Paste to hopefully do some sensible things.
3190 There are still some small problems that can lead to
3191 double spaces stored in the document file or space at
3192 the beginning of paragraphs. This happens if you have
3193 the cursor betwenn to spaces and then save. Or if you
3194 cut and paste and the selection have a space at the
3195 beginning and then save right after the paste. I am
3196 sure none of these are very hard to fix, but I will
3197 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3198 that I can get some feedback. (Lgb)
3201 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3202 // delete the LineSeparator.
3205 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3206 // delete the LineSeparator.
3209 // If the pos around the old_cursor were spaces, delete one of them.
3210 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3211 // Only if the cursor has really moved
3213 if (old_cursor.pos() > 0
3214 && old_cursor.pos() < old_cursor.par()->Last()
3215 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3216 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3217 old_cursor.par()->Erase(old_cursor.pos() - 1);
3218 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3220 if (old_cursor.par() == cursor.par() &&
3221 cursor.pos() > old_cursor.pos()) {
3222 SetCursorIntern(bview, cursor.par(),
3225 SetCursorIntern(bview, cursor.par(),
3231 // Do not delete empty paragraphs with keepempty set.
3232 if ((textclasslist.Style(bview->buffer()->params.textclass,
3233 old_cursor.par()->GetLayout())).keepempty)
3236 LyXCursor tmpcursor;
3238 if (old_cursor.par() != cursor.par()) {
3239 if ( (old_cursor.par()->Last() == 0
3240 || (old_cursor.par()->Last() == 1
3241 && old_cursor.par()->IsLineSeparator(0)))
3242 && old_cursor.par()->FirstPhysicalPar()
3243 == old_cursor.par()->LastPhysicalPar()) {
3244 // ok, we will delete anything
3246 // make sure that you do not delete any environments
3247 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3248 !(old_cursor.row()->previous()
3249 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3250 && !(old_cursor.row()->next()
3251 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3252 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3253 && ((old_cursor.row()->previous()
3254 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3255 || (old_cursor.row()->next()
3256 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3258 status = LyXText::NEED_MORE_REFRESH;
3261 if (old_cursor.row()->previous()) {
3262 refresh_row = old_cursor.row()->previous();
3263 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3265 cursor = old_cursor; // that undo can restore the right cursor position
3266 LyXParagraph * endpar = old_cursor.par()->next;
3267 if (endpar && endpar->GetDepth()) {
3268 while (endpar && endpar->GetDepth()) {
3269 endpar = endpar->LastPhysicalPar()->Next();
3272 SetUndo(bview->buffer(), Undo::DELETE,
3273 old_cursor.par()->previous,
3278 RemoveRow(old_cursor.row());
3279 if (OwnerParagraph() == old_cursor.par()) {
3280 OwnerParagraph(OwnerParagraph()->next);
3283 delete old_cursor.par();
3285 /* Breakagain the next par. Needed
3286 * because of the parindent that
3287 * can occur or dissappear. The
3288 * next row can change its height,
3289 * if there is another layout before */
3290 if (refresh_row->next()) {
3291 BreakAgain(bview, refresh_row->next());
3292 UpdateCounters(bview, refresh_row);
3294 SetHeightOfRow(bview, refresh_row);
3296 refresh_row = old_cursor.row()->next();
3297 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3300 cursor = old_cursor; // that undo can restore the right cursor position
3301 LyXParagraph * endpar = old_cursor.par()->next;
3302 if (endpar && endpar->GetDepth()) {
3303 while (endpar && endpar->GetDepth()) {
3304 endpar = endpar->LastPhysicalPar()->Next();
3307 SetUndo(bview->buffer(), Undo::DELETE,
3308 old_cursor.par()->previous,
3313 RemoveRow(old_cursor.row());
3315 if (OwnerParagraph() == old_cursor.par()) {
3316 OwnerParagraph(OwnerParagraph()->next);
3318 delete old_cursor.par();
3320 /* Breakagain the next par. Needed
3321 because of the parindent that can
3322 occur or dissappear.
3323 The next row can change its height,
3324 if there is another layout before
3327 BreakAgain(bview, refresh_row);
3328 UpdateCounters(bview, refresh_row->previous());
3334 SetCursorIntern(bview, cursor.par(), cursor.pos());
3336 if (sel_cursor.par() == old_cursor.par()
3337 && sel_cursor.pos() == sel_cursor.pos()) {
3338 // correct selection
3339 sel_cursor = cursor;
3344 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3345 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3347 SetCursorIntern(bview, cursor.par(), cursor.pos());
3348 sel_cursor = cursor;
3355 LyXParagraph * LyXText::GetParFromID(int id)
3357 LyXParagraph * result = FirstParagraph();
3358 while (result && result->id() != id)
3359 result = result->next;
3365 bool LyXText::TextUndo(BufferView * bview)
3367 // returns false if no undo possible
3368 Undo * undo = bview->buffer()->undostack.pop();
3372 bview->buffer()->redostack
3373 .push(CreateUndo(bview->buffer(), undo->kind,
3374 GetParFromID(undo->number_of_before_par),
3375 GetParFromID(undo->number_of_behind_par)));
3377 return TextHandleUndo(bview, undo);
3381 bool LyXText::TextRedo(BufferView * bview)
3383 // returns false if no redo possible
3384 Undo * undo = bview->buffer()->redostack.pop();
3388 bview->buffer()->undostack
3389 .push(CreateUndo(bview->buffer(), undo->kind,
3390 GetParFromID(undo->number_of_before_par),
3391 GetParFromID(undo->number_of_behind_par)));
3393 return TextHandleUndo(bview, undo);
3397 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3399 // returns false if no undo possible
3400 bool result = false;
3402 LyXParagraph * before =
3403 GetParFromID(undo->number_of_before_par);
3404 LyXParagraph * behind =
3405 GetParFromID(undo->number_of_behind_par);
3406 LyXParagraph * tmppar;
3407 LyXParagraph * tmppar2;
3408 LyXParagraph * endpar;
3409 LyXParagraph * tmppar5;
3411 // if there's no before take the beginning
3412 // of the document for redoing
3414 SetCursorIntern(bview, FirstParagraph(), 0);
3416 // replace the paragraphs with the undo informations
3418 LyXParagraph * tmppar3 = undo->par;
3419 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3420 LyXParagraph * tmppar4 = tmppar3;
3422 while (tmppar4->next)
3423 tmppar4 = tmppar4->next;
3424 } // get last undo par
3426 // now remove the old text if there is any
3427 if (before != behind || (!behind && !before)){
3429 tmppar5 = before->next;
3431 tmppar5 = OwnerParagraph();
3433 while (tmppar5 && tmppar5 != behind){
3435 tmppar5 = tmppar5->next;
3436 // a memory optimization for edit: Only layout information
3437 // is stored in the undo. So restore the text informations.
3438 if (undo->kind == Undo::EDIT) {
3439 tmppar2->setContentsFromPar(tmppar);
3440 tmppar->clearContents();
3441 tmppar2 = tmppar2->next;
3446 // put the new stuff in the list if there is one
3449 before->next = tmppar3;
3451 OwnerParagraph(tmppar3);
3452 tmppar3->previous = before;
3456 OwnerParagraph(behind);
3459 tmppar4->next = behind;
3461 behind->previous = tmppar4;
3465 // Set the cursor for redoing
3467 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3468 // check wether before points to a closed float and open it if necessary
3469 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3470 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3472 while (tmppar4->previous &&
3473 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3474 tmppar4 = tmppar4->previous;
3475 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3476 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3477 tmppar4 = tmppar4->next;
3482 // open a cosed footnote at the end if necessary
3483 if (behind && behind->previous &&
3484 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3485 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3486 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3487 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3488 behind = behind->next;
3492 // calculate the endpar for redoing the paragraphs.
3494 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3495 endpar = behind->LastPhysicalPar()->Next();
3497 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3501 tmppar = GetParFromID(undo->number_of_cursor_par);
3502 RedoParagraphs(bview, cursor, endpar);
3504 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3505 UpdateCounters(bview, cursor.row());
3515 void LyXText::FinishUndo()
3517 // makes sure the next operation will be stored
3518 undo_finished = true;
3522 void LyXText::FreezeUndo()
3524 // this is dangerous and for internal use only
3529 void LyXText::UnFreezeUndo()
3531 // this is dangerous and for internal use only
3532 undo_frozen = false;
3536 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3537 LyXParagraph const * before,
3538 LyXParagraph const * behind) const
3541 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3542 buf->redostack.clear();
3546 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3547 LyXParagraph const * before, LyXParagraph const * behind)
3549 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3553 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3554 LyXParagraph const * before,
3555 LyXParagraph const * behind) const
3557 int before_number = -1;
3558 int behind_number = -1;
3560 before_number = before->id();
3562 behind_number = behind->id();
3563 // Undo::EDIT and Undo::FINISH are
3564 // always finished. (no overlapping there)
3565 // overlapping only with insert and delete inside one paragraph:
3566 // Nobody wants all removed character
3567 // appear one by one when undoing.
3568 // EDIT is special since only layout information, not the
3569 // contents of a paragaph are stored.
3570 if (!undo_finished && kind != Undo::EDIT &&
3571 kind != Undo::FINISH){
3572 // check wether storing is needed
3573 if (!buf->undostack.empty() &&
3574 buf->undostack.top()->kind == kind &&
3575 buf->undostack.top()->number_of_before_par == before_number &&
3576 buf->undostack.top()->number_of_behind_par == behind_number ){
3581 // create a new Undo
3582 LyXParagraph * undopar;
3583 LyXParagraph * tmppar;
3584 LyXParagraph * tmppar2;
3586 LyXParagraph * start = 0;
3587 LyXParagraph * end = 0;
3590 start = before->next;
3592 start = FirstParagraph();
3594 end = behind->previous;
3596 end = FirstParagraph();
3602 && start != end->next
3603 && (before != behind || (!before && !behind))) {
3605 tmppar2 = tmppar->Clone();
3606 tmppar2->id(tmppar->id());
3608 // a memory optimization: Just store the layout information
3610 if (kind == Undo::EDIT){
3611 //tmppar2->text.clear();
3612 tmppar2->clearContents();
3617 while (tmppar != end && tmppar->next) {
3618 tmppar = tmppar->next;
3619 tmppar2->next = tmppar->Clone();
3620 tmppar2->next->id(tmppar->id());
3621 // a memory optimization: Just store the layout
3622 // information when only edit
3623 if (kind == Undo::EDIT){
3624 //tmppar2->next->text.clear();
3625 tmppar2->clearContents();
3627 tmppar2->next->previous = tmppar2;
3628 tmppar2 = tmppar2->next;
3632 undopar = 0; // nothing to replace (undo of delete maybe)
3634 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3635 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3637 Undo * undo = new Undo(kind,
3638 before_number, behind_number,
3639 cursor_par, cursor_pos,
3642 undo_finished = false;
3647 void LyXText::SetCursorParUndo(Buffer * buf)
3649 SetUndo(buf, Undo::FINISH,
3650 cursor.par()->ParFromPos(cursor.pos())->previous,
3651 cursor.par()->ParFromPos(cursor.pos())->next);
3656 void LyXText::RemoveTableRow(LyXCursor & cur) const
3662 // move to the previous row
3663 int cell_act = NumberOfCell(cur.par(), cur.pos());
3666 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3667 cur.pos(cur.pos() - 1);
3669 !cur.par()->table->IsFirstCell(cell_act)) {
3670 cur.pos(cur.pos() - 1);
3671 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3672 cur.pos(cur.pos() - 1);
3676 // now we have to pay attention if the actual table is the
3677 // main row of TableContRows and if yes to delete all of them
3682 // delete up to the next row
3683 while (cur.pos() < cur.par()->Last() &&
3685 || !cur.par()->table->IsFirstCell(cell_act))) {
3686 while (cur.pos() < cur.par()->Last() &&
3687 !cur.par()->IsNewline(cur.pos()))
3688 cur.par()->Erase(cur.pos());
3691 if (cur.pos() < cur.par()->Last())
3692 cur.par()->Erase(cur.pos());
3694 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3695 cur.pos(cur.pos() - 1);
3696 cur.par()->Erase(cur.pos()); // no newline at very end!
3698 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3699 !cur.par()->table->IsContRow(cell_org) &&
3700 cur.par()->table->IsContRow(cell));
3701 cur.par()->table->DeleteRow(cell_org);
3708 bool LyXText::IsEmptyTableCell() const
3710 LyXParagraph::size_type pos = cursor.pos() - 1;
3711 while (pos >= 0 && pos < cursor.par()->Last()
3712 && !cursor.par()->IsNewline(pos))
3714 return cursor.par()->IsNewline(pos + 1);
3719 void LyXText::toggleAppendix(BufferView * bview)
3721 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3722 bool start = !par->start_of_appendix;
3724 // ensure that we have only one start_of_appendix in this document
3725 LyXParagraph * tmp = FirstParagraph();
3726 for (; tmp; tmp = tmp->next)
3727 tmp->start_of_appendix = 0;
3728 par->start_of_appendix = start;
3730 // we can set the refreshing parameters now
3731 status = LyXText::NEED_MORE_REFRESH;
3733 refresh_row = 0; // not needed for full update
3734 UpdateCounters(bview, 0);
3735 SetCursor(bview, cursor.par(), cursor.pos());
3738 LyXParagraph * LyXText::OwnerParagraph() const
3741 return inset_owner->par;
3743 return bv_owner->buffer()->paragraph;
3747 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3750 inset_owner->par = p;
3752 bv_owner->buffer()->paragraph = p;