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())
1115 // Stuff what we got on the clipboard. Even if there is no selection.
1117 // There is a problem with having the stuffing here in that the
1118 // larger the selection the slower LyX will get. This can be
1119 // solved by running the line below only when the selection has
1120 // finished. The solution used currently just works, to make it
1121 // faster we need to be more clever and probably also have more
1122 // calls to stuffClipboard. (Lgb)
1123 bview->stuffClipboard(selectionAsString(bview->buffer()));
1127 string LyXText::selectionAsString(Buffer const * buffer) const
1129 if (!selection) return string();
1132 // Special handling if the whole selection is within one paragraph
1133 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1134 result += sel_start_cursor.par()->String(buffer,
1135 sel_start_cursor.pos(),
1136 sel_end_cursor.pos());
1140 // The selection spans more than one paragraph
1142 // First paragraph in selection
1143 result += sel_start_cursor.par()->String(buffer,
1144 sel_start_cursor.pos(),
1145 sel_start_cursor.par()->Last())
1148 // The paragraphs in between (if any)
1149 LyXCursor tmpcur(sel_start_cursor);
1150 tmpcur.par(tmpcur.par()->Next());
1151 while (tmpcur.par() != sel_end_cursor.par()) {
1152 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1153 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1156 // Last paragraph in selection
1157 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1163 void LyXText::ClearSelection() const
1170 void LyXText::CursorHome(BufferView * bview) const
1172 SetCursor(bview, cursor.par(), cursor.row()->pos());
1176 void LyXText::CursorEnd(BufferView * bview) const
1178 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1179 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1181 if (cursor.par()->Last() &&
1182 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1183 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1184 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1186 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1189 if (cursor.par()->table) {
1190 int cell = NumberOfCell(cursor.par(), cursor.pos());
1191 if (cursor.par()->table->RowHasContRow(cell) &&
1192 cursor.par()->table->CellHasContRow(cell)<0) {
1193 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1194 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1196 if (cursor.par()->Last() &&
1197 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1198 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1199 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1201 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1209 void LyXText::CursorTop(BufferView * bview) const
1211 while (cursor.par()->Previous())
1212 cursor.par(cursor.par()->Previous());
1213 SetCursor(bview, cursor.par(), 0);
1217 void LyXText::CursorBottom(BufferView * bview) const
1219 while (cursor.par()->Next())
1220 cursor.par(cursor.par()->Next());
1221 SetCursor(bview, cursor.par(), cursor.par()->Last());
1225 /* returns a pointer to the row near the specified y-coordinate
1226 * (relative to the whole text). y is set to the real beginning
1228 Row * LyXText::GetRowNearY(long & y) const
1230 Row * tmprow = firstrow;
1233 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1234 tmpy += tmprow->height();
1235 tmprow = tmprow->next();
1238 y = tmpy; // return the real y
1243 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1245 // If the mask is completely neutral, tell user
1246 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1247 // Could only happen with user style
1248 bview->owner()->getMiniBuffer()
1249 ->Set(_("No font change defined. Use Character under"
1250 " the Layout menu to define font change."));
1254 // Try implicit word selection
1255 // If there is a change in the language the implicit word selection
1257 LyXCursor resetCursor = cursor;
1258 bool implicitSelection = (font.language() == ignore_language)
1259 ? SelectWordWhenUnderCursor(bview) : false;
1262 SetFont(bview, font, toggleall);
1264 /* Implicit selections are cleared afterwards and cursor is set to the
1265 original position. */
1266 if (implicitSelection) {
1268 cursor = resetCursor;
1269 SetCursor(bview, cursor.par(), cursor.pos());
1270 sel_cursor = cursor;
1275 LyXParagraph::size_type
1276 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1278 if (textclasslist.Style(buf->params.textclass,
1279 par->GetLayout()).labeltype != LABEL_MANUAL)
1282 return par->BeginningOfMainBody();
1286 /* if there is a selection, reset every environment you can find
1287 * in the selection, otherwise just the environment you are in */
1288 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1290 LyXParagraph * tmppar, * firsttmppar;
1294 /* is is only allowed, if the cursor is IN an open footnote.
1295 * Otherwise it is too dangerous */
1296 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1299 SetUndo(bview->buffer(), Undo::FINISH,
1300 cursor.par()->PreviousBeforeFootnote()->previous,
1301 cursor.par()->NextAfterFootnote()->next);
1303 /* ok, move to the beginning of the footnote. */
1304 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1305 cursor.par(cursor.par()->Previous());
1307 SetCursor(bview, cursor.par(), cursor.par()->Last());
1308 /* this is just faster than using CursorLeft(); */
1310 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1311 tmppar = firsttmppar;
1312 /* tmppar is now the paragraph right before the footnote */
1314 bool first_footnote_par_is_not_empty = tmppar->next->size();
1317 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1318 tmppar = tmppar->next; /* I use next instead of Next(),
1319 * because there cannot be any
1320 * footnotes in a footnote
1322 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1324 /* remember the captions and empty paragraphs */
1325 if ((textclasslist.Style(bview->buffer()->params.textclass,
1326 tmppar->GetLayout())
1327 .labeltype == LABEL_SENSITIVE)
1329 tmppar->SetLayout(bview->buffer()->params, 0);
1332 // now we will paste the ex-footnote, if the layouts allow it
1333 // first restore the layout of the paragraph right behind
1336 tmppar->next->MakeSameLayout(cursor.par());
1339 if ((!tmppar->GetLayout() && !tmppar->table)
1341 && (!tmppar->Next()->Last()
1342 || tmppar->Next()->HasSameLayout(tmppar)))) {
1343 if (tmppar->Next()->Last()
1344 && tmppar->Next()->IsLineSeparator(0))
1345 tmppar->Next()->Erase(0);
1346 tmppar->PasteParagraph(bview->buffer()->params);
1349 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1350 * by the pasting of the beginning */
1352 /* then the beginning */
1353 /* if there is no space between the text and the footnote, so we insert
1355 * (only if the previous par and the footnotepar are not empty!) */
1356 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1357 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1358 if (firsttmppar->size()
1359 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1360 && first_footnote_par_is_not_empty) {
1361 firsttmppar->next->InsertChar(0, ' ');
1363 firsttmppar->PasteParagraph(bview->buffer()->params);
1366 /* now redo the paragaphs */
1367 RedoParagraphs(bview, cursor, tmppar);
1369 SetCursor(bview, cursor.par(), cursor.pos());
1371 /* sometimes it can happen, that there is a counter change */
1372 Row * row = cursor.row();
1373 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1375 UpdateCounters(bview, row);
1382 /* the DTP switches for paragraphs. LyX will store them in the
1383 * first physicla paragraph. When a paragraph is broken, the top settings
1384 * rest, the bottom settings are given to the new one. So I can make shure,
1385 * they do not duplicate themself and you cannnot make dirty things with
1388 void LyXText::SetParagraph(BufferView * bview,
1389 bool line_top, bool line_bottom,
1390 bool pagebreak_top, bool pagebreak_bottom,
1391 VSpace const & space_top,
1392 VSpace const & space_bottom,
1394 string labelwidthstring,
1397 LyXCursor tmpcursor = cursor;
1399 sel_start_cursor = cursor;
1400 sel_end_cursor = cursor;
1403 // make sure that the depth behind the selection are restored, too
1404 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1405 LyXParagraph * undoendpar = endpar;
1407 if (endpar && endpar->GetDepth()) {
1408 while (endpar && endpar->GetDepth()) {
1409 endpar = endpar->LastPhysicalPar()->Next();
1410 undoendpar = endpar;
1414 endpar = endpar->Next(); // because of parindents etc.
1417 SetUndo(bview->buffer(), Undo::EDIT,
1419 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1423 LyXParagraph * tmppar = sel_end_cursor.par();
1424 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1425 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1426 status = LyXText::NEED_MORE_REFRESH;
1427 refresh_row = cursor.row();
1428 refresh_y = cursor.y() - cursor.row()->baseline();
1429 if (cursor.par()->footnoteflag ==
1430 sel_start_cursor.par()->footnoteflag) {
1431 cursor.par()->line_top = line_top;
1432 cursor.par()->line_bottom = line_bottom;
1433 cursor.par()->pagebreak_top = pagebreak_top;
1434 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1435 cursor.par()->added_space_top = space_top;
1436 cursor.par()->added_space_bottom = space_bottom;
1437 // does the layout allow the new alignment?
1438 if (align == LYX_ALIGN_LAYOUT)
1439 align = textclasslist
1440 .Style(bview->buffer()->params.textclass,
1441 cursor.par()->GetLayout()).align;
1442 if (align & textclasslist
1443 .Style(bview->buffer()->params.textclass,
1444 cursor.par()->GetLayout()).alignpossible) {
1445 if (align == textclasslist
1446 .Style(bview->buffer()->params.textclass,
1447 cursor.par()->GetLayout()).align)
1448 cursor.par()->align = LYX_ALIGN_LAYOUT;
1450 cursor.par()->align = align;
1452 cursor.par()->SetLabelWidthString(labelwidthstring);
1453 cursor.par()->noindent = noindent;
1456 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1459 RedoParagraphs(bview, sel_start_cursor, endpar);
1462 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1463 sel_cursor = cursor;
1464 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1465 SetSelection(bview);
1466 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1470 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1472 char const * widthp,
1473 int alignment, bool hfill,
1474 bool start_minipage)
1476 LyXCursor tmpcursor = cursor;
1477 LyXParagraph * tmppar;
1479 sel_start_cursor = cursor;
1480 sel_end_cursor = cursor;
1483 // make sure that the depth behind the selection are restored, too
1484 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1485 LyXParagraph * undoendpar = endpar;
1487 if (endpar && endpar->GetDepth()) {
1488 while (endpar && endpar->GetDepth()) {
1489 endpar = endpar->LastPhysicalPar()->Next();
1490 undoendpar = endpar;
1494 endpar = endpar->Next(); // because of parindents etc.
1497 SetUndo(bview->buffer(), Undo::EDIT,
1499 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1502 tmppar = sel_end_cursor.par();
1503 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1504 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1505 status = LyXText::NEED_MORE_REFRESH;
1506 refresh_row = cursor.row();
1507 refresh_y = cursor.y() - cursor.row()->baseline();
1508 if (cursor.par()->footnoteflag ==
1509 sel_start_cursor.par()->footnoteflag) {
1510 if (type == LyXParagraph::PEXTRA_NONE) {
1511 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1512 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1513 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1516 cursor.par()->SetPExtraType(bview->buffer()->params,
1517 type, width, widthp);
1518 cursor.par()->pextra_hfill = hfill;
1519 cursor.par()->pextra_start_minipage = start_minipage;
1520 cursor.par()->pextra_alignment = alignment;
1523 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1525 RedoParagraphs(bview, sel_start_cursor, endpar);
1527 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1528 sel_cursor = cursor;
1529 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1530 SetSelection(bview);
1531 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1535 char loweralphaCounter(int n)
1537 if (n < 1 || n > 26)
1543 char alphaCounter(int n)
1545 if (n < 1 || n > 26)
1551 char hebrewCounter(int n)
1553 static const char hebrew[22] = {
1554 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1555 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1556 '÷', 'ø', 'ù', 'ú'
1558 if (n < 1 || n > 22)
1564 static char const * romanCounter(int n)
1566 static char const * roman[20] = {
1567 "i", "ii", "iii", "iv", "v",
1568 "vi", "vii", "viii", "ix", "x",
1569 "xi", "xii", "xiii", "xiv", "xv",
1570 "xvi", "xvii", "xviii", "xix", "xx"
1572 if (n < 1 || n > 20)
1578 // set the counter of a paragraph. This includes the labels
1579 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1581 // this is only relevant for the beginning of paragraph
1582 par = par->FirstPhysicalPar();
1584 LyXLayout const & layout =
1585 textclasslist.Style(buf->params.textclass,
1588 LyXTextClass const & textclass =
1589 textclasslist.TextClass(buf->params.textclass);
1591 /* copy the prev-counters to this one, unless this is the start of a
1592 footnote or of a bibliography or the very first paragraph */
1594 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1595 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1596 && par->footnotekind == LyXParagraph::FOOTNOTE)
1597 && !(textclasslist.Style(buf->params.textclass,
1598 par->Previous()->GetLayout()
1599 ).labeltype != LABEL_BIBLIO
1600 && layout.labeltype == LABEL_BIBLIO)) {
1601 for (int i = 0; i < 10; ++i) {
1602 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1604 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1605 if (!par->appendix && par->start_of_appendix){
1606 par->appendix = true;
1607 for (int i = 0; i < 10; ++i) {
1608 par->setCounter(i, 0);
1611 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1612 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1615 for (int i = 0; i < 10; ++i) {
1616 par->setCounter(i, 0);
1618 par->appendix = par->start_of_appendix;
1623 // if this is an open marginnote and this is the first
1624 // entry in the marginnote and the enclosing
1625 // environment is an enum/item then correct for the
1626 // LaTeX behaviour (ARRae)
1627 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1628 && par->footnotekind == LyXParagraph::MARGIN
1630 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1631 && (par->PreviousBeforeFootnote()
1632 && textclasslist.Style(buf->params.textclass,
1633 par->PreviousBeforeFootnote()->GetLayout()
1634 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1635 // Any itemize or enumerate environment in a marginnote
1636 // that is embedded in an itemize or enumerate
1637 // paragraph is seen by LaTeX as being at a deeper
1638 // level within that enclosing itemization/enumeration
1639 // even if there is a "standard" layout at the start of
1645 /* Maybe we have to increment the enumeration depth.
1646 * BUT, enumeration in a footnote is considered in isolation from its
1647 * surrounding paragraph so don't increment if this is the
1648 * first line of the footnote
1649 * AND, bibliographies can't have their depth changed ie. they
1650 * are always of depth 0
1653 && par->Previous()->GetDepth() < par->GetDepth()
1654 && textclasslist.Style(buf->params.textclass,
1655 par->Previous()->GetLayout()
1656 ).labeltype == LABEL_COUNTER_ENUMI
1657 && par->enumdepth < 3
1658 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1659 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1660 && par->footnotekind == LyXParagraph::FOOTNOTE)
1661 && layout.labeltype != LABEL_BIBLIO) {
1665 /* Maybe we have to decrement the enumeration depth, see note above */
1667 && par->Previous()->GetDepth() > par->GetDepth()
1668 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1669 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1670 && par->footnotekind == LyXParagraph::FOOTNOTE)
1671 && layout.labeltype != LABEL_BIBLIO) {
1672 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1673 par->setCounter(6 + par->enumdepth,
1674 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1675 /* reset the counters.
1676 * A depth change is like a breaking layout
1678 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1679 par->setCounter(i, 0);
1682 if (!par->labelstring.empty()) {
1683 par->labelstring.erase();
1686 if (layout.margintype == MARGIN_MANUAL) {
1687 if (par->labelwidthstring.empty()) {
1688 par->SetLabelWidthString(layout.labelstring());
1691 par->SetLabelWidthString(string());
1694 /* is it a layout that has an automatic label ? */
1695 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1697 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1698 if (i >= 0 && i<= buf->params.secnumdepth) {
1699 par->incCounter(i); // increment the counter
1701 // Is there a label? Useful for Chapter layout
1702 if (!par->appendix){
1703 if (!layout.labelstring().empty())
1704 par->labelstring = layout.labelstring();
1706 par->labelstring.erase();
1708 if (!layout.labelstring_appendix().empty())
1709 par->labelstring = layout.labelstring_appendix();
1711 par->labelstring.erase();
1715 std::ostringstream s;
1719 if (!par->appendix) {
1720 switch (2 * LABEL_FIRST_COUNTER -
1721 textclass.maxcounter() + i) {
1722 case LABEL_COUNTER_CHAPTER:
1723 s << par->getCounter(i);
1725 case LABEL_COUNTER_SECTION:
1726 s << par->getCounter(i - 1) << '.'
1727 << par->getCounter(i);
1729 case LABEL_COUNTER_SUBSECTION:
1730 s << par->getCounter(i - 2) << '.'
1731 << par->getCounter(i - 1) << '.'
1732 << par->getCounter(i);
1734 case LABEL_COUNTER_SUBSUBSECTION:
1735 s << par->getCounter(i - 3) << '.'
1736 << par->getCounter(i - 2) << '.'
1737 << par->getCounter(i - 1) << '.'
1738 << par->getCounter(i);
1741 case LABEL_COUNTER_PARAGRAPH:
1742 s << par->getCounter(i - 4) << '.'
1743 << par->getCounter(i - 3) << '.'
1744 << par->getCounter(i - 2) << '.'
1745 << par->getCounter(i - 1) << '.'
1746 << par->getCounter(i);
1748 case LABEL_COUNTER_SUBPARAGRAPH:
1749 s << par->getCounter(i - 5) << '.'
1750 << par->getCounter(i - 4) << '.'
1751 << par->getCounter(i - 3) << '.'
1752 << par->getCounter(i - 2) << '.'
1753 << par->getCounter(i - 1) << '.'
1754 << par->getCounter(i);
1758 s << par->getCounter(i) << '.';
1761 } else { // appendix
1762 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1763 case LABEL_COUNTER_CHAPTER:
1764 if (par->isRightToLeftPar(buf->params))
1765 s << hebrewCounter(par->getCounter(i));
1767 s << alphaCounter(par->getCounter(i));
1769 case LABEL_COUNTER_SECTION:
1770 if (par->isRightToLeftPar(buf->params))
1771 s << hebrewCounter(par->getCounter(i - 1));
1773 s << alphaCounter(par->getCounter(i - 1));
1776 << par->getCounter(i);
1779 case LABEL_COUNTER_SUBSECTION:
1780 if (par->isRightToLeftPar(buf->params))
1781 s << hebrewCounter(par->getCounter(i - 2));
1783 s << alphaCounter(par->getCounter(i - 2));
1786 << par->getCounter(i-1) << '.'
1787 << par->getCounter(i);
1790 case LABEL_COUNTER_SUBSUBSECTION:
1791 if (par->isRightToLeftPar(buf->params))
1792 s << hebrewCounter(par->getCounter(i-3));
1794 s << alphaCounter(par->getCounter(i-3));
1797 << par->getCounter(i-2) << '.'
1798 << par->getCounter(i-1) << '.'
1799 << par->getCounter(i);
1802 case LABEL_COUNTER_PARAGRAPH:
1803 if (par->isRightToLeftPar(buf->params))
1804 s << hebrewCounter(par->getCounter(i-4));
1806 s << alphaCounter(par->getCounter(i-4));
1809 << par->getCounter(i-3) << '.'
1810 << par->getCounter(i-2) << '.'
1811 << par->getCounter(i-1) << '.'
1812 << par->getCounter(i);
1815 case LABEL_COUNTER_SUBPARAGRAPH:
1816 if (par->isRightToLeftPar(buf->params))
1817 s << hebrewCounter(par->getCounter(i-5));
1819 s << alphaCounter(par->getCounter(i-5));
1822 << par->getCounter(i-4) << '.'
1823 << par->getCounter(i-3) << '.'
1824 << par->getCounter(i-2) << '.'
1825 << par->getCounter(i-1) << '.'
1826 << par->getCounter(i);
1830 // Can this ever be reached? And in the
1831 // case it is, how can this be correct?
1833 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1839 par->labelstring += s.str().c_str();
1840 // We really want to remove the c_str as soon as
1844 char * tmps = s.str();
1845 par->labelstring += tmps;
1849 for (i++; i < 10; ++i) {
1850 // reset the following counters
1851 par->setCounter(i, 0);
1853 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1854 for (i++; i < 10; ++i) {
1855 // reset the following counters
1856 par->setCounter(i, 0);
1858 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1859 par->incCounter(i + par->enumdepth);
1860 int number = par->getCounter(i + par->enumdepth);
1863 std::ostringstream s;
1867 switch (par->enumdepth) {
1869 if (par->isRightToLeftPar(buf->params))
1871 << hebrewCounter(number)
1875 << loweralphaCounter(number)
1879 if (par->isRightToLeftPar(buf->params))
1880 s << '.' << romanCounter(number);
1882 s << romanCounter(number) << '.';
1885 if (par->isRightToLeftPar(buf->params))
1887 << alphaCounter(number);
1889 s << alphaCounter(number)
1893 if (par->isRightToLeftPar(buf->params))
1900 par->labelstring = s.str().c_str();
1901 // we really want to get rid of that c_str()
1904 char * tmps = s.str();
1905 par->labelstring = tmps;
1909 for (i += par->enumdepth + 1; i < 10; ++i)
1910 par->setCounter(i, 0); /* reset the following counters */
1913 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1914 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1916 int number = par->getCounter(i);
1918 par->bibkey = new InsetBibKey();
1919 par->bibkey->setCounter(number);
1920 par->labelstring = layout.labelstring();
1922 // In biblio should't be following counters but...
1924 string s = layout.labelstring();
1926 // the caption hack:
1928 if (layout.labeltype == LABEL_SENSITIVE) {
1929 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1930 && (par->footnotekind == LyXParagraph::FIG
1931 || par->footnotekind == LyXParagraph::WIDE_FIG))
1932 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1933 ? ":øåéà " : "Figure:";
1934 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1935 && (par->footnotekind == LyXParagraph::TAB
1936 || par->footnotekind == LyXParagraph::WIDE_TAB))
1937 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1938 ? ":äìáè" : "Table:";
1939 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1940 && par->footnotekind == LyXParagraph::ALGORITHM)
1941 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1942 ? ":Ãúéøåâìà " : "Algorithm:";
1944 /* par->SetLayout(0);
1945 s = layout->labelstring; */
1946 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1947 ? " :úåòîùî øñç" : "Senseless: ";
1950 par->labelstring = s;
1952 /* reset the enumeration counter. They are always resetted
1953 * when there is any other layout between */
1954 for (int i = 6 + par->enumdepth; i < 10; ++i)
1955 par->setCounter(i, 0);
1960 /* Updates all counters BEHIND the row. Changed paragraphs
1961 * with a dynamic left margin will be rebroken. */
1962 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1970 if (row->par()->next
1971 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1972 par = row->par()->LastPhysicalPar()->Next();
1974 par = row->par()->next;
1979 while (row->par() != par)
1982 SetCounter(bview->buffer(), par);
1984 /* now check for the headline layouts. remember that they
1985 * have a dynamic left margin */
1987 && ( textclasslist.Style(bview->buffer()->params.textclass,
1988 par->layout).margintype == MARGIN_DYNAMIC
1989 || textclasslist.Style(bview->buffer()->params.textclass,
1990 par->layout).labeltype == LABEL_SENSITIVE)
1993 /* Rebreak the paragraph */
1994 RemoveParagraph(row);
1995 AppendParagraph(bview, row);
1997 /* think about the damned open footnotes! */
1998 while (par->Next() &&
1999 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2000 || par->Next()->IsDummy())){
2002 if (par->IsDummy()) {
2003 while (row->par() != par)
2005 RemoveParagraph(row);
2006 AppendParagraph(bview, row);
2011 par = par->LastPhysicalPar()->Next();
2017 /* insets an inset. */
2018 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2020 if (!cursor.par()->InsertInsetAllowed(inset))
2022 SetUndo(bview->buffer(), Undo::INSERT,
2023 cursor.par()->ParFromPos(cursor.pos())->previous,
2024 cursor.par()->ParFromPos(cursor.pos())->next);
2025 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2026 cursor.par()->InsertInset(cursor.pos(), inset);
2027 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2028 * The character will not be inserted a
2033 #ifdef USE_OLD_CUT_AND_PASTE
2034 // this is for the simple cut and paste mechanism
2035 static LyXParagraph * simple_cut_buffer = 0;
2036 static char simple_cut_buffer_textclass = 0;
2038 void DeleteSimpleCutBuffer()
2040 if (!simple_cut_buffer)
2042 LyXParagraph * tmppar;
2044 while (simple_cut_buffer) {
2045 tmppar = simple_cut_buffer;
2046 simple_cut_buffer = simple_cut_buffer()->next;
2049 simple_cut_buffer = 0;
2053 void LyXText::copyEnvironmentType()
2055 copylayouttype = cursor.par()->GetLayout();
2059 void LyXText::pasteEnvironmentType(BufferView * bview)
2061 SetLayout(bview, copylayouttype);
2064 #ifdef USE_OLD_CUT_AND_PASTE
2065 void LyXText::CutSelection(Buffer const * buf, bool doclear)
2067 // This doesn't make sense, if there is no selection
2071 // OK, we have a selection. This is always between sel_start_cursor
2072 // and sel_end cursor
2073 LyXParagraph * tmppar;
2075 // Check whether there are half footnotes in the selection
2076 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2077 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2078 tmppar = sel_start_cursor.par();
2079 while (tmppar != sel_end_cursor.par()){
2080 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2081 WriteAlert(_("Impossible operation"),
2082 _("Don't know what to do with half floats."),
2086 tmppar = tmppar->Next();
2091 /* table stuff -- begin */
2092 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2093 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2094 WriteAlert(_("Impossible operation"),
2095 _("Don't know what to do with half tables."),
2099 sel_start_cursor.par()->table->Reinit();
2101 /* table stuff -- end */
2104 // make sure that the depth behind the selection are restored, too
2105 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2106 LyXParagraph * undoendpar = endpar;
2108 if (endpar && endpar->GetDepth()) {
2109 while (endpar && endpar->GetDepth()) {
2110 endpar = endpar->LastPhysicalPar()->Next();
2111 undoendpar = endpar;
2113 } else if (endpar) {
2114 endpar = endpar->Next(); // because of parindents etc.
2117 SetUndo(bview->buffer(), Undo::DELETE,
2119 .par->ParFromPos(sel_start_cursor.pos())->previous,
2122 // clear the simple_cut_buffer
2123 DeleteSimpleCutBuffer();
2125 // set the textclass
2126 simple_cut_buffer_textclass = buf->params.textclass;
2128 #ifdef WITH_WARNINGS
2129 #warning Asger: Make cut more intelligent here.
2132 White paper for "intelligent" cutting:
2134 Example: "This is our text."
2135 Using " our " as selection, cutting will give "This istext.".
2136 Using "our" as selection, cutting will give "This is text.".
2137 Using " our" as selection, cutting will give "This is text.".
2138 Using "our " as selection, cutting will give "This is text.".
2140 All those four selections will (however) paste identically:
2141 Pasting with the cursor right after the "is" will give the
2142 original text with all four selections.
2144 The rationale is to be intelligent such that words are copied,
2145 cut and pasted in a functional manner.
2147 This is not implemented yet. (Asger)
2149 The changes below sees to do a lot of what you want. However
2150 I have not verified that all cases work as they should:
2152 - cut in multiple row
2154 - cut across footnotes and paragraph
2155 My simplistic tests show that the idea are basically sound but
2156 there are some items to fix up...we only need to find them
2159 As do redo Asger's example above (with | beeing the cursor in the
2160 result after cutting.):
2162 Example: "This is our text."
2163 Using " our " as selection, cutting will give "This is|text.".
2164 Using "our" as selection, cutting will give "This is | text.".
2165 Using " our" as selection, cutting will give "This is| text.".
2166 Using "our " as selection, cutting will give "This is |text.".
2171 // there are two cases: cut only within one paragraph or
2172 // more than one paragraph
2174 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2175 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2176 // only within one paragraph
2177 simple_cut_buffer = new LyXParagraph;
2178 LyXParagraph::size_type i =
2179 sel_start_cursor.pos();
2180 for (; i < sel_end_cursor.pos(); ++i) {
2182 /* table stuff -- begin */
2183 if (sel_start_cursor.par()->table
2184 && sel_start_cursor.par()->IsNewline(sel_start_cursor.pos())) {
2185 sel_start_cursor.par()->CopyIntoMinibuffer(sel_start_cursor.pos());
2186 sel_start_cursor.pos()++;
2188 /* table stuff -- end */
2190 sel_start_cursor.par()->CopyIntoMinibuffer(sel_start_cursor.pos());
2191 sel_start_cursor.par()->Erase(sel_start_cursor.pos());
2195 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2197 endpar = sel_end_cursor.par()->Next();
2199 // cut more than one paragraph
2201 sel_end_cursor.par()
2202 ->BreakParagraphConservative(sel_end_cursor.pos());
2203 sel_end_cursor.par() = sel_end_cursor.par()->Next();
2204 sel_end_cursor.pos() = 0;
2206 cursor = sel_end_cursor;
2208 sel_start_cursor.par()
2209 ->BreakParagraphConservative(sel_start_cursor.pos());
2210 // store the endparagraph for redoing later
2211 endpar = sel_end_cursor.par()->Next(); /* needed because
2216 // store the selection
2217 simple_cut_buffer = sel_start_cursor.par()
2218 ->ParFromPos(sel_start_cursor.pos())->next;
2219 simple_cut_buffer->previous = 0;
2220 sel_end_cursor.par()->previous->next = 0;
2222 // cut the selection
2223 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->next
2224 = sel_end_cursor.par();
2226 sel_end_cursor.par()->previous
2227 = sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos());
2229 // care about footnotes
2230 if (simple_cut_buffer->footnoteflag) {
2231 LyXParagraph * tmppar = simple_cut_buffer;
2233 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2234 tmppar = tmppar->next;
2238 // the cut selection should begin with standard layout
2239 simple_cut_buffer->Clear();
2241 // paste the paragraphs again, if possible
2243 sel_start_cursor.par()->Next()->StripLeadingSpaces(simple_cut_buffer_textclass);
2244 if (sel_start_cursor.par()->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par()->Next())
2246 !sel_start_cursor.par()->Next()->Last())
2247 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->PasteParagraph();
2250 // sometimes necessary
2252 sel_start_cursor.par()->StripLeadingSpaces(simple_cut_buffer_textclass);
2254 RedoParagraphs(sel_start_cursor, endpar);
2257 cursor = sel_start_cursor;
2258 SetCursor(cursor.par(), cursor.pos());
2259 sel_cursor = cursor;
2260 UpdateCounters(cursor.row());
2263 #else ///////////////////////////////////////////////////////////////////
2265 void LyXText::CutSelection(BufferView * bview, bool doclear)
2267 // This doesn't make sense, if there is no selection
2271 // OK, we have a selection. This is always between sel_start_cursor
2272 // and sel_end cursor
2273 LyXParagraph * tmppar;
2275 // Check whether there are half footnotes in the selection
2276 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2277 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2278 tmppar = sel_start_cursor.par();
2279 while (tmppar != sel_end_cursor.par()){
2280 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2281 WriteAlert(_("Impossible operation"),
2282 _("Don't know what to do with half floats."),
2286 tmppar = tmppar->Next();
2291 /* table stuff -- begin */
2292 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2293 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2294 WriteAlert(_("Impossible operation"),
2295 _("Don't know what to do with half tables."),
2299 sel_start_cursor.par()->table->Reinit();
2301 /* table stuff -- end */
2304 // make sure that the depth behind the selection are restored, too
2305 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2306 LyXParagraph * undoendpar = endpar;
2308 if (endpar && endpar->GetDepth()) {
2309 while (endpar && endpar->GetDepth()) {
2310 endpar = endpar->LastPhysicalPar()->Next();
2311 undoendpar = endpar;
2313 } else if (endpar) {
2314 endpar = endpar->Next(); // because of parindents etc.
2317 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2318 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2322 // there are two cases: cut only within one paragraph or
2323 // more than one paragraph
2324 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2325 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2326 // only within one paragraph
2327 endpar = sel_start_cursor.par();
2328 int pos = sel_end_cursor.pos();
2329 cap.cutSelection(sel_start_cursor.par(), &endpar,
2330 sel_start_cursor.pos(), pos,
2331 bview->buffer()->params.textclass, doclear);
2332 sel_end_cursor.pos(pos);
2334 endpar = sel_end_cursor.par();
2336 int pos = sel_end_cursor.pos();
2337 cap.cutSelection(sel_start_cursor.par(), &endpar,
2338 sel_start_cursor.pos(), pos,
2339 bview->buffer()->params.textclass, doclear);
2341 sel_end_cursor.par(endpar);
2342 sel_end_cursor.pos(pos);
2343 cursor.pos(sel_end_cursor.pos());
2345 endpar = endpar->Next();
2347 // sometimes necessary
2349 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2351 RedoParagraphs(bview, sel_start_cursor, endpar);
2354 cursor = sel_start_cursor;
2355 SetCursor(bview, cursor.par(), cursor.pos());
2356 sel_cursor = cursor;
2357 UpdateCounters(bview, cursor.row());
2361 #ifdef USE_OLD_CUT_AND_PASTE
2362 void LyXText::CopySelection(Buffer const * buf)
2364 // this doesnt make sense, if there is no selection
2368 // ok we have a selection. This is always between sel_start_cursor
2369 // and sel_end cursor
2370 LyXParagraph * tmppar;
2372 /* check wether there are half footnotes in the selection */
2373 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2374 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2375 tmppar = sel_start_cursor.par();
2376 while (tmppar != sel_end_cursor.par()) {
2377 if (tmppar->footnoteflag !=
2378 sel_end_cursor.par()->footnoteflag) {
2379 WriteAlert(_("Impossible operation"),
2380 _("Don't know what to do"
2381 " with half floats."),
2385 tmppar = tmppar->Next();
2390 /* table stuff -- begin */
2391 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2392 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2393 WriteAlert(_("Impossible operation"),
2394 _("Don't know what to do with half tables."),
2399 /* table stuff -- end */
2402 // delete the simple_cut_buffer
2403 DeleteSimpleCutBuffer();
2405 // set the textclass
2406 simple_cut_buffer_textclass = buf->params.textclass;
2408 // copy behind a space if there is one
2409 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2410 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2411 && (sel_start_cursor.par() != sel_end_cursor.par()
2412 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2413 sel_start_cursor.pos()++;
2415 // there are two cases: copy only within one paragraph
2416 // or more than one paragraph
2417 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2418 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2419 // only within one paragraph
2420 simple_cut_buffer = new LyXParagraph;
2421 LyXParagraph::size_type i = 0;
2422 for (i = sel_start_cursor.pos(); i < sel_end_cursor.pos(); ++i){
2423 sel_start_cursor.par()->CopyIntoMinibuffer(i);
2424 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos());
2427 // copy more than one paragraph
2428 // clone the paragraphs within the selection
2430 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos());
2431 simple_cut_buffer = tmppar->Clone();
2432 LyXParagraph *tmppar2 = simple_cut_buffer;
2434 while (tmppar != sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())
2436 tmppar = tmppar->next;
2437 tmppar2->next = tmppar->Clone();
2438 tmppar2->next->previous = tmppar2;
2439 tmppar2 = tmppar2->next;
2443 // care about footnotes
2444 if (simple_cut_buffer->footnoteflag) {
2445 tmppar = simple_cut_buffer;
2447 tmppar->footnoteflag =
2448 LyXParagraph::NO_FOOTNOTE;
2449 tmppar = tmppar->next;
2453 // the simple_cut_buffer paragraph is too big
2454 LyXParagraph::size_type tmpi2 =
2455 sel_start_cursor.par()->PositionInParFromPos(sel_start_cursor.pos());
2456 for (; tmpi2; --tmpi2)
2457 simple_cut_buffer->Erase(0);
2459 // now tmppar 2 is too big, delete all after sel_end_cursor.pos()
2461 tmpi2 = sel_end_cursor.par()->PositionInParFromPos(sel_end_cursor.pos());
2462 while (tmppar2->size() > tmpi2) {
2463 tmppar2->Erase(tmppar2->size() - 1);
2468 #else //////////////////////////////////////////////////////////////////////
2470 void LyXText::CopySelection(Buffer const * buf)
2472 // this doesnt make sense, if there is no selection
2476 // ok we have a selection. This is always between sel_start_cursor
2477 // and sel_end cursor
2478 LyXParagraph * tmppar;
2480 /* check wether there are half footnotes in the selection */
2481 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2482 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2483 tmppar = sel_start_cursor.par();
2484 while (tmppar != sel_end_cursor.par()) {
2485 if (tmppar->footnoteflag !=
2486 sel_end_cursor.par()->footnoteflag) {
2487 WriteAlert(_("Impossible operation"),
2488 _("Don't know what to do"
2489 " with half floats."),
2493 tmppar = tmppar->Next();
2498 /* table stuff -- begin */
2499 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2500 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2501 WriteAlert(_("Impossible operation"),
2502 _("Don't know what to do with half tables."),
2507 /* table stuff -- end */
2510 // copy behind a space if there is one
2511 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2512 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2513 && (sel_start_cursor.par() != sel_end_cursor.par()
2514 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2515 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2519 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2520 sel_start_cursor.pos(), sel_end_cursor.pos(),
2521 buf->params.textclass);
2525 #ifdef USE_OLD_CUT_AND_PASTE
2526 void LyXText::PasteSelection(Buffer const * buf)
2528 // this does not make sense, if there is nothing to paste
2529 if (!simple_cut_buffer)
2532 LyXParagraph * tmppar;
2533 LyXParagraph * endpar;
2535 LyXCursor tmpcursor;
2537 // be carefull with footnotes in footnotes
2538 if (cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2540 // check whether the cut_buffer includes a footnote
2541 tmppar = simple_cut_buffer;
2543 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2544 tmppar = tmppar->next;
2547 WriteAlert(_("Impossible operation"),
2548 _("Can't paste float into float!"),
2555 /* table stuff -- begin */
2556 if (cursor.par()->table) {
2557 if (simple_cut_buffer->next) {
2558 WriteAlert(_("Impossible operation"),
2559 _("Table cell cannot include more than one paragraph!"),
2564 /* table stuff -- end */
2567 SetUndo(bview->buffer(), Undo::INSERT,
2568 cursor.par()->ParFromPos(cursor.pos())->previous,
2569 cursor.par()->ParFromPos(cursor.pos())->next);
2573 // There are two cases: cutbuffer only one paragraph or many
2574 if (!simple_cut_buffer->next) {
2575 // only within a paragraph
2577 tmppar = simple_cut_buffer->Clone();
2579 /* table stuff -- begin */
2580 bool table_too_small = false;
2581 if (tmpcursor.par()->table) {
2582 while (simple_cut_buffer->size()
2583 && !table_too_small) {
2584 if (simple_cut_buffer->IsNewline(0)){
2585 while(tmpcursor.pos() < tmpcursor.par()->Last() && !tmpcursor.par()->IsNewline(tmpcursor.pos()))
2587 simple_cut_buffer->Erase(0);
2588 if (tmpcursor.pos() < tmpcursor.par()->Last())
2591 table_too_small = true;
2593 // This is an attempt to fix the
2594 // "never insert a space at the
2595 // beginning of a paragraph" problem.
2596 if (tmpcursor.pos() == 0
2597 && simple_cut_buffer->IsLineSeparator(0)) {
2598 simple_cut_buffer->Erase(0);
2600 simple_cut_buffer->CutIntoMinibuffer(0);
2601 simple_cut_buffer->Erase(0);
2602 tmpcursor.par()->InsertFromMinibuffer(tmpcursor.pos());
2609 /* table stuff -- end */
2610 // Some provisions should be done here for checking
2611 // if we are inserting at the beginning of a
2612 // paragraph. If there are a space at the beginning
2613 // of the text to insert and we are inserting at
2614 // the beginning of the paragraph the space should
2616 while (simple_cut_buffer->size()) {
2617 // This is an attempt to fix the
2618 // "never insert a space at the
2619 // beginning of a paragraph" problem.
2620 if (tmpcursor.pos() == 0
2621 && simple_cut_buffer->IsLineSeparator(0)) {
2622 simple_cut_buffer->Erase(0);
2624 simple_cut_buffer->CutIntoMinibuffer(0);
2625 simple_cut_buffer->Erase(0);
2626 tmpcursor.par()->InsertFromMinibuffer(tmpcursor.pos());
2633 delete simple_cut_buffer;
2634 simple_cut_buffer = tmppar;
2635 endpar = tmpcursor.par()->Next();
2640 // make a copy of the simple cut_buffer
2641 tmppar = simple_cut_buffer;
2642 LyXParagraph * simple_cut_clone = tmppar->Clone();
2643 LyXParagraph * tmppar2 = simple_cut_clone;
2644 if (cursor.par()->footnoteflag){
2645 tmppar->footnoteflag = cursor.par()->footnoteflag;
2646 tmppar->footnotekind = cursor.par()->footnotekind;
2648 while (tmppar->next) {
2649 tmppar = tmppar->next;
2650 tmppar2->next = tmppar->Clone();
2651 tmppar2->next->previous = tmppar2;
2652 tmppar2 = tmppar2->next;
2653 if (cursor.par()->footnoteflag){
2654 tmppar->footnoteflag = cursor.par()->footnoteflag;
2655 tmppar->footnotekind = cursor.par()->footnotekind;
2659 // make sure there is no class difference
2660 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2661 buf->params.textclass,
2664 // make the simple_cut_buffer exactly the same layout than
2665 // the cursor paragraph
2666 simple_cut_buffer->MakeSameLayout(cursor.par());
2668 // find the end of the buffer
2669 LyXParagraph * lastbuffer = simple_cut_buffer;
2670 while (lastbuffer->Next())
2671 lastbuffer = lastbuffer->Next();
2673 bool paste_the_end = false;
2675 // open the paragraph for inserting the simple_cut_buffer
2677 if (cursor.par()->Last() > cursor.pos() || !cursor.par()->Next()){
2678 cursor.par()->BreakParagraphConservative(cursor.pos());
2679 paste_the_end = true;
2682 // set the end for redoing later
2683 endpar = cursor.par()->ParFromPos(cursor.pos())->next->Next();
2686 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2687 cursor.par()->ParFromPos(cursor.pos())->next;
2688 cursor.par()->ParFromPos(cursor.pos())->next->previous =
2689 lastbuffer->ParFromPos(lastbuffer->Last());
2691 cursor.par()->ParFromPos(cursor.pos())->next = simple_cut_buffer;
2692 simple_cut_buffer->previous =
2693 cursor.par()->ParFromPos(cursor.pos());
2695 if (cursor.par()->ParFromPos(cursor.pos())->Next() == lastbuffer)
2696 lastbuffer = cursor.par();
2698 cursor.par()->ParFromPos(cursor.pos())->PasteParagraph();
2700 // store the new cursor position
2701 tmpcursor.par() = lastbuffer;
2702 tmpcursor.pos() = lastbuffer->Last();
2704 // maybe some pasting
2705 if (lastbuffer->Next() && paste_the_end) {
2706 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2707 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2709 } else if (!lastbuffer->Next()->Last()) {
2710 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2711 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2713 } else if (!lastbuffer->Last()) {
2714 lastbuffer->MakeSameLayout(lastbuffer->next);
2715 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2718 lastbuffer->Next()->StripLeadingSpaces(buffer->params.textclass);
2721 // restore the simple cut buffer
2722 simple_cut_buffer = simple_cut_clone;
2725 RedoParagraphs(cursor, endpar);
2727 SetCursor(cursor.par(), cursor.pos());
2730 sel_cursor = cursor;
2731 SetCursor(tmpcursor.par(), tmpcursor.pos());
2733 UpdateCounters(cursor.row());
2736 #else ////////////////////////////////////////////////////////////////////
2738 void LyXText::PasteSelection(BufferView * bview)
2742 // this does not make sense, if there is nothing to paste
2743 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2746 SetUndo(bview->buffer(), Undo::INSERT,
2747 cursor.par()->ParFromPos(cursor.pos())->previous,
2748 cursor.par()->ParFromPos(cursor.pos())->next);
2750 LyXParagraph * endpar;
2751 LyXParagraph * actpar = cursor.par();
2753 int pos = cursor.pos();
2754 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2756 RedoParagraphs(bview, cursor, endpar);
2758 SetCursor(bview, cursor.par(), cursor.pos());
2761 sel_cursor = cursor;
2762 SetCursor(bview, actpar, pos);
2763 SetSelection(bview);
2764 UpdateCounters(bview, cursor.row());
2768 // returns a pointer to the very first LyXParagraph
2769 LyXParagraph * LyXText::FirstParagraph() const
2771 return OwnerParagraph();
2775 // returns true if the specified string is at the specified position
2776 bool LyXText::IsStringInText(LyXParagraph * par,
2777 LyXParagraph::size_type pos,
2778 char const * str) const
2782 while (pos + i < par->Last() && str[i] &&
2783 str[i] == par->GetChar(pos + i)) {
2793 // sets the selection over the number of characters of string, no check!!
2794 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2796 sel_cursor = cursor;
2797 for (int i = 0; string[i]; ++i)
2799 SetSelection(bview);
2803 // simple replacing. The font of the first selected character is used
2804 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2806 SetCursorParUndo(bview->buffer());
2809 if (!selection) { // create a dummy selection
2810 sel_end_cursor = cursor;
2811 sel_start_cursor = cursor;
2814 // Get font setting before we cut
2815 LyXParagraph::size_type pos = sel_end_cursor.pos();
2816 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2817 sel_start_cursor.pos());
2819 // Insert the new string
2820 for (int i = 0; str[i]; ++i) {
2821 sel_end_cursor.par()->InsertChar(pos, str[i]);
2822 sel_end_cursor.par()->SetFont(pos, font);
2826 // Cut the selection
2827 CutSelection(bview);
2833 // if the string can be found: return true and set the cursor to
2835 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2837 LyXParagraph * par = cursor.par();
2838 LyXParagraph::size_type pos = cursor.pos();
2839 while (par && !IsStringInText(par, pos, str)) {
2840 if (pos < par->Last() - 1)
2848 SetCursor(bview, par, pos);
2856 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2858 LyXParagraph * par = cursor.par();
2859 int pos = cursor.pos();
2865 // We skip empty paragraphs (Asger)
2867 par = par->Previous();
2869 pos = par->Last() - 1;
2870 } while (par && pos < 0);
2872 } while (par && !IsStringInText(par, pos, string));
2875 SetCursor(bview, par, pos);
2882 // needed to insert the selection
2883 void LyXText::InsertStringA(BufferView * bview, string const & str)
2885 LyXParagraph * par = cursor.par();
2886 LyXParagraph::size_type pos = cursor.pos();
2887 LyXParagraph::size_type a = 0;
2889 LyXParagraph * endpar = cursor.par()->Next();
2891 SetCursorParUndo(bview->buffer());
2894 textclasslist.Style(bview->buffer()->params.textclass,
2895 cursor.par()->GetLayout()).isEnvironment();
2896 // only to be sure, should not be neccessary
2899 // insert the string, don't insert doublespace
2900 string::size_type i = 0;
2901 while (i < str.length()) {
2902 if (str[i] != '\n') {
2904 && i + 1 < str.length() && str[i + 1] != ' '
2905 && pos && par->GetChar(pos - 1)!= ' ') {
2906 par->InsertChar(pos,' ');
2907 par->SetFont(pos, current_font);
2910 } else if (par->table) {
2911 if (str[i] == '\t') {
2912 while((pos < par->size()) &&
2913 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2915 if (pos < par->size())
2917 else // no more fields to fill skip the rest
2919 } else if ((str[i] != 13) &&
2920 ((str[i] & 127) >= ' ')) {
2921 par->InsertChar(pos, str[i]);
2922 par->SetFont(pos, current_font);
2926 } else if (str[i] == ' ') {
2927 InsetSpecialChar * new_inset =
2928 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2929 if (par->InsertInsetAllowed(new_inset)) {
2930 par->InsertChar(pos, LyXParagraph::META_INSET);
2931 par->SetFont(pos, current_font);
2932 par->InsertInset(pos, new_inset);
2937 } else if (str[i] == '\t') {
2938 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2939 InsetSpecialChar * new_inset =
2940 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2941 if (par->InsertInsetAllowed(new_inset)) {
2942 par->InsertChar(pos, LyXParagraph::META_INSET);
2943 par->SetFont(pos, current_font);
2944 par->InsertInset(pos, new_inset);
2950 } else if (str[i] != 13 &&
2951 // Ignore unprintables
2952 (str[i] & 127) >= ' ') {
2953 par->InsertChar(pos, str[i]);
2954 par->SetFont(pos, current_font);
2960 if ((i + 1) >= str.length()) {
2961 if (pos < par->size())
2965 while((pos < par->size()) &&
2966 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2969 cell = NumberOfCell(par, pos);
2970 while((pos < par->size()) &&
2971 !(par->table->IsFirstCell(cell))) {
2973 while((pos < par->size()) &&
2974 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2977 cell = NumberOfCell(par, pos);
2979 if (pos >= par->size())
2980 // no more fields to fill skip the rest
2984 if (!par->size()) { // par is empty
2985 InsetSpecialChar * new_inset =
2986 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2987 if (par->InsertInsetAllowed(new_inset)) {
2988 par->InsertChar(pos, LyXParagraph::META_INSET);
2989 par->SetFont(pos, current_font);
2990 par->InsertInset(pos, new_inset);
2996 par->BreakParagraph(bview->buffer()->params, pos, flag);
3006 RedoParagraphs(bview, cursor, endpar);
3007 SetCursor(bview, cursor.par(), cursor.pos());
3008 sel_cursor = cursor;
3009 SetCursor(bview, par, pos);
3010 SetSelection(bview);
3014 /* turns double-CR to single CR, others where converted into one blank and 13s
3015 * that are ignored .Double spaces are also converted into one. Spaces at
3016 * the beginning of a paragraph are forbidden. tabs are converted into one
3017 * space. then InsertStringA is called */
3018 void LyXText::InsertStringB(BufferView * bview, string const & s)
3021 LyXParagraph * par = cursor.par();
3022 string::size_type i = 1;
3023 while (i < str.length()) {
3024 if (str[i] == '\t' && !par->table)
3026 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
3028 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
3029 if (str[i + 1] != '\n') {
3030 if (str[i - 1] != ' ')
3035 while (i + 1 < str.length()
3036 && (str[i + 1] == ' '
3037 || str[i + 1] == '\t'
3038 || str[i + 1] == '\n'
3039 || str[i + 1] == 13)) {
3046 InsertStringA(bview, str);
3050 bool LyXText::GotoNextError(BufferView * bview) const
3052 LyXCursor res = cursor;
3054 if (res.pos() < res.par()->Last() - 1) {
3055 res.pos(res.pos() + 1);
3057 res.par(res.par()->Next());
3061 } while (res.par() &&
3062 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
3063 && res.par()->GetInset(res.pos())->AutoDelete()));
3066 SetCursor(bview, res.par(), res.pos());
3073 bool LyXText::GotoNextNote(BufferView * bview) const
3075 LyXCursor res = cursor;
3077 if (res.pos() < res.par()->Last() - 1) {
3078 res.pos(res.pos() + 1);
3080 res.par(res.par()->Next());
3084 } while (res.par() &&
3085 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
3086 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
3089 SetCursor(bview, res.par(), res.pos());
3096 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
3097 LyXParagraph::size_type pos)
3099 LyXCursor tmpcursor;
3102 /* table stuff -- begin*/
3105 CheckParagraphInTable(bview, par, pos);
3109 /* table stuff -- end*/
3112 LyXParagraph::size_type z;
3113 Row * row = GetRow(par, pos, y);
3115 // is there a break one row above
3116 if (row->previous() && row->previous()->par() == row->par()) {
3117 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
3118 if ( z >= row->pos()) {
3119 // set the dimensions of the row above
3120 y -= row->previous()->height();
3122 refresh_row = row->previous();
3123 status = LyXText::NEED_MORE_REFRESH;
3125 BreakAgain(bview, row->previous());
3127 // set the cursor again. Otherwise
3128 // dangling pointers are possible
3129 SetCursor(bview, cursor.par(), cursor.pos());
3130 sel_cursor = cursor;
3135 int tmpheight = row->height();
3136 LyXParagraph::size_type tmplast = RowLast(row);
3140 BreakAgain(bview, row);
3141 if (row->height() == tmpheight && RowLast(row) == tmplast)
3142 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3144 status = LyXText::NEED_MORE_REFRESH;
3146 // check the special right address boxes
3147 if (textclasslist.Style(bview->buffer()->params.textclass,
3148 par->GetLayout()).margintype
3149 == MARGIN_RIGHT_ADDRESS_BOX) {
3156 RedoDrawingOfParagraph(bview, tmpcursor);
3162 // set the cursor again. Otherwise dangling pointers are possible
3163 // also set the selection
3167 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
3168 sel_cursor = cursor;
3169 SetCursorIntern(bview, sel_start_cursor.par(),
3170 sel_start_cursor.pos());
3171 sel_start_cursor = cursor;
3172 SetCursorIntern(bview, sel_end_cursor.par(),
3173 sel_end_cursor.pos());
3174 sel_end_cursor = cursor;
3175 SetCursorIntern(bview, last_sel_cursor.par(),
3176 last_sel_cursor.pos());
3177 last_sel_cursor = cursor;
3180 SetCursorIntern(bview, cursor.par(), cursor.pos());
3184 // returns 0 if inset wasn't found
3185 int LyXText::UpdateInset(BufferView * bview, Inset * inset)
3187 // first check the current paragraph
3188 int pos = cursor.par()->GetPositionOfInset(inset);
3190 CheckParagraph(bview, cursor.par(), pos);
3194 // check every paragraph
3196 LyXParagraph * par = FirstParagraph();
3198 // make sure the paragraph is open
3199 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3200 pos = par->GetPositionOfInset(inset);
3202 CheckParagraph(bview, par, pos);
3213 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
3214 LyXParagraph::size_type pos,
3215 bool setfont, bool boundary) const
3217 LyXCursor old_cursor = cursor;
3218 SetCursorIntern(bview, par, pos, setfont, boundary);
3219 DeleteEmptyParagraphMechanism(bview, old_cursor);
3223 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
3224 LyXParagraph::size_type pos, bool boundary) const
3226 // correct the cursor position if impossible
3227 if (pos > par->Last()){
3228 LyXParagraph * tmppar = par->ParFromPos(pos);
3229 pos = par->PositionInParFromPos(pos);
3232 if (par->IsDummy() && par->previous &&
3233 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3234 while (par->previous &&
3235 ((par->previous->IsDummy() &&
3236 (par->previous->previous->footnoteflag ==
3237 LyXParagraph::CLOSED_FOOTNOTE)) ||
3238 (par->previous->footnoteflag ==
3239 LyXParagraph::CLOSED_FOOTNOTE))) {
3240 par = par->previous ;
3241 if (par->IsDummy() &&
3242 (par->previous->footnoteflag ==
3243 LyXParagraph::CLOSED_FOOTNOTE))
3244 pos += par->size() + 1;
3246 if (par->previous) {
3247 par = par->previous;
3249 pos += par->size() + 1;
3254 cur.boundary(boundary);
3256 /* get the cursor y position in text */
3258 Row * row = GetRow(par, pos, y);
3259 /* y is now the beginning of the cursor row */
3260 y += row->baseline();
3261 /* y is now the cursor baseline */
3264 /* now get the cursors x position */
3266 float fill_separator, fill_hfill, fill_label_hfill;
3267 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
3269 LyXParagraph::size_type cursor_vpos = 0;
3270 LyXParagraph::size_type last = RowLastPrintable(row);
3272 if (pos > last + 1) // This shouldn't happen.
3274 else if (pos < row->pos())
3277 if (last < row->pos())
3278 cursor_vpos = row->pos();
3279 else if (pos > last && !boundary)
3280 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
3281 ? row->pos() : last + 1;
3282 else if (pos > row->pos() &&
3283 (pos > last || boundary ||
3284 (row->par()->table && row->par()->IsNewline(pos))))
3285 /// Place cursor after char at (logical) position pos - 1
3286 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
3287 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
3289 /// Place cursor before char at (logical) position pos
3290 cursor_vpos = (bidi_level(pos) % 2 == 0)
3291 ? log2vis(pos) : log2vis(pos) + 1;
3294 /* table stuff -- begin*/
3295 if (row->par()->table) {
3296 int cell = NumberOfCell(row->par(), row->pos());
3298 x += row->par()->table->GetBeginningOfTextInCell(cell);
3299 for (LyXParagraph::size_type vpos = row->pos();
3300 vpos < cursor_vpos; ++vpos) {
3301 pos = vis2log(vpos);
3302 if (row->par()->IsNewline(pos)) {
3303 x = x_old + row->par()->table->WidthOfColumn(cell);
3306 x += row->par()->table->GetBeginningOfTextInCell(cell);
3308 x += SingleWidth(bview, row->par(), pos);
3312 /* table stuff -- end*/
3314 LyXParagraph::size_type main_body =
3315 BeginningOfMainBody(bview->buffer(), row->par());
3316 if ((main_body > 0) &&
3317 ((main_body-1 > last) ||
3318 !row->par()->IsLineSeparator(main_body-1)))
3321 for (LyXParagraph::size_type vpos = row->pos();
3322 vpos < cursor_vpos; ++vpos) {
3323 pos = vis2log(vpos);
3324 if (main_body > 0 && pos == main_body-1) {
3325 x += fill_label_hfill +
3326 lyxfont::width(textclasslist.Style(
3327 bview->buffer()->params.textclass,
3328 row->par()->GetLayout())
3330 GetFont(bview->buffer(), row->par(), -2));
3331 if (row->par()->IsLineSeparator(main_body-1))
3332 x -= SingleWidth(bview, row->par(),main_body-1);
3334 if (HfillExpansion(bview->buffer(), row, pos)) {
3335 x += SingleWidth(bview, row->par(), pos);
3336 if (pos >= main_body)
3339 x += fill_label_hfill;
3340 } else if (row->par()->IsSeparator(pos)) {
3341 x += SingleWidth(bview, row->par(), pos);
3342 if (pos >= main_body)
3343 x += fill_separator;
3345 x += SingleWidth(bview, row->par(), pos);
3357 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3358 LyXParagraph::size_type pos,
3359 bool setfont, bool boundary) const
3361 SetCursor(bview, cursor, par, pos, boundary);
3362 // #warning Remove this when verified working (Jug 20000413)
3364 // correct the cursor position if impossible
3365 if (pos > par->Last()){
3366 LyXParagraph * tmppar = par->ParFromPos(pos);
3367 pos = par->PositionInParFromPos(pos);
3370 if (par->IsDummy() && par->previous &&
3371 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3372 while (par->previous &&
3373 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3374 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3375 par = par->previous ;
3376 if (par->IsDummy() &&
3377 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3378 pos += par->size() + 1;
3380 if (par->previous) {
3381 par = par->previous;
3383 pos += par->size() + 1;
3389 /* get the cursor y position in text */
3391 Row * row = GetRow(par, pos, y);
3392 /* y is now the beginning of the cursor row */
3393 y += row->baseline();
3394 /* y is now the cursor baseline */
3397 /* now get the cursors x position */
3399 float fill_separator, fill_hfill, fill_label_hfill;
3400 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3401 LyXParagraph::size_type cursor_vpos;
3402 LyXParagraph::size_type last = RowLastPrintable(row);
3404 if (pos > last + 1) // This shouldn't happen.
3407 if (last < row->pos())
3409 else if (pos > last ||
3410 (pos - 1 >= row->pos() &&
3411 (row->par()->IsSeparator(pos) ||
3412 (row->par()->table && row->par()->IsNewline(pos))
3414 /// Place cursor after char at (logical) position pos-1
3415 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3416 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3418 /// Place cursor before char at (logical) position pos
3419 cursor_vpos = (bidi_level(pos) % 2 == 0)
3420 ? log2vis(pos) : log2vis(pos) + 1;
3423 /* table stuff -- begin*/
3424 if (row->par()->table) {
3425 int cell = NumberOfCell(row->par(), row->pos());
3427 x += row->par()->table->GetBeginningOfTextInCell(cell);
3428 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
3429 pos = vis2log(vpos);
3430 if (row->par()->IsNewline(pos)) {
3431 x = x_old + row->par()->table->WidthOfColumn(cell);
3434 x += row->par()->table->GetBeginningOfTextInCell(cell);
3436 x += SingleWidth(row->par(), pos);
3440 /* table stuff -- end*/
3442 LyXParagraph::size_type main_body =
3443 BeginningOfMainBody(row->par());
3444 if (main_body > 0 &&
3445 (main_body-1 > last ||
3446 !row->par()->IsLineSeparator(main_body-1)))
3449 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
3450 pos = vis2log(vpos);
3451 if (main_body > 0 && pos == main_body-1) {
3452 x += fill_label_hfill +
3453 lyxfont::width(textclasslist
3454 .Style(bview->buffer()->params.textclass,
3455 row->par()->GetLayout())
3457 GetFont(row->par(), -2));
3458 if (row->par()->IsLineSeparator(main_body-1))
3459 x -= SingleWidth(row->par(), main_body-1);
3461 if (HfillExpansion(row, pos)) {
3462 x += SingleWidth(row->par(), pos);
3463 if (pos >= main_body)
3466 x += fill_label_hfill;
3468 else if (row->par()->IsSeparator(pos)) {
3469 x += SingleWidth(row->par(), pos);
3470 if (pos >= main_body)
3471 x += fill_separator;
3473 x += SingleWidth(row->par(), pos);
3480 cursor.x_fix = cursor.x;
3484 SetCurrentFont(bview);
3487 void LyXText::SetCurrentFont(BufferView * bview) const
3489 LyXParagraph::size_type pos = cursor.pos();
3490 if (cursor.boundary() && pos > 0)
3494 if (pos == cursor.par()->Last() ||
3495 (cursor.par()->table && cursor.par()->IsNewline(pos)))
3497 else if (cursor.par()->IsSeparator(pos)) {
3498 if (pos > cursor.row()->pos() &&
3499 bidi_level(pos) % 2 ==
3500 bidi_level(pos - 1) % 2)
3502 else if (pos + 1 < cursor.par()->Last())
3507 current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3508 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3512 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3514 LyXCursor old_cursor = cursor;
3516 /* get the row first */
3518 Row * row = GetRowNearY(y);
3519 cursor.par(row->par());
3522 int column = GetColumnNearX(bview, row, x, bound);
3523 cursor.pos(row->pos() + column);
3525 cursor.y(y + row->baseline());
3527 cursor.boundary(bound);
3528 SetCurrentFont(bview);
3529 DeleteEmptyParagraphMechanism(bview, old_cursor);
3533 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3534 int x, long y) const
3536 /* get the row first */
3538 Row * row = GetRowNearY(y);
3540 int column = GetColumnNearX(bview, row, x, bound);
3542 cur.par(row->par());
3543 cur.pos(row->pos() + column);
3545 cur.y(y + row->baseline());
3547 cur.boundary(bound);
3551 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3553 CursorLeftIntern(bview, internal);
3555 if (cursor.par()->table) {
3556 int cell = NumberOfCell(cursor.par(), cursor.pos());
3557 if (cursor.par()->table->IsContRow(cell)
3558 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3566 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3568 if (cursor.pos() > 0) {
3569 bool boundary = cursor.boundary();
3570 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3571 if (!internal && !boundary &&
3572 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3573 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3574 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3575 LyXParagraph * par = cursor.par()->Previous();
3576 LyXParagraph::size_type pos = par->Last();
3577 SetCursor(bview, par, pos);
3578 if (IsBoundary(bview->buffer(), par, pos))
3579 SetCursor(bview, par, pos, false, true);
3584 void LyXText::CursorRight(BufferView * bview, bool internal) const
3586 CursorRightIntern(bview, internal);
3588 if (cursor.par()->table) {
3589 int cell = NumberOfCell(cursor.par(), cursor.pos());
3590 if (cursor.par()->table->IsContRow(cell) &&
3591 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3599 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3601 if (cursor.pos() < cursor.par()->Last()) {
3602 if (!internal && cursor.boundary() &&
3603 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3604 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3606 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3607 if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3608 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3610 } else if (cursor.par()->Next())
3611 SetCursor(bview, cursor.par()->Next(), 0);
3615 void LyXText::CursorUp(BufferView * bview) const
3617 SetCursorFromCoordinates(bview, cursor.x_fix(),
3618 cursor.y() - cursor.row()->baseline() - 1);
3620 if (cursor.par()->table) {
3621 int cell = NumberOfCell(cursor.par(), cursor.pos());
3622 if (cursor.par()->table->IsContRow(cell) &&
3623 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3631 void LyXText::CursorDown(BufferView * bview) const
3634 if (cursor.par()->table &&
3635 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3636 !cursor.par()->next)
3640 SetCursorFromCoordinates(bview, cursor.x_fix(),
3641 cursor.y() - cursor.row()->baseline()
3642 + cursor.row()->height() + 1);
3644 if (cursor.par()->table) {
3645 int cell = NumberOfCell(cursor.par(), cursor.pos());
3646 int cell_above = cursor.par()->table->GetCellAbove(cell);
3647 while(cursor.par()->table &&
3648 cursor.par()->table->IsContRow(cell) &&
3649 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3650 SetCursorFromCoordinates(bview, cursor.x_fix(),
3651 cursor.y() - cursor.row()->baseline()
3652 + cursor.row()->height() + 1);
3653 if (cursor.par()->table) {
3654 cell = NumberOfCell(cursor.par(), cursor.pos());
3655 cell_above = cursor.par()->table->GetCellAbove(cell);
3663 void LyXText::CursorUpParagraph(BufferView * bview) const
3665 if (cursor.pos() > 0) {
3666 SetCursor(bview, cursor.par(), 0);
3668 else if (cursor.par()->Previous()) {
3669 SetCursor(bview, cursor.par()->Previous(), 0);
3674 void LyXText::CursorDownParagraph(BufferView * bview) const
3676 if (cursor.par()->Next()) {
3677 SetCursor(bview, cursor.par()->Next(), 0);
3679 SetCursor(bview, cursor.par(), cursor.par()->Last());
3684 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3685 LyXCursor const & old_cursor) const
3687 // Would be wrong to delete anything if we have a selection.
3688 if (selection) return;
3690 // We allow all kinds of "mumbo-jumbo" when freespacing.
3691 if (textclasslist.Style(bview->buffer()->params.textclass,
3692 old_cursor.par()->GetLayout()).free_spacing)
3695 bool deleted = false;
3697 /* Ok I'll put some comments here about what is missing.
3698 I have fixed BackSpace (and thus Delete) to not delete
3699 double-spaces automagically. I have also changed Cut,
3700 Copy and Paste to hopefully do some sensible things.
3701 There are still some small problems that can lead to
3702 double spaces stored in the document file or space at
3703 the beginning of paragraphs. This happens if you have
3704 the cursor betwenn to spaces and then save. Or if you
3705 cut and paste and the selection have a space at the
3706 beginning and then save right after the paste. I am
3707 sure none of these are very hard to fix, but I will
3708 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3709 that I can get some feedback. (Lgb)
3712 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3713 // delete the LineSeparator.
3716 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3717 // delete the LineSeparator.
3720 // If the pos around the old_cursor were spaces, delete one of them.
3721 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3722 // Only if the cursor has really moved
3724 if (old_cursor.pos() > 0
3725 && old_cursor.pos() < old_cursor.par()->Last()
3726 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3727 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3728 old_cursor.par()->Erase(old_cursor.pos() - 1);
3729 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3731 if (old_cursor.par() == cursor.par() &&
3732 cursor.pos() > old_cursor.pos()) {
3733 SetCursorIntern(bview, cursor.par(),
3736 SetCursorIntern(bview, cursor.par(),
3742 // Do not delete empty paragraphs with keepempty set.
3743 if ((textclasslist.Style(bview->buffer()->params.textclass,
3744 old_cursor.par()->GetLayout())).keepempty)
3747 LyXCursor tmpcursor;
3749 if (old_cursor.par() != cursor.par()) {
3750 if ( (old_cursor.par()->Last() == 0
3751 || (old_cursor.par()->Last() == 1
3752 && old_cursor.par()->IsLineSeparator(0)))
3753 && old_cursor.par()->FirstPhysicalPar()
3754 == old_cursor.par()->LastPhysicalPar()) {
3755 // ok, we will delete anything
3757 // make sure that you do not delete any environments
3758 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3759 !(old_cursor.row()->previous()
3760 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3761 && !(old_cursor.row()->next()
3762 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3763 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3764 && ((old_cursor.row()->previous()
3765 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3766 || (old_cursor.row()->next()
3767 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3769 status = LyXText::NEED_MORE_REFRESH;
3772 if (old_cursor.row()->previous()) {
3773 refresh_row = old_cursor.row()->previous();
3774 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3776 cursor = old_cursor; // that undo can restore the right cursor position
3777 LyXParagraph * endpar = old_cursor.par()->next;
3778 if (endpar && endpar->GetDepth()) {
3779 while (endpar && endpar->GetDepth()) {
3780 endpar = endpar->LastPhysicalPar()->Next();
3783 SetUndo(bview->buffer(), Undo::DELETE,
3784 old_cursor.par()->previous,
3789 RemoveRow(old_cursor.row());
3790 if (OwnerParagraph() == old_cursor.par()) {
3791 OwnerParagraph(OwnerParagraph()->next);
3794 delete old_cursor.par();
3796 /* Breakagain the next par. Needed
3797 * because of the parindent that
3798 * can occur or dissappear. The
3799 * next row can change its height,
3800 * if there is another layout before */
3801 if (refresh_row->next()) {
3802 BreakAgain(bview, refresh_row->next());
3803 UpdateCounters(bview, refresh_row);
3805 SetHeightOfRow(bview, refresh_row);
3807 refresh_row = old_cursor.row()->next();
3808 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3811 cursor = old_cursor; // that undo can restore the right cursor position
3812 LyXParagraph * endpar = old_cursor.par()->next;
3813 if (endpar && endpar->GetDepth()) {
3814 while (endpar && endpar->GetDepth()) {
3815 endpar = endpar->LastPhysicalPar()->Next();
3818 SetUndo(bview->buffer(), Undo::DELETE,
3819 old_cursor.par()->previous,
3824 RemoveRow(old_cursor.row());
3826 if (OwnerParagraph() == old_cursor.par()) {
3827 OwnerParagraph(OwnerParagraph()->next);
3829 delete old_cursor.par();
3831 /* Breakagain the next par. Needed
3832 because of the parindent that can
3833 occur or dissappear.
3834 The next row can change its height,
3835 if there is another layout before
3838 BreakAgain(bview, refresh_row);
3839 UpdateCounters(bview, refresh_row->previous());
3845 SetCursorIntern(bview, cursor.par(), cursor.pos());
3847 if (sel_cursor.par() == old_cursor.par()
3848 && sel_cursor.pos() == sel_cursor.pos()) {
3849 // correct selection
3850 sel_cursor = cursor;
3855 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3856 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3858 SetCursorIntern(bview, cursor.par(), cursor.pos());
3859 sel_cursor = cursor;
3866 LyXParagraph * LyXText::GetParFromID(int id)
3868 LyXParagraph * result = FirstParagraph();
3869 while (result && result->id() != id)
3870 result = result->next;
3876 bool LyXText::TextUndo(BufferView * bview)
3878 // returns false if no undo possible
3879 Undo * undo = bview->buffer()->undostack.pop();
3883 bview->buffer()->redostack
3884 .push(CreateUndo(bview->buffer(), undo->kind,
3885 GetParFromID(undo->number_of_before_par),
3886 GetParFromID(undo->number_of_behind_par)));
3888 return TextHandleUndo(bview, undo);
3892 bool LyXText::TextRedo(BufferView * bview)
3894 // returns false if no redo possible
3895 Undo * undo = bview->buffer()->redostack.pop();
3899 bview->buffer()->undostack
3900 .push(CreateUndo(bview->buffer(), undo->kind,
3901 GetParFromID(undo->number_of_before_par),
3902 GetParFromID(undo->number_of_behind_par)));
3904 return TextHandleUndo(bview, undo);
3908 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3910 // returns false if no undo possible
3911 bool result = false;
3913 LyXParagraph * before =
3914 GetParFromID(undo->number_of_before_par);
3915 LyXParagraph * behind =
3916 GetParFromID(undo->number_of_behind_par);
3917 LyXParagraph * tmppar;
3918 LyXParagraph * tmppar2;
3919 LyXParagraph * endpar;
3920 LyXParagraph * tmppar5;
3922 // if there's no before take the beginning
3923 // of the document for redoing
3925 SetCursorIntern(bview, FirstParagraph(), 0);
3927 // replace the paragraphs with the undo informations
3929 LyXParagraph * tmppar3 = undo->par;
3930 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3931 LyXParagraph * tmppar4 = tmppar3;
3933 while (tmppar4->next)
3934 tmppar4 = tmppar4->next;
3935 } // get last undo par
3937 // now remove the old text if there is any
3938 if (before != behind || (!behind && !before)){
3940 tmppar5 = before->next;
3942 tmppar5 = OwnerParagraph();
3944 while (tmppar5 && tmppar5 != behind){
3946 tmppar5 = tmppar5->next;
3947 // a memory optimization for edit: Only layout information
3948 // is stored in the undo. So restore the text informations.
3949 if (undo->kind == Undo::EDIT) {
3950 tmppar2->setContentsFromPar(tmppar);
3951 tmppar->clearContents();
3952 tmppar2 = tmppar2->next;
3957 // put the new stuff in the list if there is one
3960 before->next = tmppar3;
3962 OwnerParagraph(tmppar3);
3963 tmppar3->previous = before;
3967 OwnerParagraph(behind);
3970 tmppar4->next = behind;
3972 behind->previous = tmppar4;
3976 // Set the cursor for redoing
3978 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3979 // check wether before points to a closed float and open it if necessary
3980 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3981 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3983 while (tmppar4->previous &&
3984 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3985 tmppar4 = tmppar4->previous;
3986 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3987 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3988 tmppar4 = tmppar4->next;
3993 // open a cosed footnote at the end if necessary
3994 if (behind && behind->previous &&
3995 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3996 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3997 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3998 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3999 behind = behind->next;
4003 // calculate the endpar for redoing the paragraphs.
4005 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
4006 endpar = behind->LastPhysicalPar()->Next();
4008 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
4012 tmppar = GetParFromID(undo->number_of_cursor_par);
4013 RedoParagraphs(bview, cursor, endpar);
4015 SetCursorIntern(bview, tmppar, undo->cursor_pos);
4016 UpdateCounters(bview, cursor.row());
4026 void LyXText::FinishUndo()
4028 // makes sure the next operation will be stored
4029 undo_finished = true;
4033 void LyXText::FreezeUndo()
4035 // this is dangerous and for internal use only
4040 void LyXText::UnFreezeUndo()
4042 // this is dangerous and for internal use only
4043 undo_frozen = false;
4047 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
4048 LyXParagraph const * before,
4049 LyXParagraph const * behind) const
4052 buf->undostack.push(CreateUndo(buf, kind, before, behind));
4053 buf->redostack.clear();
4057 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
4058 LyXParagraph const * before, LyXParagraph const * behind)
4060 buf->redostack.push(CreateUndo(buf, kind, before, behind));
4064 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
4065 LyXParagraph const * before,
4066 LyXParagraph const * behind) const
4068 int before_number = -1;
4069 int behind_number = -1;
4071 before_number = before->id();
4073 behind_number = behind->id();
4074 // Undo::EDIT and Undo::FINISH are
4075 // always finished. (no overlapping there)
4076 // overlapping only with insert and delete inside one paragraph:
4077 // Nobody wants all removed character
4078 // appear one by one when undoing.
4079 // EDIT is special since only layout information, not the
4080 // contents of a paragaph are stored.
4081 if (!undo_finished && kind != Undo::EDIT &&
4082 kind != Undo::FINISH){
4083 // check wether storing is needed
4084 if (!buf->undostack.empty() &&
4085 buf->undostack.top()->kind == kind &&
4086 buf->undostack.top()->number_of_before_par == before_number &&
4087 buf->undostack.top()->number_of_behind_par == behind_number ){
4092 // create a new Undo
4093 LyXParagraph * undopar;
4094 LyXParagraph * tmppar;
4095 LyXParagraph * tmppar2;
4097 LyXParagraph * start = 0;
4098 LyXParagraph * end = 0;
4101 start = before->next;
4103 start = FirstParagraph();
4105 end = behind->previous;
4107 end = FirstParagraph();
4113 && start != end->next
4114 && (before != behind || (!before && !behind))) {
4116 tmppar2 = tmppar->Clone();
4117 tmppar2->id(tmppar->id());
4119 // a memory optimization: Just store the layout information
4121 if (kind == Undo::EDIT){
4122 //tmppar2->text.clear();
4123 tmppar2->clearContents();
4128 while (tmppar != end && tmppar->next) {
4129 tmppar = tmppar->next;
4130 tmppar2->next = tmppar->Clone();
4131 tmppar2->next->id(tmppar->id());
4132 // a memory optimization: Just store the layout
4133 // information when only edit
4134 if (kind == Undo::EDIT){
4135 //tmppar2->next->text.clear();
4136 tmppar2->clearContents();
4138 tmppar2->next->previous = tmppar2;
4139 tmppar2 = tmppar2->next;
4143 undopar = 0; // nothing to replace (undo of delete maybe)
4145 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
4146 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
4148 Undo * undo = new Undo(kind,
4149 before_number, behind_number,
4150 cursor_par, cursor_pos,
4153 undo_finished = false;
4158 void LyXText::SetCursorParUndo(Buffer * buf)
4160 SetUndo(buf, Undo::FINISH,
4161 cursor.par()->ParFromPos(cursor.pos())->previous,
4162 cursor.par()->ParFromPos(cursor.pos())->next);
4167 void LyXText::RemoveTableRow(LyXCursor & cur) const
4173 // move to the previous row
4174 int cell_act = NumberOfCell(cur.par(), cur.pos());
4177 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
4178 cur.pos(cur.pos() - 1);
4180 !cur.par()->table->IsFirstCell(cell_act)) {
4181 cur.pos(cur.pos() - 1);
4182 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
4183 cur.pos(cur.pos() - 1);
4187 // now we have to pay attention if the actual table is the
4188 // main row of TableContRows and if yes to delete all of them
4193 // delete up to the next row
4194 while (cur.pos() < cur.par()->Last() &&
4196 || !cur.par()->table->IsFirstCell(cell_act))) {
4197 while (cur.pos() < cur.par()->Last() &&
4198 !cur.par()->IsNewline(cur.pos()))
4199 cur.par()->Erase(cur.pos());
4202 if (cur.pos() < cur.par()->Last())
4203 cur.par()->Erase(cur.pos());
4205 if (cur.pos() && cur.pos() == cur.par()->Last()) {
4206 cur.pos(cur.pos() - 1);
4207 cur.par()->Erase(cur.pos()); // no newline at very end!
4209 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
4210 !cur.par()->table->IsContRow(cell_org) &&
4211 cur.par()->table->IsContRow(cell));
4212 cur.par()->table->DeleteRow(cell_org);
4219 bool LyXText::IsEmptyTableCell() const
4221 LyXParagraph::size_type pos = cursor.pos() - 1;
4222 while (pos >= 0 && pos < cursor.par()->Last()
4223 && !cursor.par()->IsNewline(pos))
4225 return cursor.par()->IsNewline(pos + 1);
4230 void LyXText::toggleAppendix(BufferView * bview)
4232 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
4233 bool start = !par->start_of_appendix;
4235 // ensure that we have only one start_of_appendix in this document
4236 LyXParagraph * tmp = FirstParagraph();
4237 for (; tmp; tmp = tmp->next)
4238 tmp->start_of_appendix = 0;
4239 par->start_of_appendix = start;
4241 // we can set the refreshing parameters now
4242 status = LyXText::NEED_MORE_REFRESH;
4244 refresh_row = 0; // not needed for full update
4245 UpdateCounters(bview, 0);
4246 SetCursor(bview, cursor.par(), cursor.pos());
4249 LyXParagraph * LyXText::OwnerParagraph() const
4252 return inset_owner->par;
4254 return bv_owner->buffer()->paragraph;
4258 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
4261 inset_owner->par = p;
4263 bv_owner->buffer()->paragraph = p;