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, int pw, Buffer * p)
58 status = LyXText::UNCHANGED;
59 LyXParagraph * par = p->paragraph;
60 current_font = GetFont(par, 0);
65 InsertParagraph(par, lastrow);
69 // set cursor at the very top position
70 selection = true; /* these setting is necessary
71 because of the delete-empty-
72 paragraph mechanism in
74 SetCursor(firstrow->par, 0);
79 // no rebreak necessary
85 // Default layouttype for copy environment type
89 // Dump all rowinformation:
90 Row * tmprow = firstrow;
91 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
93 lyxerr << tmprow->baseline << '\t'
94 << tmprow->par << '\t'
95 << tmprow->pos << '\t'
96 << tmprow->height << '\t'
97 << tmprow->ascent_of_text << '\t'
98 << tmprow->fill << '\n';
99 tmprow = tmprow->next;
108 // Delete all rows, this does not touch the paragraphs!
109 Row * tmprow = firstrow;
111 tmprow = firstrow->next;
118 void LyXText::owner(BufferView * bv)
120 if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
124 // Gets the fully instantiated font at a given position in a paragraph
125 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
126 // The difference is that this one is used for displaying, and thus we
127 // are allowed to make cosmetic improvements. For instance make footnotes
129 // If position is -1, we get the layout font of the paragraph.
130 // If position is -2, we get the font of the manual label of the paragraph.
131 LyXFont LyXText::GetFont(LyXParagraph * par,
132 LyXParagraph::size_type pos) const
134 LyXLayout const & layout =
135 textclasslist.Style(buffer->params.textclass,
138 char par_depth = par->GetDepth();
139 // We specialize the 95% common case:
140 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
143 if (layout.labeltype == LABEL_MANUAL
144 && pos < BeginningOfMainBody(par)) {
146 return par->GetFontSettings(pos).
147 realize(layout.reslabelfont);
149 return par->GetFontSettings(pos).
150 realize(layout.resfont);
153 // process layoutfont for pos == -1 and labelfont for pos < -1
155 return layout.resfont;
157 return layout.reslabelfont;
161 // The uncommon case need not be optimized as much
163 LyXFont layoutfont, tmpfont;
167 if (pos < BeginningOfMainBody(par)) {
169 layoutfont = layout.labelfont;
172 layoutfont = layout.font;
174 tmpfont = par->GetFontSettings(pos);
175 tmpfont.realize(layoutfont);
178 // process layoutfont for pos == -1 and labelfont for pos < -1
180 tmpfont = layout.font;
182 tmpfont = layout.labelfont;
185 // Resolve against environment font information
186 while (par && par_depth && !tmpfont.resolved()) {
187 par = par->DepthHook(par_depth - 1);
189 tmpfont.realize(textclasslist.
190 Style(buffer->params.textclass,
191 par->GetLayout()).font);
192 par_depth = par->GetDepth();
196 tmpfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
198 // Cosmetic improvement: If this is an open footnote, make the font
200 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
201 && par->footnotekind == LyXParagraph::FOOTNOTE) {
209 void LyXText::SetCharFont(LyXParagraph * par,
210 LyXParagraph::size_type pos,
214 // Let the insets convert their font
215 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
216 if (par->GetInset(pos))
217 font = par->GetInset(pos)->ConvertFont(font);
220 LyXLayout const & layout =
221 textclasslist.Style(buffer->params.textclass,
224 // Get concrete layout font to reduce against
227 if (pos < BeginningOfMainBody(par))
228 layoutfont = layout.labelfont;
230 layoutfont = layout.font;
232 // Realize against environment font information
233 if (par->GetDepth()){
234 LyXParagraph * tp = par;
235 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
236 tp = tp->DepthHook(tp->GetDepth()-1);
238 layoutfont.realize(textclasslist.
239 Style(buffer->params.textclass,
240 tp->GetLayout()).font);
244 layoutfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
246 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
247 && par->footnotekind == LyXParagraph::FOOTNOTE) {
248 layoutfont.decSize();
251 // Now, reduce font against full layout font
252 font.reduce(layoutfont);
254 par->SetFont(pos, font);
258 /* inserts a new row behind the specified row, increments
259 * the touched counters */
260 void LyXText::InsertRow(Row * row, LyXParagraph * par,
261 LyXParagraph::size_type pos) const
263 Row * tmprow = new Row;
265 tmprow->previous = 0;
266 tmprow->next = firstrow;
269 tmprow->previous = row;
270 tmprow->next = row->next;
275 tmprow->next->previous = tmprow;
277 if (tmprow->previous)
278 tmprow->previous->next = tmprow;
286 ++number_of_rows; // one more row
290 // removes the row and reset the touched counters
291 void LyXText::RemoveRow(Row * row) const
293 /* this must not happen before the currentrow for clear reasons.
294 so the trick is just to set the current row onto the previous
297 GetRow(row->par, row->pos, unused_y);
300 row->next->previous = row->previous;
301 if (!row->previous) {
302 firstrow = row->next;
304 row->previous->next = row->next;
307 lastrow = row->previous;
309 height -= row->height; // the text becomes smaller
312 --number_of_rows; // one row less
316 // remove all following rows of the paragraph of the specified row.
317 void LyXText::RemoveParagraph(Row * row) const
319 LyXParagraph * tmppar = row->par;
323 while (row && row->par == tmppar) {
331 // insert the specified paragraph behind the specified row
332 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
334 InsertRow(row, par, 0); /* insert a new row, starting
337 SetCounter(par); // set the counters
339 // and now append the whole paragraph behind the new row
341 firstrow->height = 0;
342 AppendParagraph(firstrow);
344 row->next->height = 0;
345 AppendParagraph(row->next);
350 void LyXText::ToggleFootnote()
352 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
354 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
356 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
358 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
364 void LyXText::OpenStuff()
366 if (cursor.pos == 0 && cursor.par->bibkey){
367 cursor.par->bibkey->Edit(owner_, 0, 0, 0);
369 else if (cursor.pos < cursor.par->Last()
370 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
371 && cursor.par->GetInset(cursor.pos)->Editable()) {
372 owner_->owner()->getMiniBuffer()
373 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
374 if (cursor.par->GetInset(cursor.pos)->Editable() != Inset::HIGHLY_EDITABLE)
376 cursor.par->GetInset(cursor.pos)->Edit(owner_, 0, 0, 0);
383 void LyXText::CloseFootnote()
385 LyXParagraph * tmppar;
386 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
388 // if the cursor is not in an open footnote, or
389 // there is no open footnote in this paragraph, just return.
390 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
393 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
394 owner_->owner()->getMiniBuffer()
395 ->Set(_("Nothing to do"));
399 // ok, move the cursor right before the footnote
400 // just a little faster than using CursorRight()
402 cursor.par->ParFromPos(cursor.pos) != par;
406 // now the cursor is at the beginning of the physical par
407 SetCursor(cursor.par,
409 cursor.par->ParFromPos(cursor.pos)->size());
411 /* we are in a footnote, so let us move at the beginning */
412 /* this is just faster than using just CursorLeft() */
415 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
416 // just a little bit faster than movin the cursor
417 tmppar = tmppar->Previous();
419 SetCursor(tmppar, tmppar->Last());
422 // the cursor must be exactly before the footnote
423 par = cursor.par->ParFromPos(cursor.pos);
425 status = LyXText::NEED_MORE_REFRESH;
426 refresh_row = cursor.row;
427 refresh_y = cursor.y - cursor.row->baseline;
430 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
431 Row * row = cursor.row;
433 tmppar->CloseFootnote(cursor.pos);
435 while (tmppar != endpar) {
436 RemoveRow(row->next);
438 tmppar = row->next->par;
443 AppendParagraph(cursor.row);
445 SetCursor(cursor.par, cursor.pos);
449 if (cursor.row->next)
450 SetHeightOfRow(cursor.row->next);
454 /* used in setlayout */
455 // Asger is not sure we want to do this...
456 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
459 LyXLayout const & layout =
460 textclasslist.Style(buffer->params.textclass,
463 LyXFont layoutfont, tmpfont;
464 for (LyXParagraph::size_type pos = 0;
465 pos < par->Last(); ++pos) {
466 if (pos < BeginningOfMainBody(par))
467 layoutfont = layout.labelfont;
469 layoutfont = layout.font;
471 tmpfont = par->GetFontSettings(pos);
472 tmpfont.reduce(layoutfont);
473 par->SetFont(pos, tmpfont);
477 LyXParagraph * LyXText::SetLayout(LyXCursor & cur, LyXCursor & sstart_cur,
478 LyXCursor & send_cur,
479 LyXTextClass::size_type layout)
481 LyXParagraph * endpar = send_cur.par->LastPhysicalPar()->Next();
482 LyXParagraph * undoendpar = endpar;
484 if (endpar && endpar->GetDepth()) {
485 while (endpar && endpar->GetDepth()) {
486 endpar = endpar->LastPhysicalPar()->Next();
490 endpar = endpar->Next(); // because of parindents etc.
494 sstart_cur.par->ParFromPos(sstart_cur.pos)->previous,
497 /* ok we have a selection. This is always between sstart_cur
498 * and sel_end cursor */
501 LyXLayout const & lyxlayout =
502 textclasslist.Style(buffer->params.textclass, layout);
504 while (cur.par != send_cur.par) {
505 if (cur.par->footnoteflag == sstart_cur.par->footnoteflag) {
506 cur.par->SetLayout(layout);
507 MakeFontEntriesLayoutSpecific(cur.par);
508 LyXParagraph* fppar = cur.par->FirstPhysicalPar();
509 fppar->added_space_top = lyxlayout.fill_top ?
510 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
511 fppar->added_space_bottom = lyxlayout.fill_bottom ?
512 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
513 if (lyxlayout.margintype == MARGIN_MANUAL)
514 cur.par->SetLabelWidthString(lyxlayout.labelstring());
515 if (lyxlayout.labeltype != LABEL_BIBLIO
517 delete fppar->bibkey;
521 cur.par = cur.par->Next();
523 if (cur.par->footnoteflag == sstart_cur.par->footnoteflag) {
524 cur.par->SetLayout(layout);
525 MakeFontEntriesLayoutSpecific(cur.par);
526 LyXParagraph* fppar = cur.par->FirstPhysicalPar();
527 fppar->added_space_top = lyxlayout.fill_top ?
528 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
529 fppar->added_space_bottom = lyxlayout.fill_bottom ?
530 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
531 if (lyxlayout.margintype == MARGIN_MANUAL)
532 cur.par->SetLabelWidthString(lyxlayout.labelstring());
533 if (lyxlayout.labeltype != LABEL_BIBLIO
535 delete fppar->bibkey;
542 // set layout over selection and make a total rebreak of those paragraphs
543 void LyXText::SetLayout(LyXTextClass::size_type layout)
546 tmpcursor = cursor; /* store the current cursor */
548 #ifdef USE_OLD_SET_LAYOUT
549 // if there is no selection just set the layout
550 // of the current paragraph */
552 sel_start_cursor = cursor; // dummy selection
553 sel_end_cursor = cursor;
556 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
557 LyXParagraph * undoendpar = endpar;
559 if (endpar && endpar->GetDepth()) {
560 while (endpar && endpar->GetDepth()) {
561 endpar = endpar->LastPhysicalPar()->Next();
566 endpar = endpar->Next(); // because of parindents etc.
570 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
573 /* ok we have a selection. This is always between sel_start_cursor
574 * and sel_end cursor */
575 cursor = sel_start_cursor;
577 LyXLayout const & lyxlayout =
578 textclasslist.Style(buffer->params.textclass, layout);
580 while (cursor.par != sel_end_cursor.par) {
581 if (cursor.par->footnoteflag ==
582 sel_start_cursor.par->footnoteflag) {
583 cursor.par->SetLayout(layout);
584 MakeFontEntriesLayoutSpecific(cursor.par);
585 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
586 fppar->added_space_top = lyxlayout.fill_top ?
587 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
588 fppar->added_space_bottom = lyxlayout.fill_bottom ?
589 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
590 if (lyxlayout.margintype == MARGIN_MANUAL)
591 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
592 if (lyxlayout.labeltype != LABEL_BIBLIO
594 delete fppar->bibkey;
598 cursor.par = cursor.par->Next();
600 if (cursor.par->footnoteflag ==
601 sel_start_cursor.par->footnoteflag) {
602 cursor.par->SetLayout(layout);
603 MakeFontEntriesLayoutSpecific(cursor.par);
604 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
605 fppar->added_space_top = lyxlayout.fill_top ?
606 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
607 fppar->added_space_bottom = lyxlayout.fill_bottom ?
608 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
609 if (lyxlayout.margintype == MARGIN_MANUAL)
610 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
611 if (lyxlayout.labeltype != LABEL_BIBLIO
613 delete fppar->bibkey;
618 // if there is no selection just set the layout
619 // of the current paragraph */
621 sel_start_cursor = cursor; // dummy selection
622 sel_end_cursor = cursor;
625 endpar = SetLayout(cursor, sel_start_cursor, sel_end_cursor, layout);
627 RedoParagraphs(sel_start_cursor, endpar);
629 // we have to reset the selection, because the
630 // geometry could have changed */
631 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
633 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
634 UpdateCounters(cursor.row);
637 SetCursor(tmpcursor.par, tmpcursor.pos, true);
641 // increment depth over selection and
642 // make a total rebreak of those paragraphs
643 void LyXText::IncDepth()
645 // If there is no selection, just use the current paragraph
647 sel_start_cursor = cursor; // dummy selection
648 sel_end_cursor = cursor;
651 // We end at the next paragraph with depth 0
652 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
653 LyXParagraph * undoendpar = endpar;
655 if (endpar && endpar->GetDepth()) {
656 while (endpar && endpar->GetDepth()) {
657 endpar = endpar->LastPhysicalPar()->Next();
662 endpar = endpar->Next(); // because of parindents etc.
667 .par->ParFromPos(sel_start_cursor.pos)->previous,
670 LyXCursor tmpcursor = cursor; // store the current cursor
672 // ok we have a selection. This is always between sel_start_cursor
673 // and sel_end cursor
674 cursor = sel_start_cursor;
676 bool anything_changed = false;
679 // NOTE: you can't change the depth of a bibliography entry
680 if (cursor.par->footnoteflag ==
681 sel_start_cursor.par->footnoteflag
682 && textclasslist.Style(buffer->params.textclass,
683 cursor.par->GetLayout()
684 ).labeltype != LABEL_BIBLIO) {
685 LyXParagraph * prev =
686 cursor.par->FirstPhysicalPar()->Previous();
688 && (prev->GetDepth() - cursor.par->GetDepth() > 0
689 || (prev->GetDepth() == cursor.par->GetDepth()
690 && textclasslist.Style(buffer->params.textclass,
691 prev->GetLayout()).isEnvironment()))) {
692 cursor.par->FirstPhysicalPar()->depth++;
693 anything_changed = true;
696 if (cursor.par == sel_end_cursor.par)
698 cursor.par = cursor.par->Next();
701 // if nothing changed set all depth to 0
702 if (!anything_changed) {
703 cursor = sel_start_cursor;
704 while (cursor.par != sel_end_cursor.par) {
705 cursor.par->FirstPhysicalPar()->depth = 0;
706 cursor.par = cursor.par->Next();
708 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
709 cursor.par->FirstPhysicalPar()->depth = 0;
712 RedoParagraphs(sel_start_cursor, endpar);
714 // we have to reset the selection, because the
715 // geometry could have changed
716 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
718 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
719 UpdateCounters(cursor.row);
722 SetCursor(tmpcursor.par, tmpcursor.pos);
726 // decrement depth over selection and
727 // make a total rebreak of those paragraphs
728 void LyXText::DecDepth()
730 // if there is no selection just set the layout
731 // of the current paragraph
733 sel_start_cursor = cursor; // dummy selection
734 sel_end_cursor = cursor;
737 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
738 LyXParagraph * undoendpar = endpar;
740 if (endpar && endpar->GetDepth()) {
741 while (endpar && endpar->GetDepth()) {
742 endpar = endpar->LastPhysicalPar()->Next();
747 endpar = endpar->Next(); // because of parindents etc.
752 .par->ParFromPos(sel_start_cursor.pos)->previous,
755 LyXCursor tmpcursor = cursor; // store the current cursor
757 // ok we have a selection. This is always between sel_start_cursor
758 // and sel_end cursor
759 cursor = sel_start_cursor;
762 if (cursor.par->footnoteflag ==
763 sel_start_cursor.par->footnoteflag) {
764 if (cursor.par->FirstPhysicalPar()->depth)
765 cursor.par->FirstPhysicalPar()->depth--;
767 if (cursor.par == sel_end_cursor.par)
769 cursor.par = cursor.par->Next();
772 RedoParagraphs(sel_start_cursor, endpar);
774 // we have to reset the selection, because the
775 // geometry could have changed
776 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
778 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
779 UpdateCounters(cursor.row);
782 SetCursor(tmpcursor.par, tmpcursor.pos);
786 // set font over selection and make a total rebreak of those paragraphs
787 void LyXText::SetFont(LyXFont const & font, bool toggleall)
789 // if there is no selection just set the current_font
791 // Determine basis font
793 if (cursor.pos < BeginningOfMainBody(cursor.par))
794 layoutfont = GetFont(cursor.par, -2);
796 layoutfont = GetFont(cursor.par, -1);
797 // Update current font
798 real_current_font.update(font,
799 buffer->params.language_info,
802 // Reduce to implicit settings
803 current_font = real_current_font;
804 current_font.reduce(layoutfont);
805 // And resolve it completely
806 real_current_font.realize(layoutfont);
810 LyXCursor tmpcursor = cursor; // store the current cursor
812 // ok we have a selection. This is always between sel_start_cursor
813 // and sel_end cursor
816 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
817 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
818 cursor = sel_start_cursor;
819 while (cursor.par != sel_end_cursor.par ||
820 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
821 && cursor.pos < sel_end_cursor.pos))
823 if (cursor.pos < cursor.par->Last()
824 && cursor.par->footnoteflag
825 == sel_start_cursor.par->footnoteflag) {
826 // an open footnote should behave
828 LyXFont newfont = GetFont(cursor.par, cursor.pos);
830 buffer->params.language_info,
832 SetCharFont(cursor.par, cursor.pos, newfont);
836 cursor.par = cursor.par->Next();
840 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
842 // we have to reset the selection, because the
843 // geometry could have changed
844 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
846 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
849 SetCursor(tmpcursor.par, tmpcursor.pos);
853 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
855 Row * tmprow = cur.row;
856 long y = cur.y - tmprow->baseline;
858 SetHeightOfRow(tmprow);
859 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
860 // find the first row of the paragraph
861 if (first_phys_par != tmprow->par)
862 while (tmprow->previous
863 && tmprow->previous->par != first_phys_par) {
864 tmprow = tmprow->previous;
866 SetHeightOfRow(tmprow);
868 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
869 tmprow = tmprow->previous;
871 SetHeightOfRow(tmprow);
874 // we can set the refreshing parameters now
875 status = LyXText::NEED_MORE_REFRESH;
877 refresh_row = tmprow;
878 SetCursor(cur.par, cur.pos);
882 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
884 Row * tmprow = cur.row;
886 long y = cur.y - tmprow->baseline;
887 SetHeightOfRow(tmprow);
888 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
889 // find the first row of the paragraph
890 if (first_phys_par != tmprow->par)
891 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
892 tmprow = tmprow->previous;
895 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
896 tmprow = tmprow->previous;
900 // we can set the refreshing parameters now
901 if (status == LyXText::UNCHANGED || y < refresh_y) {
903 refresh_row = tmprow;
905 status = LyXText::NEED_MORE_REFRESH;
906 SetCursor(cur.par, cur.pos);
910 /* deletes and inserts again all paragaphs between the cursor
911 * and the specified par
912 * This function is needed after SetLayout and SetFont etc. */
913 void LyXText::RedoParagraphs(LyXCursor const & cur,
914 LyXParagraph const * endpar) const
917 LyXParagraph * tmppar, * first_phys_par;
919 Row * tmprow = cur.row;
921 long y = cur.y - tmprow->baseline;
923 if (!tmprow->previous){
924 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
926 first_phys_par = tmprow->par->FirstPhysicalPar();
927 // find the first row of the paragraph
928 if (first_phys_par != tmprow->par)
929 while (tmprow->previous &&
930 (tmprow->previous->par != first_phys_par)) {
931 tmprow = tmprow->previous;
934 while (tmprow->previous
935 && tmprow->previous->par == first_phys_par) {
936 tmprow = tmprow->previous;
941 // we can set the refreshing parameters now
942 status = LyXText::NEED_MORE_REFRESH;
944 refresh_row = tmprow->previous; /* the real refresh row will
945 be deleted, so I store
949 tmppar = tmprow->next->par;
952 while (tmppar != endpar) {
953 RemoveRow(tmprow->next);
955 tmppar = tmprow->next->par;
960 // remove the first one
961 tmprow2 = tmprow; /* this is because tmprow->previous
963 tmprow = tmprow->previous;
966 tmppar = first_phys_par;
970 InsertParagraph(tmppar, tmprow);
973 while (tmprow->next && tmprow->next->par == tmppar)
974 tmprow = tmprow->next;
975 tmppar = tmppar->Next();
977 } while (tmppar != endpar);
979 // this is because of layout changes
981 refresh_y -= refresh_row->height;
982 SetHeightOfRow(refresh_row);
984 refresh_row = firstrow;
986 SetHeightOfRow(refresh_row);
989 if (tmprow && tmprow->next)
990 SetHeightOfRow(tmprow->next);
994 bool LyXText::FullRebreak()
996 if (need_break_row) {
997 BreakAgain(need_break_row);
1005 /* important for the screen */
1008 /* the cursor set functions have a special mechanism. When they
1009 * realize, that you left an empty paragraph, they will delete it.
1010 * They also delete the corresponding row */
1012 // need the selection cursor:
1013 void LyXText::SetSelection()
1016 last_sel_cursor = sel_cursor;
1017 sel_start_cursor = sel_cursor;
1018 sel_end_cursor = sel_cursor;
1023 // first the toggling area
1024 if (cursor.y < last_sel_cursor.y
1025 || (cursor.y == last_sel_cursor.y
1026 && cursor.x < last_sel_cursor.x)) {
1027 toggle_end_cursor = last_sel_cursor;
1028 toggle_cursor = cursor;
1030 toggle_end_cursor = cursor;
1031 toggle_cursor = last_sel_cursor;
1034 last_sel_cursor = cursor;
1036 // and now the whole selection
1038 if (sel_cursor.par == cursor.par)
1039 if (sel_cursor.pos < cursor.pos) {
1040 sel_end_cursor = cursor;
1041 sel_start_cursor = sel_cursor;
1043 sel_end_cursor = sel_cursor;
1044 sel_start_cursor = cursor;
1046 else if (sel_cursor.y < cursor.y ||
1047 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
1048 sel_end_cursor = cursor;
1049 sel_start_cursor = sel_cursor;
1052 sel_end_cursor = sel_cursor;
1053 sel_start_cursor = cursor;
1056 // a selection with no contents is not a selection
1057 if (sel_start_cursor.x == sel_end_cursor.x &&
1058 sel_start_cursor.y == sel_end_cursor.y)
1061 // Stuff what we got on the clipboard. Even if there is no selection.
1063 // There is a problem with having the stuffing here in that the
1064 // larger the selection the slower LyX will get. This can be
1065 // solved by running the line below only when the selection has
1066 // finished. The solution used currently just works, to make it
1067 // faster we need to be more clever and probably also have more
1068 // calls to stuffClipboard. (Lgb)
1069 owner_->stuffClipboard(selectionAsString());
1073 string LyXText::selectionAsString() const
1075 if (!selection) return string();
1078 // Special handling if the whole selection is within one paragraph
1079 if (sel_start_cursor.par == sel_end_cursor.par) {
1080 result += sel_start_cursor.par->String(sel_start_cursor.pos,
1081 sel_end_cursor.pos);
1085 // The selection spans more than one paragraph
1087 // First paragraph in selection
1088 result += sel_start_cursor.par->String(sel_start_cursor.pos,
1089 sel_start_cursor.par->Last());
1091 // The paragraphs in between (if any)
1092 LyXCursor tmpcur(sel_start_cursor);
1093 tmpcur.par = tmpcur.par->Next();
1094 while (tmpcur.par != sel_end_cursor.par) {
1095 result += tmpcur.par->String(false);
1096 tmpcur.par = tmpcur.par->Next(); // Or NextAfterFootnote??
1099 // Last paragraph in selection
1100 result += sel_end_cursor.par->String(0, sel_end_cursor.pos);
1106 void LyXText::ClearSelection() const
1113 void LyXText::CursorHome() const
1115 SetCursor(cursor.par, cursor.row->pos);
1119 void LyXText::CursorEnd() const
1121 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1122 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1124 if (cursor.par->Last() &&
1125 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1126 || cursor.par->IsNewline(RowLast(cursor.row))))
1127 SetCursor(cursor.par, RowLast(cursor.row));
1129 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1131 if (cursor.par->table) {
1132 int cell = NumberOfCell(cursor.par, cursor.pos);
1133 if (cursor.par->table->RowHasContRow(cell) &&
1134 cursor.par->table->CellHasContRow(cell)<0) {
1135 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1136 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1138 if (cursor.par->Last() &&
1139 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1140 || cursor.par->IsNewline(RowLast(cursor.row))))
1141 SetCursor(cursor.par, RowLast(cursor.row));
1143 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1150 void LyXText::CursorTop() const
1152 while (cursor.par->Previous())
1153 cursor.par = cursor.par->Previous();
1154 SetCursor(cursor.par, 0);
1158 void LyXText::CursorBottom() const
1160 while (cursor.par->Next())
1161 cursor.par = cursor.par->Next();
1162 SetCursor(cursor.par, cursor.par->Last());
1166 /* returns a pointer to the row near the specified y-coordinate
1167 * (relative to the whole text). y is set to the real beginning
1169 Row * LyXText::GetRowNearY(long & y) const
1171 Row * tmprow = firstrow;
1174 while (tmprow->next && tmpy + tmprow->height <= y) {
1175 tmpy += tmprow->height;
1176 tmprow = tmprow->next;
1179 y = tmpy; // return the real y
1184 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1186 // If the mask is completely neutral, tell user
1187 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1188 // Could only happen with user style
1189 owner_->owner()->getMiniBuffer()
1190 ->Set(_("No font change defined. Use Character under"
1191 " the Layout menu to define font change."));
1195 // Try implicit word selection
1196 // If there is a change in the language the implicit word selection
1198 LyXCursor resetCursor = cursor;
1199 bool implicitSelection = (font.language() == ignore_language)
1200 ? SelectWordWhenUnderCursor() : false;
1203 SetFont(font, toggleall);
1205 /* Implicit selections are cleared afterwards and cursor is set to the
1206 original position. */
1207 if (implicitSelection) {
1209 cursor = resetCursor;
1210 SetCursor( cursor.par, cursor.pos );
1211 sel_cursor = cursor;
1216 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1218 if (textclasslist.Style(buffer->params.textclass,
1219 par->GetLayout()).labeltype != LABEL_MANUAL)
1222 return par->BeginningOfMainBody();
1226 /* if there is a selection, reset every environment you can find
1227 * in the selection, otherwise just the environment you are in */
1228 void LyXText::MeltFootnoteEnvironment()
1230 LyXParagraph * tmppar, * firsttmppar;
1234 /* is is only allowed, if the cursor is IN an open footnote.
1235 * Otherwise it is too dangerous */
1236 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1239 SetUndo(Undo::FINISH,
1240 cursor.par->PreviousBeforeFootnote()->previous,
1241 cursor.par->NextAfterFootnote()->next);
1243 /* ok, move to the beginning of the footnote. */
1244 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1245 cursor.par = cursor.par->Previous();
1247 SetCursor(cursor.par, cursor.par->Last());
1248 /* this is just faster than using CursorLeft(); */
1250 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1251 tmppar = firsttmppar;
1252 /* tmppar is now the paragraph right before the footnote */
1254 bool first_footnote_par_is_not_empty = tmppar->next->size();
1257 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1258 tmppar = tmppar->next; /* I use next instead of Next(),
1259 * because there cannot be any
1260 * footnotes in a footnote
1262 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1264 /* remember the captions and empty paragraphs */
1265 if ((textclasslist.Style(buffer->params.textclass,
1266 tmppar->GetLayout())
1267 .labeltype == LABEL_SENSITIVE)
1269 tmppar->SetLayout(0);
1272 // now we will paste the ex-footnote, if the layouts allow it
1273 // first restore the layout of the paragraph right behind
1276 tmppar->next->MakeSameLayout(cursor.par);
1279 if ((!tmppar->GetLayout() && !tmppar->table)
1281 && (!tmppar->Next()->Last()
1282 || tmppar->Next()->HasSameLayout(tmppar)))) {
1283 if (tmppar->Next()->Last()
1284 && tmppar->Next()->IsLineSeparator(0))
1285 tmppar->Next()->Erase(0);
1286 tmppar->PasteParagraph();
1289 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1290 * by the pasting of the beginning */
1292 /* then the beginning */
1293 /* if there is no space between the text and the footnote, so we insert
1295 * (only if the previous par and the footnotepar are not empty!) */
1296 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1297 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1298 if (firsttmppar->size()
1299 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1300 && first_footnote_par_is_not_empty) {
1301 firsttmppar->next->InsertChar(0, ' ');
1303 firsttmppar->PasteParagraph();
1306 /* now redo the paragaphs */
1307 RedoParagraphs(cursor, tmppar);
1309 SetCursor(cursor.par, cursor.pos);
1311 /* sometimes it can happen, that there is a counter change */
1312 Row * row = cursor.row;
1313 while (row->next && row->par != tmppar && row->next->par != tmppar)
1315 UpdateCounters(row);
1322 /* the DTP switches for paragraphs. LyX will store them in the
1323 * first physicla paragraph. When a paragraph is broken, the top settings
1324 * rest, the bottom settings are given to the new one. So I can make shure,
1325 * they do not duplicate themself and you cannnot make dirty things with
1328 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1329 bool pagebreak_top, bool pagebreak_bottom,
1330 VSpace const & space_top,
1331 VSpace const & space_bottom,
1333 string labelwidthstring,
1336 LyXCursor tmpcursor = cursor;
1338 sel_start_cursor = cursor;
1339 sel_end_cursor = cursor;
1342 // make sure that the depth behind the selection are restored, too
1343 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1344 LyXParagraph * undoendpar = endpar;
1346 if (endpar && endpar->GetDepth()) {
1347 while (endpar && endpar->GetDepth()) {
1348 endpar = endpar->LastPhysicalPar()->Next();
1349 undoendpar = endpar;
1353 endpar = endpar->Next(); // because of parindents etc.
1358 .par->ParFromPos(sel_start_cursor.pos)->previous,
1362 LyXParagraph * tmppar = sel_end_cursor.par;
1363 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1364 SetCursor(tmppar->FirstPhysicalPar(), 0);
1365 status = LyXText::NEED_MORE_REFRESH;
1366 refresh_row = cursor.row;
1367 refresh_y = cursor.y - cursor.row->baseline;
1368 if (cursor.par->footnoteflag ==
1369 sel_start_cursor.par->footnoteflag) {
1370 cursor.par->line_top = line_top;
1371 cursor.par->line_bottom = line_bottom;
1372 cursor.par->pagebreak_top = pagebreak_top;
1373 cursor.par->pagebreak_bottom = pagebreak_bottom;
1374 cursor.par->added_space_top = space_top;
1375 cursor.par->added_space_bottom = space_bottom;
1376 // does the layout allow the new alignment?
1377 if (align == LYX_ALIGN_LAYOUT)
1378 align = textclasslist
1379 .Style(buffer->params.textclass,
1380 cursor.par->GetLayout()).align;
1381 if (align & textclasslist
1382 .Style(buffer->params.textclass,
1383 cursor.par->GetLayout()).alignpossible) {
1384 if (align == textclasslist
1385 .Style(buffer->params.textclass,
1386 cursor.par->GetLayout()).align)
1387 cursor.par->align = LYX_ALIGN_LAYOUT;
1389 cursor.par->align = align;
1391 cursor.par->SetLabelWidthString(labelwidthstring);
1392 cursor.par->noindent = noindent;
1395 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1398 RedoParagraphs(sel_start_cursor, endpar);
1401 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1402 sel_cursor = cursor;
1403 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1405 SetCursor(tmpcursor.par, tmpcursor.pos);
1409 void LyXText::SetParagraphExtraOpt(int type,
1411 char const * widthp,
1412 int alignment, bool hfill,
1413 bool start_minipage)
1415 LyXCursor tmpcursor = cursor;
1416 LyXParagraph * tmppar;
1418 sel_start_cursor = cursor;
1419 sel_end_cursor = cursor;
1422 // make sure that the depth behind the selection are restored, too
1423 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1424 LyXParagraph * undoendpar = endpar;
1426 if (endpar && endpar->GetDepth()) {
1427 while (endpar && endpar->GetDepth()) {
1428 endpar = endpar->LastPhysicalPar()->Next();
1429 undoendpar = endpar;
1433 endpar = endpar->Next(); // because of parindents etc.
1438 .par->ParFromPos(sel_start_cursor.pos)->previous,
1441 tmppar = sel_end_cursor.par;
1442 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1443 SetCursor(tmppar->FirstPhysicalPar(), 0);
1444 status = LyXText::NEED_MORE_REFRESH;
1445 refresh_row = cursor.row;
1446 refresh_y = cursor.y - cursor.row->baseline;
1447 if (cursor.par->footnoteflag ==
1448 sel_start_cursor.par->footnoteflag) {
1449 if (type == LyXParagraph::PEXTRA_NONE) {
1450 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1451 cursor.par->UnsetPExtraType();
1452 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1455 cursor.par->SetPExtraType(type, width, widthp);
1456 cursor.par->pextra_hfill = hfill;
1457 cursor.par->pextra_start_minipage = start_minipage;
1458 cursor.par->pextra_alignment = alignment;
1461 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1463 RedoParagraphs(sel_start_cursor, endpar);
1465 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1466 sel_cursor = cursor;
1467 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1469 SetCursor(tmpcursor.par, tmpcursor.pos);
1473 char loweralphaCounter(int n)
1475 if (n < 1 || n > 26)
1481 char alphaCounter(int n)
1483 if (n < 1 || n > 26)
1489 char hebrewCounter(int n)
1491 static const char hebrew[22] = {
1492 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1493 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1494 '÷', 'ø', 'ù', 'ú'
1496 if (n < 1 || n > 22)
1502 static char const * romanCounter(int n)
1504 static char const * roman[20] = {
1505 "i", "ii", "iii", "iv", "v",
1506 "vi", "vii", "viii", "ix", "x",
1507 "xi", "xii", "xiii", "xiv", "xv",
1508 "xvi", "xvii", "xviii", "xix", "xx"
1510 if (n < 1 || n > 20)
1516 // set the counter of a paragraph. This includes the labels
1517 void LyXText::SetCounter(LyXParagraph * par) const
1519 // this is only relevant for the beginning of paragraph
1520 par = par->FirstPhysicalPar();
1522 LyXLayout const & layout =
1523 textclasslist.Style(buffer->params.textclass,
1526 LyXTextClass const & textclass =
1527 textclasslist.TextClass(buffer->params.textclass);
1529 /* copy the prev-counters to this one, unless this is the start of a
1530 footnote or of a bibliography or the very first paragraph */
1532 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1533 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1534 && par->footnotekind == LyXParagraph::FOOTNOTE)
1535 && !(textclasslist.Style(buffer->params.textclass,
1536 par->Previous()->GetLayout()
1537 ).labeltype != LABEL_BIBLIO
1538 && layout.labeltype == LABEL_BIBLIO)) {
1539 for (int i = 0; i < 10; ++i) {
1540 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1542 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1543 if (!par->appendix && par->start_of_appendix){
1544 par->appendix = true;
1545 for (int i = 0; i < 10; ++i) {
1546 par->setCounter(i, 0);
1549 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1550 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1553 for (int i = 0; i < 10; ++i) {
1554 par->setCounter(i, 0);
1556 par->appendix = par->start_of_appendix;
1561 // if this is an open marginnote and this is the first
1562 // entry in the marginnote and the enclosing
1563 // environment is an enum/item then correct for the
1564 // LaTeX behaviour (ARRae)
1565 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1566 && par->footnotekind == LyXParagraph::MARGIN
1568 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1569 && (par->PreviousBeforeFootnote()
1570 && textclasslist.Style(buffer->params.textclass,
1571 par->PreviousBeforeFootnote()->GetLayout()
1572 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1573 // Any itemize or enumerate environment in a marginnote
1574 // that is embedded in an itemize or enumerate
1575 // paragraph is seen by LaTeX as being at a deeper
1576 // level within that enclosing itemization/enumeration
1577 // even if there is a "standard" layout at the start of
1583 /* Maybe we have to increment the enumeration depth.
1584 * BUT, enumeration in a footnote is considered in isolation from its
1585 * surrounding paragraph so don't increment if this is the
1586 * first line of the footnote
1587 * AND, bibliographies can't have their depth changed ie. they
1588 * are always of depth 0
1591 && par->Previous()->GetDepth() < par->GetDepth()
1592 && textclasslist.Style(buffer->params.textclass,
1593 par->Previous()->GetLayout()
1594 ).labeltype == LABEL_COUNTER_ENUMI
1595 && par->enumdepth < 3
1596 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1597 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1598 && par->footnotekind == LyXParagraph::FOOTNOTE)
1599 && layout.labeltype != LABEL_BIBLIO) {
1603 /* Maybe we have to decrement the enumeration depth, see note above */
1605 && par->Previous()->GetDepth() > par->GetDepth()
1606 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1607 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1608 && par->footnotekind == LyXParagraph::FOOTNOTE)
1609 && layout.labeltype != LABEL_BIBLIO) {
1610 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1611 par->setCounter(6 + par->enumdepth,
1612 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1613 /* reset the counters.
1614 * A depth change is like a breaking layout
1616 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1617 par->setCounter(i, 0);
1620 if (!par->labelstring.empty()) {
1621 par->labelstring.erase();
1624 if (layout.margintype == MARGIN_MANUAL) {
1625 if (par->labelwidthstring.empty()) {
1626 par->SetLabelWidthString(layout.labelstring());
1629 par->SetLabelWidthString(string());
1632 /* is it a layout that has an automatic label ? */
1633 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1635 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1636 if (i >= 0 && i<= buffer->params.secnumdepth) {
1637 par->incCounter(i); // increment the counter
1639 // Is there a label? Useful for Chapter layout
1640 if (!par->appendix){
1641 if (!layout.labelstring().empty())
1642 par->labelstring = layout.labelstring();
1644 par->labelstring.erase();
1646 if (!layout.labelstring_appendix().empty())
1647 par->labelstring = layout.labelstring_appendix();
1649 par->labelstring.erase();
1653 std::ostringstream s;
1657 if (!par->appendix) {
1658 switch (2 * LABEL_FIRST_COUNTER -
1659 textclass.maxcounter() + i) {
1660 case LABEL_COUNTER_CHAPTER:
1661 s << par->getCounter(i);
1663 case LABEL_COUNTER_SECTION:
1664 s << par->getCounter(i - 1) << '.'
1665 << par->getCounter(i);
1667 case LABEL_COUNTER_SUBSECTION:
1668 s << par->getCounter(i - 2) << '.'
1669 << par->getCounter(i - 1) << '.'
1670 << par->getCounter(i);
1672 case LABEL_COUNTER_SUBSUBSECTION:
1673 s << par->getCounter(i - 3) << '.'
1674 << par->getCounter(i - 2) << '.'
1675 << par->getCounter(i - 1) << '.'
1676 << par->getCounter(i);
1679 case LABEL_COUNTER_PARAGRAPH:
1680 s << par->getCounter(i - 4) << '.'
1681 << par->getCounter(i - 3) << '.'
1682 << par->getCounter(i - 2) << '.'
1683 << par->getCounter(i - 1) << '.'
1684 << par->getCounter(i);
1686 case LABEL_COUNTER_SUBPARAGRAPH:
1687 s << par->getCounter(i - 5) << '.'
1688 << par->getCounter(i - 4) << '.'
1689 << par->getCounter(i - 3) << '.'
1690 << par->getCounter(i - 2) << '.'
1691 << par->getCounter(i - 1) << '.'
1692 << par->getCounter(i);
1696 s << par->getCounter(i) << '.';
1699 } else { // appendix
1700 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1701 case LABEL_COUNTER_CHAPTER:
1702 if (par->isRightToLeftPar())
1703 s << hebrewCounter(par->getCounter(i));
1705 s << alphaCounter(par->getCounter(i));
1707 case LABEL_COUNTER_SECTION:
1708 if (par->isRightToLeftPar())
1709 s << hebrewCounter(par->getCounter(i - 1));
1711 s << alphaCounter(par->getCounter(i - 1));
1714 << par->getCounter(i);
1717 case LABEL_COUNTER_SUBSECTION:
1718 if (par->isRightToLeftPar())
1719 s << hebrewCounter(par->getCounter(i - 2));
1721 s << alphaCounter(par->getCounter(i - 2));
1724 << par->getCounter(i-1) << '.'
1725 << par->getCounter(i);
1728 case LABEL_COUNTER_SUBSUBSECTION:
1729 if (par->isRightToLeftPar())
1730 s << hebrewCounter(par->getCounter(i-3));
1732 s << alphaCounter(par->getCounter(i-3));
1735 << par->getCounter(i-2) << '.'
1736 << par->getCounter(i-1) << '.'
1737 << par->getCounter(i);
1740 case LABEL_COUNTER_PARAGRAPH:
1741 if (par->isRightToLeftPar())
1742 s << hebrewCounter(par->getCounter(i-4));
1744 s << alphaCounter(par->getCounter(i-4));
1747 << par->getCounter(i-3) << '.'
1748 << par->getCounter(i-2) << '.'
1749 << par->getCounter(i-1) << '.'
1750 << par->getCounter(i);
1753 case LABEL_COUNTER_SUBPARAGRAPH:
1754 if (par->isRightToLeftPar())
1755 s << hebrewCounter(par->getCounter(i-5));
1757 s << alphaCounter(par->getCounter(i-5));
1760 << par->getCounter(i-4) << '.'
1761 << par->getCounter(i-3) << '.'
1762 << par->getCounter(i-2) << '.'
1763 << par->getCounter(i-1) << '.'
1764 << par->getCounter(i);
1768 // Can this ever be reached? And in the
1769 // case it is, how can this be correct?
1771 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1777 par->labelstring += s.str().c_str();
1778 // We really want to remove the c_str as soon as
1782 char * tmps = s.str();
1783 par->labelstring += tmps;
1787 for (i++; i < 10; ++i) {
1788 // reset the following counters
1789 par->setCounter(i, 0);
1791 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1792 for (i++; i < 10; ++i) {
1793 // reset the following counters
1794 par->setCounter(i, 0);
1796 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1797 par->incCounter(i + par->enumdepth);
1798 int number = par->getCounter(i + par->enumdepth);
1801 std::ostringstream s;
1805 switch (par->enumdepth) {
1807 if (par->isRightToLeftPar())
1809 << hebrewCounter(number)
1813 << loweralphaCounter(number)
1817 if (par->isRightToLeftPar())
1818 s << '.' << romanCounter(number);
1820 s << romanCounter(number) << '.';
1823 if (par->isRightToLeftPar())
1825 << alphaCounter(number);
1827 s << alphaCounter(number)
1831 if (par->isRightToLeftPar())
1838 par->labelstring = s.str().c_str();
1839 // we really want to get rid of that c_str()
1842 char * tmps = s.str();
1843 par->labelstring = tmps;
1847 for (i += par->enumdepth + 1; i < 10; ++i)
1848 par->setCounter(i, 0); /* reset the following counters */
1851 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1852 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1854 int number = par->getCounter(i);
1856 par->bibkey = new InsetBibKey();
1857 par->bibkey->setCounter(number);
1858 par->labelstring = layout.labelstring();
1860 // In biblio should't be following counters but...
1862 string s = layout.labelstring();
1864 // the caption hack:
1866 if (layout.labeltype == LABEL_SENSITIVE) {
1867 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1868 && (par->footnotekind == LyXParagraph::FIG
1869 || par->footnotekind == LyXParagraph::WIDE_FIG))
1870 s = (par->getParLanguage()->lang == "hebrew")
1871 ? ":øåéà " : "Figure:";
1872 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1873 && (par->footnotekind == LyXParagraph::TAB
1874 || par->footnotekind == LyXParagraph::WIDE_TAB))
1875 s = (par->getParLanguage()->lang == "hebrew")
1876 ? ":äìáè" : "Table:";
1877 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1878 && par->footnotekind == LyXParagraph::ALGORITHM)
1879 s = (par->getParLanguage()->lang == "hebrew")
1880 ? ":Ãúéøåâìà " : "Algorithm:";
1882 /* par->SetLayout(0);
1883 s = layout->labelstring; */
1884 s = (par->getParLanguage()->lang == "hebrew")
1885 ? " :úåòîùî øñç" : "Senseless: ";
1888 par->labelstring = s;
1890 /* reset the enumeration counter. They are always resetted
1891 * when there is any other layout between */
1892 for (int i = 6 + par->enumdepth; i < 10; ++i)
1893 par->setCounter(i, 0);
1898 /* Updates all counters BEHIND the row. Changed paragraphs
1899 * with a dynamic left margin will be rebroken. */
1900 void LyXText::UpdateCounters(Row * row) const
1909 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1910 par = row->par->LastPhysicalPar()->Next();
1912 par = row->par->next;
1917 while (row->par != par)
1922 /* now check for the headline layouts. remember that they
1923 * have a dynamic left margin */
1925 && ( textclasslist.Style(buffer->params.textclass,
1926 par->layout).margintype == MARGIN_DYNAMIC
1927 || textclasslist.Style(buffer->params.textclass,
1928 par->layout).labeltype == LABEL_SENSITIVE)
1931 /* Rebreak the paragraph */
1932 RemoveParagraph(row);
1933 AppendParagraph(row);
1935 /* think about the damned open footnotes! */
1936 while (par->Next() &&
1937 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1938 || par->Next()->IsDummy())){
1940 if (par->IsDummy()) {
1941 while (row->par != par)
1943 RemoveParagraph(row);
1944 AppendParagraph(row);
1949 par = par->LastPhysicalPar()->Next();
1955 /* insets an inset. */
1956 void LyXText::InsertInset(Inset *inset)
1958 if (!cursor.par->InsertInsetAllowed(inset))
1960 SetUndo(Undo::INSERT,
1961 cursor.par->ParFromPos(cursor.pos)->previous,
1962 cursor.par->ParFromPos(cursor.pos)->next);
1963 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1964 cursor.par->InsertInset(cursor.pos, inset);
1965 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1966 * The character will not be inserted a
1971 #ifdef USE_OLD_CUT_AND_PASTE
1972 // this is for the simple cut and paste mechanism
1973 static LyXParagraph * simple_cut_buffer = 0;
1974 static char simple_cut_buffer_textclass = 0;
1976 void DeleteSimpleCutBuffer()
1978 if (!simple_cut_buffer)
1980 LyXParagraph * tmppar;
1982 while (simple_cut_buffer) {
1983 tmppar = simple_cut_buffer;
1984 simple_cut_buffer = simple_cut_buffer->next;
1987 simple_cut_buffer = 0;
1991 void LyXText::copyEnvironmentType()
1993 copylayouttype = cursor.par->GetLayout();
1997 void LyXText::pasteEnvironmentType()
1999 SetLayout(copylayouttype);
2002 #ifdef USE_OLD_CUT_AND_PASTE
2003 void LyXText::CutSelection(bool doclear)
2005 // This doesn't make sense, if there is no selection
2009 // OK, we have a selection. This is always between sel_start_cursor
2010 // and sel_end cursor
2011 LyXParagraph * tmppar;
2013 // Check whether there are half footnotes in the selection
2014 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2015 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2016 tmppar = sel_start_cursor.par;
2017 while (tmppar != sel_end_cursor.par){
2018 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2019 WriteAlert(_("Impossible operation"),
2020 _("Don't know what to do with half floats."),
2024 tmppar = tmppar->Next();
2028 /* table stuff -- begin */
2029 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2030 if ( sel_start_cursor.par != sel_end_cursor.par) {
2031 WriteAlert(_("Impossible operation"),
2032 _("Don't know what to do with half tables."),
2036 sel_start_cursor.par->table->Reinit();
2038 /* table stuff -- end */
2040 // make sure that the depth behind the selection are restored, too
2041 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2042 LyXParagraph * undoendpar = endpar;
2044 if (endpar && endpar->GetDepth()) {
2045 while (endpar && endpar->GetDepth()) {
2046 endpar = endpar->LastPhysicalPar()->Next();
2047 undoendpar = endpar;
2049 } else if (endpar) {
2050 endpar = endpar->Next(); // because of parindents etc.
2053 SetUndo(Undo::DELETE,
2055 .par->ParFromPos(sel_start_cursor.pos)->previous,
2058 // clear the simple_cut_buffer
2059 DeleteSimpleCutBuffer();
2061 // set the textclass
2062 simple_cut_buffer_textclass = buffer->params.textclass;
2064 #ifdef WITH_WARNINGS
2065 #warning Asger: Make cut more intelligent here.
2068 White paper for "intelligent" cutting:
2070 Example: "This is our text."
2071 Using " our " as selection, cutting will give "This istext.".
2072 Using "our" as selection, cutting will give "This is text.".
2073 Using " our" as selection, cutting will give "This is text.".
2074 Using "our " as selection, cutting will give "This is text.".
2076 All those four selections will (however) paste identically:
2077 Pasting with the cursor right after the "is" will give the
2078 original text with all four selections.
2080 The rationale is to be intelligent such that words are copied,
2081 cut and pasted in a functional manner.
2083 This is not implemented yet. (Asger)
2085 The changes below sees to do a lot of what you want. However
2086 I have not verified that all cases work as they should:
2088 - cut in multiple row
2090 - cut across footnotes and paragraph
2091 My simplistic tests show that the idea are basically sound but
2092 there are some items to fix up...we only need to find them
2095 As do redo Asger's example above (with | beeing the cursor in the
2096 result after cutting.):
2098 Example: "This is our text."
2099 Using " our " as selection, cutting will give "This is|text.".
2100 Using "our" as selection, cutting will give "This is | text.".
2101 Using " our" as selection, cutting will give "This is| text.".
2102 Using "our " as selection, cutting will give "This is |text.".
2107 // there are two cases: cut only within one paragraph or
2108 // more than one paragraph
2110 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2111 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2112 // only within one paragraph
2113 simple_cut_buffer = new LyXParagraph;
2114 LyXParagraph::size_type i =
2115 sel_start_cursor.pos;
2116 for (; i < sel_end_cursor.pos; ++i) {
2117 /* table stuff -- begin */
2118 if (sel_start_cursor.par->table
2119 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2120 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2121 sel_start_cursor.pos++;
2123 /* table stuff -- end */
2124 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2125 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2127 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2129 endpar = sel_end_cursor.par->Next();
2131 // cut more than one paragraph
2134 ->BreakParagraphConservative(sel_end_cursor.pos);
2135 sel_end_cursor.par = sel_end_cursor.par->Next();
2136 sel_end_cursor.pos = 0;
2138 cursor = sel_end_cursor;
2140 sel_start_cursor.par
2141 ->BreakParagraphConservative(sel_start_cursor.pos);
2142 // store the endparagraph for redoing later
2143 endpar = sel_end_cursor.par->Next(); /* needed because
2148 // store the selection
2149 simple_cut_buffer = sel_start_cursor.par
2150 ->ParFromPos(sel_start_cursor.pos)->next;
2151 simple_cut_buffer->previous = 0;
2152 sel_end_cursor.par->previous->next = 0;
2154 // cut the selection
2155 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2156 = sel_end_cursor.par;
2158 sel_end_cursor.par->previous
2159 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2161 // care about footnotes
2162 if (simple_cut_buffer->footnoteflag) {
2163 LyXParagraph * tmppar = simple_cut_buffer;
2165 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2166 tmppar = tmppar->next;
2170 // the cut selection should begin with standard layout
2171 simple_cut_buffer->Clear();
2173 // paste the paragraphs again, if possible
2175 sel_start_cursor.par->Next()->ClearParagraph();
2176 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2178 !sel_start_cursor.par->Next()->Last())
2179 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2182 // sometimes necessary
2184 sel_start_cursor.par->ClearParagraph();
2186 RedoParagraphs(sel_start_cursor, endpar);
2189 cursor = sel_start_cursor;
2190 SetCursor(cursor.par, cursor.pos);
2191 sel_cursor = cursor;
2192 UpdateCounters(cursor.row);
2195 #else ///////////////////////////////////////////////////////////////////
2197 void LyXText::CutSelection(bool doclear)
2199 // This doesn't make sense, if there is no selection
2203 // OK, we have a selection. This is always between sel_start_cursor
2204 // and sel_end cursor
2205 LyXParagraph * tmppar;
2207 // Check whether there are half footnotes in the selection
2208 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2209 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2210 tmppar = sel_start_cursor.par;
2211 while (tmppar != sel_end_cursor.par){
2212 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2213 WriteAlert(_("Impossible operation"),
2214 _("Don't know what to do with half floats."),
2218 tmppar = tmppar->Next();
2222 /* table stuff -- begin */
2223 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2224 if ( sel_start_cursor.par != sel_end_cursor.par) {
2225 WriteAlert(_("Impossible operation"),
2226 _("Don't know what to do with half tables."),
2230 sel_start_cursor.par->table->Reinit();
2232 /* table stuff -- end */
2234 // make sure that the depth behind the selection are restored, too
2235 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2236 LyXParagraph * undoendpar = endpar;
2238 if (endpar && endpar->GetDepth()) {
2239 while (endpar && endpar->GetDepth()) {
2240 endpar = endpar->LastPhysicalPar()->Next();
2241 undoendpar = endpar;
2243 } else if (endpar) {
2244 endpar = endpar->Next(); // because of parindents etc.
2247 SetUndo(Undo::DELETE, sel_start_cursor
2248 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2252 // there are two cases: cut only within one paragraph or
2253 // more than one paragraph
2254 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2255 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2256 // only within one paragraph
2257 endpar = sel_start_cursor.par;
2258 cap.cutSelection(sel_start_cursor.par, &endpar,
2259 sel_start_cursor.pos, sel_end_cursor.pos,
2260 buffer->params.textclass, doclear);
2262 endpar = sel_end_cursor.par;
2264 cap.cutSelection(sel_start_cursor.par, &endpar,
2265 sel_start_cursor.pos, sel_end_cursor.pos,
2266 buffer->params.textclass, doclear);
2267 cursor.par = sel_end_cursor.par = endpar;
2268 cursor.pos = sel_end_cursor.pos;
2270 endpar = endpar->Next();
2272 // sometimes necessary
2274 sel_start_cursor.par->ClearParagraph();
2276 RedoParagraphs(sel_start_cursor, endpar);
2279 cursor = sel_start_cursor;
2280 SetCursor(cursor.par, cursor.pos);
2281 sel_cursor = cursor;
2282 UpdateCounters(cursor.row);
2286 #ifdef USE_OLD_CUT_AND_PASTE
2287 void LyXText::CopySelection()
2289 // this doesnt make sense, if there is no selection
2293 // ok we have a selection. This is always between sel_start_cursor
2294 // and sel_end cursor
2295 LyXParagraph * tmppar;
2297 /* check wether there are half footnotes in the selection */
2298 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2299 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2300 tmppar = sel_start_cursor.par;
2301 while (tmppar != sel_end_cursor.par) {
2302 if (tmppar->footnoteflag !=
2303 sel_end_cursor.par->footnoteflag) {
2304 WriteAlert(_("Impossible operation"),
2305 _("Don't know what to do"
2306 " with half floats."),
2310 tmppar = tmppar->Next();
2314 /* table stuff -- begin */
2315 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2316 if ( sel_start_cursor.par != sel_end_cursor.par){
2317 WriteAlert(_("Impossible operation"),
2318 _("Don't know what to do with half tables."),
2323 /* table stuff -- end */
2325 // delete the simple_cut_buffer
2326 DeleteSimpleCutBuffer();
2328 // set the textclass
2329 simple_cut_buffer_textclass = buffer->params.textclass;
2331 // copy behind a space if there is one
2332 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2333 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2334 && (sel_start_cursor.par != sel_end_cursor.par
2335 || sel_start_cursor.pos < sel_end_cursor.pos))
2336 sel_start_cursor.pos++;
2338 // there are two cases: copy only within one paragraph
2339 // or more than one paragraph
2340 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2341 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2342 // only within one paragraph
2343 simple_cut_buffer = new LyXParagraph;
2344 LyXParagraph::size_type i = 0;
2345 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2346 sel_start_cursor.par->CopyIntoMinibuffer(i);
2347 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2350 // copy more than one paragraph
2351 // clone the paragraphs within the selection
2353 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2354 simple_cut_buffer = tmppar->Clone();
2355 LyXParagraph *tmppar2 = simple_cut_buffer;
2357 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2359 tmppar = tmppar->next;
2360 tmppar2->next = tmppar->Clone();
2361 tmppar2->next->previous = tmppar2;
2362 tmppar2 = tmppar2->next;
2366 // care about footnotes
2367 if (simple_cut_buffer->footnoteflag) {
2368 tmppar = simple_cut_buffer;
2370 tmppar->footnoteflag =
2371 LyXParagraph::NO_FOOTNOTE;
2372 tmppar = tmppar->next;
2376 // the simple_cut_buffer paragraph is too big
2377 LyXParagraph::size_type tmpi2 =
2378 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2379 for (; tmpi2; --tmpi2)
2380 simple_cut_buffer->Erase(0);
2382 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2384 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2385 while (tmppar2->size() > tmpi2) {
2386 tmppar2->Erase(tmppar2->size() - 1);
2391 #else //////////////////////////////////////////////////////////////////////
2393 void LyXText::CopySelection()
2395 // this doesnt make sense, if there is no selection
2399 // ok we have a selection. This is always between sel_start_cursor
2400 // and sel_end cursor
2401 LyXParagraph * tmppar;
2403 /* check wether there are half footnotes in the selection */
2404 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2405 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2406 tmppar = sel_start_cursor.par;
2407 while (tmppar != sel_end_cursor.par) {
2408 if (tmppar->footnoteflag !=
2409 sel_end_cursor.par->footnoteflag) {
2410 WriteAlert(_("Impossible operation"),
2411 _("Don't know what to do"
2412 " with half floats."),
2416 tmppar = tmppar->Next();
2420 /* table stuff -- begin */
2421 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2422 if ( sel_start_cursor.par != sel_end_cursor.par){
2423 WriteAlert(_("Impossible operation"),
2424 _("Don't know what to do with half tables."),
2429 /* table stuff -- end */
2431 // copy behind a space if there is one
2432 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2433 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2434 && (sel_start_cursor.par != sel_end_cursor.par
2435 || sel_start_cursor.pos < sel_end_cursor.pos))
2436 sel_start_cursor.pos++;
2440 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2441 sel_start_cursor.pos, sel_end_cursor.pos,
2442 buffer->params.textclass);
2446 #ifdef USE_OLD_CUT_AND_PASTE
2447 void LyXText::PasteSelection()
2449 // this does not make sense, if there is nothing to paste
2450 if (!simple_cut_buffer)
2453 LyXParagraph * tmppar;
2454 LyXParagraph * endpar;
2456 LyXCursor tmpcursor;
2458 // be carefull with footnotes in footnotes
2459 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2461 // check whether the cut_buffer includes a footnote
2462 tmppar = simple_cut_buffer;
2464 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2465 tmppar = tmppar->next;
2468 WriteAlert(_("Impossible operation"),
2469 _("Can't paste float into float!"),
2475 /* table stuff -- begin */
2476 if (cursor.par->table) {
2477 if (simple_cut_buffer->next) {
2478 WriteAlert(_("Impossible operation"),
2479 _("Table cell cannot include more than one paragraph!"),
2484 /* table stuff -- end */
2486 SetUndo(Undo::INSERT,
2487 cursor.par->ParFromPos(cursor.pos)->previous,
2488 cursor.par->ParFromPos(cursor.pos)->next);
2492 // There are two cases: cutbuffer only one paragraph or many
2493 if (!simple_cut_buffer->next) {
2494 // only within a paragraph
2496 tmppar = simple_cut_buffer->Clone();
2497 /* table stuff -- begin */
2498 bool table_too_small = false;
2499 if (tmpcursor.par->table) {
2500 while (simple_cut_buffer->size()
2501 && !table_too_small) {
2502 if (simple_cut_buffer->IsNewline(0)){
2503 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2505 simple_cut_buffer->Erase(0);
2506 if (tmpcursor.pos < tmpcursor.par->Last())
2509 table_too_small = true;
2511 // This is an attempt to fix the
2512 // "never insert a space at the
2513 // beginning of a paragraph" problem.
2514 if (tmpcursor.pos == 0
2515 && simple_cut_buffer->IsLineSeparator(0)) {
2516 simple_cut_buffer->Erase(0);
2518 simple_cut_buffer->CutIntoMinibuffer(0);
2519 simple_cut_buffer->Erase(0);
2520 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2526 /* table stuff -- end */
2527 // Some provisions should be done here for checking
2528 // if we are inserting at the beginning of a
2529 // paragraph. If there are a space at the beginning
2530 // of the text to insert and we are inserting at
2531 // the beginning of the paragraph the space should
2533 while (simple_cut_buffer->size()) {
2534 // This is an attempt to fix the
2535 // "never insert a space at the
2536 // beginning of a paragraph" problem.
2537 if (tmpcursor.pos == 0
2538 && simple_cut_buffer->IsLineSeparator(0)) {
2539 simple_cut_buffer->Erase(0);
2541 simple_cut_buffer->CutIntoMinibuffer(0);
2542 simple_cut_buffer->Erase(0);
2543 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2548 delete simple_cut_buffer;
2549 simple_cut_buffer = tmppar;
2550 endpar = tmpcursor.par->Next();
2555 // make a copy of the simple cut_buffer
2556 tmppar = simple_cut_buffer;
2557 LyXParagraph * simple_cut_clone = tmppar->Clone();
2558 LyXParagraph * tmppar2 = simple_cut_clone;
2559 if (cursor.par->footnoteflag){
2560 tmppar->footnoteflag = cursor.par->footnoteflag;
2561 tmppar->footnotekind = cursor.par->footnotekind;
2563 while (tmppar->next) {
2564 tmppar = tmppar->next;
2565 tmppar2->next = tmppar->Clone();
2566 tmppar2->next->previous = tmppar2;
2567 tmppar2 = tmppar2->next;
2568 if (cursor.par->footnoteflag){
2569 tmppar->footnoteflag = cursor.par->footnoteflag;
2570 tmppar->footnotekind = cursor.par->footnotekind;
2574 // make sure there is no class difference
2575 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2576 buffer->params.textclass,
2579 // make the simple_cut_buffer exactly the same layout than
2580 // the cursor paragraph
2581 simple_cut_buffer->MakeSameLayout(cursor.par);
2583 // find the end of the buffer
2584 LyXParagraph * lastbuffer = simple_cut_buffer;
2585 while (lastbuffer->Next())
2586 lastbuffer = lastbuffer->Next();
2588 bool paste_the_end = false;
2590 // open the paragraph for inserting the simple_cut_buffer
2592 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2593 cursor.par->BreakParagraphConservative(cursor.pos);
2594 paste_the_end = true;
2597 // set the end for redoing later
2598 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2601 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2602 cursor.par->ParFromPos(cursor.pos)->next;
2603 cursor.par->ParFromPos(cursor.pos)->next->previous =
2604 lastbuffer->ParFromPos(lastbuffer->Last());
2606 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2607 simple_cut_buffer->previous =
2608 cursor.par->ParFromPos(cursor.pos);
2610 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2611 lastbuffer = cursor.par;
2613 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2615 // store the new cursor position
2616 tmpcursor.par = lastbuffer;
2617 tmpcursor.pos = lastbuffer->Last();
2619 // maybe some pasting
2620 if (lastbuffer->Next() && paste_the_end) {
2621 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2622 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2624 } else if (!lastbuffer->Next()->Last()) {
2625 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2626 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2628 } else if (!lastbuffer->Last()) {
2629 lastbuffer->MakeSameLayout(lastbuffer->next);
2630 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2633 lastbuffer->Next()->ClearParagraph();
2636 // restore the simple cut buffer
2637 simple_cut_buffer = simple_cut_clone;
2640 RedoParagraphs(cursor, endpar);
2642 SetCursor(cursor.par, cursor.pos);
2645 sel_cursor = cursor;
2646 SetCursor(tmpcursor.par, tmpcursor.pos);
2648 UpdateCounters(cursor.row);
2651 #else ////////////////////////////////////////////////////////////////////
2653 void LyXText::PasteSelection()
2657 // this does not make sense, if there is nothing to paste
2658 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2661 SetUndo(Undo::INSERT,
2662 cursor.par->ParFromPos(cursor.pos)->previous,
2663 cursor.par->ParFromPos(cursor.pos)->next);
2665 LyXParagraph *endpar;
2666 LyXParagraph *actpar = cursor.par;
2667 int endpos = cursor.pos;
2669 cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2671 RedoParagraphs(cursor, endpar);
2673 SetCursor(cursor.par, cursor.pos);
2676 sel_cursor = cursor;
2677 SetCursor(actpar, endpos);
2679 UpdateCounters(cursor.row);
2683 // returns a pointer to the very first LyXParagraph
2684 LyXParagraph * LyXText::FirstParagraph() const
2686 return buffer->paragraph;
2690 // returns true if the specified string is at the specified position
2691 bool LyXText::IsStringInText(LyXParagraph * par,
2692 LyXParagraph::size_type pos,
2693 char const * str) const
2697 while (pos + i < par->Last() && str[i] &&
2698 str[i] == par->GetChar(pos + i)) {
2708 // sets the selection over the number of characters of string, no check!!
2709 void LyXText::SetSelectionOverString(char const * string)
2711 sel_cursor = cursor;
2712 for (int i = 0; string[i]; ++i)
2718 // simple replacing. The font of the first selected character is used
2719 void LyXText::ReplaceSelectionWithString(char const * str)
2724 if (!selection) { // create a dummy selection
2725 sel_end_cursor = cursor;
2726 sel_start_cursor = cursor;
2729 // Get font setting before we cut
2730 LyXParagraph::size_type pos = sel_end_cursor.pos;
2731 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2733 // Insert the new string
2734 for (int i = 0; str[i]; ++i) {
2735 sel_end_cursor.par->InsertChar(pos, str[i]);
2736 sel_end_cursor.par->SetFont(pos, font);
2740 // Cut the selection
2747 // if the string can be found: return true and set the cursor to
2749 bool LyXText::SearchForward(char const * str) const
2751 LyXParagraph * par = cursor.par;
2752 LyXParagraph::size_type pos = cursor.pos;
2753 while (par && !IsStringInText(par, pos, str)) {
2754 if (pos < par->Last() - 1)
2762 SetCursor(par, pos);
2770 bool LyXText::SearchBackward(char const * string) const
2772 LyXParagraph * par = cursor.par;
2773 int pos = cursor.pos;
2779 // We skip empty paragraphs (Asger)
2781 par = par->Previous();
2783 pos = par->Last() - 1;
2784 } while (par && pos < 0);
2786 } while (par && !IsStringInText(par, pos, string));
2789 SetCursor(par, pos);
2796 // needed to insert the selection
2797 void LyXText::InsertStringA(string const & str)
2799 LyXParagraph * par = cursor.par;
2800 LyXParagraph::size_type pos = cursor.pos;
2801 LyXParagraph::size_type a = 0;
2803 LyXParagraph * endpar = cursor.par->Next();
2808 textclasslist.Style(buffer->params.textclass,
2809 cursor.par->GetLayout()).isEnvironment();
2810 // only to be sure, should not be neccessary
2813 // insert the string, don't insert doublespace
2814 string::size_type i = 0;
2815 while (i < str.length()) {
2816 if (str[i] != '\n') {
2818 && i + 1 < str.length() && str[i + 1] != ' '
2819 && pos && par->GetChar(pos - 1)!= ' ') {
2820 par->InsertChar(pos,' ');
2821 par->SetFont(pos, current_font);
2823 } else if (par->table) {
2824 if (str[i] == '\t') {
2825 while((pos < par->size()) &&
2826 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2828 if (pos < par->size())
2830 else // no more fields to fill skip the rest
2832 } else if ((str[i] != 13) &&
2833 ((str[i] & 127) >= ' ')) {
2834 par->InsertChar(pos, str[i]);
2835 par->SetFont(pos, current_font);
2838 } else if (str[i] == ' ') {
2839 InsetSpecialChar * new_inset =
2840 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2841 if (par->InsertInsetAllowed(new_inset)) {
2842 par->InsertChar(pos, LyXParagraph::META_INSET);
2843 par->SetFont(pos, current_font);
2844 par->InsertInset(pos, new_inset);
2849 } else if (str[i] == '\t') {
2850 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2851 InsetSpecialChar * new_inset =
2852 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2853 if (par->InsertInsetAllowed(new_inset)) {
2854 par->InsertChar(pos, LyXParagraph::META_INSET);
2855 par->SetFont(pos, current_font);
2856 par->InsertInset(pos, new_inset);
2862 } else if (str[i] != 13 &&
2863 // Ignore unprintables
2864 (str[i] & 127) >= ' ') {
2865 par->InsertChar(pos, str[i]);
2866 par->SetFont(pos, current_font);
2871 if (i + 1 >= str.length()) {
2875 while((pos < par->size()) &&
2876 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2879 cell = NumberOfCell(par, pos);
2880 while((pos < par->size()) &&
2881 !(par->table->IsFirstCell(cell))) {
2883 while((pos < par->size()) &&
2884 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2887 cell = NumberOfCell(par, pos);
2889 if (pos >= par->size())
2890 // no more fields to fill skip the rest
2893 if (!par->size()) { // par is empty
2894 InsetSpecialChar * new_inset =
2895 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2896 if (par->InsertInsetAllowed(new_inset)) {
2897 par->InsertChar(pos, LyXParagraph::META_INSET);
2898 par->SetFont(pos, current_font);
2899 par->InsertInset(pos, new_inset);
2905 par->BreakParagraph(pos, flag);
2913 RedoParagraphs(cursor, endpar);
2914 SetCursor(cursor.par, cursor.pos);
2915 sel_cursor = cursor;
2916 SetCursor(par, pos);
2921 /* turns double-CR to single CR, others where converted into one blank and 13s
2922 * that are ignored .Double spaces are also converted into one. Spaces at
2923 * the beginning of a paragraph are forbidden. tabs are converted into one
2924 * space. then InsertStringA is called */
2925 void LyXText::InsertStringB(string const & s)
2928 LyXParagraph * par = cursor.par;
2929 string::size_type i = 1;
2930 while (i < str.length()) {
2931 if (str[i] == '\t' && !par->table)
2933 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2935 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2936 if (str[i + 1] != '\n') {
2937 if (str[i - 1] != ' ')
2942 while (i + 1 < str.length()
2943 && (str[i + 1] == ' '
2944 || str[i + 1] == '\t'
2945 || str[i + 1] == '\n'
2946 || str[i + 1] == 13)) {
2957 bool LyXText::GotoNextError() const
2959 LyXCursor res = cursor;
2961 if (res.pos < res.par->Last() - 1) {
2965 res.par = res.par->Next();
2970 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2971 && res.par->GetInset(res.pos)->AutoDelete()));
2974 SetCursor(res.par, res.pos);
2981 bool LyXText::GotoNextNote() const
2983 LyXCursor res = cursor;
2985 if (res.pos < res.par->Last() - 1) {
2988 res.par = res.par->Next();
2993 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2994 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2997 SetCursor(res.par, res.pos);
3004 void LyXText::CheckParagraph(LyXParagraph * par,
3005 LyXParagraph::size_type pos)
3007 LyXCursor tmpcursor;
3010 /* table stuff -- begin*/
3013 CheckParagraphInTable(par, pos);
3016 /* table stuff -- end*/
3019 LyXParagraph::size_type z;
3020 Row * row = GetRow(par, pos, y);
3022 // is there a break one row above
3023 if (row->previous && row->previous->par == row->par) {
3024 z = NextBreakPoint(row->previous, paperwidth);
3025 if ( z >= row->pos) {
3026 // set the dimensions of the row above
3027 y -= row->previous->height;
3029 refresh_row = row->previous;
3030 status = LyXText::NEED_MORE_REFRESH;
3032 BreakAgain(row->previous);
3034 // set the cursor again. Otherwise
3035 // dangling pointers are possible
3036 SetCursor(cursor.par, cursor.pos);
3037 sel_cursor = cursor;
3042 int tmpheight = row->height;
3043 LyXParagraph::size_type tmplast = RowLast(row);
3048 if (row->height == tmpheight && RowLast(row) == tmplast)
3049 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3051 status = LyXText::NEED_MORE_REFRESH;
3053 // check the special right address boxes
3054 if (textclasslist.Style(buffer->params.textclass,
3055 par->GetLayout()).margintype
3056 == MARGIN_RIGHT_ADDRESS_BOX) {
3057 tmpcursor.par = par;
3058 tmpcursor.row = row;
3061 tmpcursor.x_fix = 0;
3062 tmpcursor.pos = pos;
3063 RedoDrawingOfParagraph(tmpcursor);
3068 // set the cursor again. Otherwise dangling pointers are possible
3069 // also set the selection
3073 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3074 sel_cursor = cursor;
3075 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3076 sel_start_cursor = cursor;
3077 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3078 sel_end_cursor = cursor;
3079 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3080 last_sel_cursor = cursor;
3083 SetCursorIntern(cursor.par, cursor.pos);
3087 // returns 0 if inset wasn't found
3088 int LyXText::UpdateInset(Inset * inset)
3090 // first check the current paragraph
3091 int pos = cursor.par->GetPositionOfInset(inset);
3093 CheckParagraph(cursor.par, pos);
3097 // check every paragraph
3099 LyXParagraph * par = FirstParagraph();
3101 // make sure the paragraph is open
3102 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3103 pos = par->GetPositionOfInset(inset);
3105 CheckParagraph(par, pos);
3116 void LyXText::SetCursor(LyXParagraph * par,
3117 LyXParagraph::size_type pos, bool setfont) const
3119 LyXCursor old_cursor = cursor;
3120 SetCursorIntern(par, pos, setfont);
3121 DeleteEmptyParagraphMechanism(old_cursor);
3125 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3126 LyXParagraph::size_type pos) const
3128 // correct the cursor position if impossible
3129 if (pos > par->Last()){
3130 LyXParagraph * tmppar = par->ParFromPos(pos);
3131 pos = par->PositionInParFromPos(pos);
3134 if (par->IsDummy() && par->previous &&
3135 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3136 while (par->previous &&
3137 ((par->previous->IsDummy() &&
3138 (par->previous->previous->footnoteflag ==
3139 LyXParagraph::CLOSED_FOOTNOTE)) ||
3140 (par->previous->footnoteflag ==
3141 LyXParagraph::CLOSED_FOOTNOTE))) {
3142 par = par->previous ;
3143 if (par->IsDummy() &&
3144 (par->previous->footnoteflag ==
3145 LyXParagraph::CLOSED_FOOTNOTE))
3146 pos += par->size() + 1;
3148 if (par->previous) {
3149 par = par->previous;
3151 pos += par->size() + 1;
3157 /* get the cursor y position in text */
3159 Row * row = GetRow(par, pos, y);
3160 /* y is now the beginning of the cursor row */
3162 /* y is now the cursor baseline */
3165 /* now get the cursors x position */
3167 float fill_separator, fill_hfill, fill_label_hfill;
3168 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3169 LyXParagraph::size_type cursor_vpos;
3170 LyXParagraph::size_type last = RowLastPrintable(row);
3172 if (pos > last + 1) // This shouldn't happen.
3175 if (last < row->pos)
3177 else if ((pos > last) ||
3178 ((pos - 1 >= row->pos) &&
3179 (row->par->IsSeparator(pos) ||
3180 (row->par->table && row->par->IsNewline(pos)))))
3181 /// Place cursor after char at (logical) position pos-1
3182 cursor_vpos = !(bidi_level(pos-1) % 2)
3183 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3185 /// Place cursor before char at (logical) position pos
3186 cursor_vpos = !(bidi_level(pos) % 2)
3187 ? log2vis(pos) : log2vis(pos) + 1;
3189 /* table stuff -- begin*/
3190 if (row->par->table) {
3191 int cell = NumberOfCell(row->par, row->pos);
3193 x += row->par->table->GetBeginningOfTextInCell(cell);
3194 for (LyXParagraph::size_type vpos = row->pos;
3195 vpos < cursor_vpos; ++vpos) {
3196 pos = vis2log(vpos);
3197 if (row->par->IsNewline(pos)) {
3198 x = x_old + row->par->table->WidthOfColumn(cell);
3201 x += row->par->table->GetBeginningOfTextInCell(cell);
3203 x += SingleWidth(row->par, pos);
3207 /* table stuff -- end*/
3208 LyXParagraph::size_type main_body =
3209 BeginningOfMainBody(row->par);
3210 if ((main_body > 0) &&
3211 ((main_body-1 > last) ||
3212 !row->par->IsLineSeparator(main_body-1)))
3215 for (LyXParagraph::size_type vpos = row->pos;
3216 vpos < cursor_vpos; ++vpos) {
3217 pos = vis2log(vpos);
3218 if (main_body > 0 && pos == main_body-1) {
3219 x += fill_label_hfill +
3220 lyxfont::width(textclasslist.Style(
3221 buffer->params.textclass,
3222 row->par->GetLayout())
3224 GetFont(row->par, -2));
3225 if (row->par->IsLineSeparator(main_body-1))
3226 x -= SingleWidth(row->par,main_body-1);
3228 if (HfillExpansion(row, pos)) {
3229 x += SingleWidth(row->par, pos);
3230 if (pos >= main_body)
3233 x += fill_label_hfill;
3234 } else if (row->par->IsSeparator(pos)) {
3235 x += SingleWidth(row->par, pos);
3236 if (pos >= main_body)
3237 x += fill_separator;
3239 x += SingleWidth(row->par, pos);
3249 void LyXText::SetCursorIntern(LyXParagraph * par,
3250 LyXParagraph::size_type pos, bool setfont) const
3252 SetCursor(cursor, par, pos);
3253 // #warning Remove this when verified working (Jug 20000413)
3255 // correct the cursor position if impossible
3256 if (pos > par->Last()){
3257 LyXParagraph * tmppar = par->ParFromPos(pos);
3258 pos = par->PositionInParFromPos(pos);
3261 if (par->IsDummy() && par->previous &&
3262 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3263 while (par->previous &&
3264 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3265 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3266 par = par->previous ;
3267 if (par->IsDummy() &&
3268 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3269 pos += par->size() + 1;
3271 if (par->previous) {
3272 par = par->previous;
3274 pos += par->size() + 1;
3280 /* get the cursor y position in text */
3282 Row * row = GetRow(par, pos, y);
3283 /* y is now the beginning of the cursor row */
3285 /* y is now the cursor baseline */
3288 /* now get the cursors x position */
3290 float fill_separator, fill_hfill, fill_label_hfill;
3291 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3292 LyXParagraph::size_type cursor_vpos;
3293 LyXParagraph::size_type last = RowLastPrintable(row);
3295 if (pos > last + 1) // This shouldn't happen.
3298 if (last < row->pos)
3300 else if (pos > last ||
3301 (pos - 1 >= row->pos &&
3302 (row->par->IsSeparator(pos) ||
3303 (row->par->table && row->par->IsNewline(pos))
3305 /// Place cursor after char at (logical) position pos-1
3306 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3307 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3309 /// Place cursor before char at (logical) position pos
3310 cursor_vpos = (bidi_level(pos) % 2 == 0)
3311 ? log2vis(pos) : log2vis(pos) + 1;
3313 /* table stuff -- begin*/
3314 if (row->par->table) {
3315 int cell = NumberOfCell(row->par, row->pos);
3317 x += row->par->table->GetBeginningOfTextInCell(cell);
3318 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3319 pos = vis2log(vpos);
3320 if (row->par->IsNewline(pos)) {
3321 x = x_old + row->par->table->WidthOfColumn(cell);
3324 x += row->par->table->GetBeginningOfTextInCell(cell);
3326 x += SingleWidth(row->par, pos);
3330 /* table stuff -- end*/
3331 LyXParagraph::size_type main_body =
3332 BeginningOfMainBody(row->par);
3333 if (main_body > 0 &&
3334 (main_body-1 > last ||
3335 !row->par->IsLineSeparator(main_body-1)))
3338 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3339 pos = vis2log(vpos);
3340 if (main_body > 0 && pos == main_body-1) {
3341 x += fill_label_hfill +
3342 lyxfont::width(textclasslist
3343 .Style(buffer->params.textclass,
3344 row->par->GetLayout())
3346 GetFont(row->par, -2));
3347 if (row->par->IsLineSeparator(main_body-1))
3348 x -= SingleWidth(row->par, main_body-1);
3350 if (HfillExpansion(row, pos)) {
3351 x += SingleWidth(row->par, pos);
3352 if (pos >= main_body)
3355 x += fill_label_hfill;
3357 else if (row->par->IsSeparator(pos)) {
3358 x += SingleWidth(row->par, pos);
3359 if (pos >= main_body)
3360 x += fill_separator;
3362 x += SingleWidth(row->par, pos);
3368 cursor.x_fix = cursor.x;
3373 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3374 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3376 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3377 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3379 current_font = cursor.par->GetFontSettings(cursor.pos);
3380 real_current_font = GetFont(cursor.par, cursor.pos);
3386 void LyXText::SetCursorFromCoordinates(int x, long y) const
3388 LyXCursor old_cursor = cursor;
3390 /* get the row first */
3392 Row * row = GetRowNearY(y);
3394 cursor.par = row->par;
3396 int column = GetColumnNearX(row, x);
3397 cursor.pos = row->pos + column;
3399 cursor.y = y + row->baseline;
3404 (cursor.pos == cursor.par->Last()
3405 || cursor.par->IsSeparator(cursor.pos)
3406 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3407 && !cursor.par->IsSeparator(cursor.pos))
3408 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3410 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3411 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3413 current_font = cursor.par->GetFontSettings(cursor.pos);
3414 real_current_font = GetFont(cursor.par, cursor.pos);
3416 DeleteEmptyParagraphMechanism(old_cursor);
3419 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3421 /* get the row first */
3423 Row * row = GetRowNearY(y);
3424 int column = GetColumnNearX(row, x);
3427 cur.pos = row->pos + column;
3429 cur.y = y + row->baseline;
3434 void LyXText::CursorLeft() const
3437 if (cursor.par->table) {
3438 int cell = NumberOfCell(cursor.par, cursor.pos);
3439 if (cursor.par->table->IsContRow(cell) &&
3440 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3447 void LyXText::CursorLeftIntern() const
3449 if (cursor.pos > 0) {
3450 SetCursor(cursor.par, cursor.pos - 1);
3452 else if (cursor.par->Previous()) { // steps into the above paragraph.
3453 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3458 void LyXText::CursorRight() const
3460 CursorRightIntern();
3461 if (cursor.par->table) {
3462 int cell = NumberOfCell(cursor.par, cursor.pos);
3463 if (cursor.par->table->IsContRow(cell) &&
3464 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3471 void LyXText::CursorRightIntern() const
3473 if (cursor.pos < cursor.par->Last()) {
3474 SetCursor(cursor.par, cursor.pos + 1);
3476 else if (cursor.par->Next()) {
3477 SetCursor(cursor.par->Next(), 0);
3482 void LyXText::CursorUp() const
3484 SetCursorFromCoordinates(cursor.x_fix,
3485 cursor.y - cursor.row->baseline - 1);
3486 if (cursor.par->table) {
3487 int cell = NumberOfCell(cursor.par, cursor.pos);
3488 if (cursor.par->table->IsContRow(cell) &&
3489 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3496 void LyXText::CursorDown() const
3498 if (cursor.par->table &&
3499 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3502 SetCursorFromCoordinates(cursor.x_fix,
3503 cursor.y - cursor.row->baseline
3504 + cursor.row->height + 1);
3505 if (cursor.par->table) {
3506 int cell = NumberOfCell(cursor.par, cursor.pos);
3507 int cell_above = cursor.par->table->GetCellAbove(cell);
3508 while(cursor.par->table &&
3509 cursor.par->table->IsContRow(cell) &&
3510 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3511 SetCursorFromCoordinates(cursor.x_fix,
3512 cursor.y - cursor.row->baseline
3513 + cursor.row->height + 1);
3514 if (cursor.par->table) {
3515 cell = NumberOfCell(cursor.par, cursor.pos);
3516 cell_above = cursor.par->table->GetCellAbove(cell);
3523 void LyXText::CursorUpParagraph() const
3525 if (cursor.pos > 0) {
3526 SetCursor(cursor.par, 0);
3528 else if (cursor.par->Previous()) {
3529 SetCursor(cursor.par->Previous(), 0);
3534 void LyXText::CursorDownParagraph() const
3536 if (cursor.par->Next()) {
3537 SetCursor(cursor.par->Next(), 0);
3539 SetCursor(cursor.par, cursor.par->Last());
3545 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3547 // Would be wrong to delete anything if we have a selection.
3548 if (selection) return;
3550 // We allow all kinds of "mumbo-jumbo" when freespacing.
3551 if (textclasslist.Style(buffer->params.textclass,
3552 old_cursor.par->GetLayout()).free_spacing)
3555 bool deleted = false;
3557 /* Ok I'll put some comments here about what is missing.
3558 I have fixed BackSpace (and thus Delete) to not delete
3559 double-spaces automagically. I have also changed Cut,
3560 Copy and Paste to hopefully do some sensible things.
3561 There are still some small problems that can lead to
3562 double spaces stored in the document file or space at
3563 the beginning of paragraphs. This happens if you have
3564 the cursor betwenn to spaces and then save. Or if you
3565 cut and paste and the selection have a space at the
3566 beginning and then save right after the paste. I am
3567 sure none of these are very hard to fix, but I will
3568 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3569 that I can get some feedback. (Lgb)
3572 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3573 // delete the LineSeparator.
3576 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3577 // delete the LineSeparator.
3580 // If the pos around the old_cursor were spaces, delete one of them.
3581 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3583 if (old_cursor.pos > 0
3584 && old_cursor.pos < old_cursor.par->Last()
3585 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3586 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3587 old_cursor.par->Erase(old_cursor.pos - 1);
3588 RedoParagraphs(old_cursor, old_cursor.par->Next());
3590 if (old_cursor.par == cursor.par &&
3591 cursor.pos > old_cursor.pos) {
3592 SetCursorIntern(cursor.par, cursor.pos - 1);
3594 SetCursorIntern(cursor.par, cursor.pos);
3599 // Do not delete empty paragraphs with keepempty set.
3600 if ((textclasslist.Style(buffer->params.textclass,
3601 old_cursor.par->GetLayout())).keepempty)
3604 LyXCursor tmpcursor;
3606 if (old_cursor.par != cursor.par) {
3607 if ( (old_cursor.par->Last() == 0
3608 || (old_cursor.par->Last() == 1
3609 && old_cursor.par->IsLineSeparator(0)))
3610 && old_cursor.par->FirstPhysicalPar()
3611 == old_cursor.par->LastPhysicalPar()) {
3612 // ok, we will delete anything
3614 // make sure that you do not delete any environments
3615 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3616 !(old_cursor.row->previous
3617 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3618 && !(old_cursor.row->next
3619 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3620 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3621 && ((old_cursor.row->previous
3622 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3623 || (old_cursor.row->next
3624 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3626 status = LyXText::NEED_MORE_REFRESH;
3629 if (old_cursor.row->previous) {
3630 refresh_row = old_cursor.row->previous;
3631 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3633 cursor = old_cursor; // that undo can restore the right cursor position
3634 LyXParagraph * endpar = old_cursor.par->next;
3635 if (endpar && endpar->GetDepth()) {
3636 while (endpar && endpar->GetDepth()) {
3637 endpar = endpar->LastPhysicalPar()->Next();
3640 SetUndo(Undo::DELETE,
3641 old_cursor.par->previous,
3646 RemoveRow(old_cursor.row);
3647 if (buffer->paragraph == old_cursor.par) {
3648 buffer->paragraph = buffer->paragraph->next;
3651 delete old_cursor.par;
3653 /* Breakagain the next par. Needed
3654 * because of the parindent that
3655 * can occur or dissappear. The
3656 * next row can change its height,
3657 * if there is another layout before */
3658 if (refresh_row->next) {
3659 BreakAgain(refresh_row->next);
3660 UpdateCounters(refresh_row);
3662 SetHeightOfRow(refresh_row);
3664 refresh_row = old_cursor.row->next;
3665 refresh_y = old_cursor.y - old_cursor.row->baseline;
3668 cursor = old_cursor; // that undo can restore the right cursor position
3669 LyXParagraph *endpar = old_cursor.par->next;
3670 if (endpar && endpar->GetDepth()) {
3671 while (endpar && endpar->GetDepth()) {
3672 endpar = endpar->LastPhysicalPar()->Next();
3675 SetUndo(Undo::DELETE,
3676 old_cursor.par->previous,
3681 RemoveRow(old_cursor.row);
3683 if (buffer->paragraph == old_cursor.par) {
3684 buffer->paragraph = buffer->paragraph->next;
3686 delete old_cursor.par;
3688 /* Breakagain the next par. Needed
3689 because of the parindent that can
3690 occur or dissappear.
3691 The next row can change its height,
3692 if there is another layout before
3695 BreakAgain(refresh_row);
3696 UpdateCounters(refresh_row->previous);
3702 SetCursorIntern(cursor.par, cursor.pos);
3704 if (sel_cursor.par == old_cursor.par
3705 && sel_cursor.pos == sel_cursor.pos) {
3706 // correct selection
3707 sel_cursor = cursor;
3712 if (old_cursor.par->ClearParagraph()) {
3713 RedoParagraphs(old_cursor, old_cursor.par->Next());
3715 SetCursorIntern(cursor.par, cursor.pos);
3716 sel_cursor = cursor;
3723 LyXParagraph * LyXText::GetParFromID(int id)
3725 LyXParagraph * result = FirstParagraph();
3726 while (result && result->id() != id)
3727 result = result->next;
3733 bool LyXText::TextUndo()
3735 // returns false if no undo possible
3736 Undo * undo = buffer->undostack.pop();
3741 .push(CreateUndo(undo->kind,
3742 GetParFromID(undo->number_of_before_par),
3743 GetParFromID(undo->number_of_behind_par)));
3745 return TextHandleUndo(undo);
3749 bool LyXText::TextRedo()
3751 // returns false if no redo possible
3752 Undo * undo = buffer->redostack.pop();
3757 .push(CreateUndo(undo->kind,
3758 GetParFromID(undo->number_of_before_par),
3759 GetParFromID(undo->number_of_behind_par)));
3761 return TextHandleUndo(undo);
3765 bool LyXText::TextHandleUndo(Undo * undo)
3767 // returns false if no undo possible
3768 bool result = false;
3770 LyXParagraph * before =
3771 GetParFromID(undo->number_of_before_par);
3772 LyXParagraph * behind =
3773 GetParFromID(undo->number_of_behind_par);
3774 LyXParagraph * tmppar;
3775 LyXParagraph * tmppar2;
3776 LyXParagraph * endpar;
3777 LyXParagraph * tmppar5;
3779 // if there's no before take the beginning
3780 // of the document for redoing
3782 SetCursorIntern(FirstParagraph(), 0);
3784 // replace the paragraphs with the undo informations
3786 LyXParagraph * tmppar3 = undo->par;
3787 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3788 LyXParagraph * tmppar4 = tmppar3;
3790 while (tmppar4->next)
3791 tmppar4 = tmppar4->next;
3792 } // get last undo par
3794 // now remove the old text if there is any
3795 if (before != behind || (!behind && !before)){
3797 tmppar5 = before->next;
3799 tmppar5 = buffer->paragraph;
3801 while (tmppar5 && tmppar5 != behind){
3803 tmppar5 = tmppar5->next;
3804 // a memory optimization for edit: Only layout information
3805 // is stored in the undo. So restore the text informations.
3806 if (undo->kind == Undo::EDIT) {
3807 tmppar2->setContentsFromPar(tmppar);
3808 tmppar->clearContents();
3809 tmppar2 = tmppar2->next;
3814 // put the new stuff in the list if there is one
3817 before->next = tmppar3;
3819 buffer->paragraph = tmppar3;
3820 tmppar3->previous = before;
3824 buffer->paragraph = behind;
3827 tmppar4->next = behind;
3829 behind->previous = tmppar4;
3833 // Set the cursor for redoing
3835 SetCursorIntern(before->FirstSelfrowPar(), 0);
3836 // check wether before points to a closed float and open it if necessary
3837 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3838 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3840 while (tmppar4->previous &&
3841 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3842 tmppar4 = tmppar4->previous;
3843 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3844 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3845 tmppar4 = tmppar4->next;
3850 // open a cosed footnote at the end if necessary
3851 if (behind && behind->previous &&
3852 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3853 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3854 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3855 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3856 behind = behind->next;
3860 // calculate the endpar for redoing the paragraphs.
3862 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3863 endpar = behind->LastPhysicalPar()->Next();
3865 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3870 tmppar = GetParFromID(undo->number_of_cursor_par);
3871 RedoParagraphs(cursor, endpar);
3873 SetCursorIntern(tmppar, undo->cursor_pos);
3874 UpdateCounters(cursor.row);
3884 void LyXText::FinishUndo()
3886 // makes sure the next operation will be stored
3887 undo_finished = True;
3891 void LyXText::FreezeUndo()
3893 // this is dangerous and for internal use only
3898 void LyXText::UnFreezeUndo()
3900 // this is dangerous and for internal use only
3901 undo_frozen = false;
3905 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3906 LyXParagraph const * behind) const
3909 buffer->undostack.push(CreateUndo(kind, before, behind));
3910 buffer->redostack.clear();
3914 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3915 LyXParagraph const * behind)
3917 buffer->redostack.push(CreateUndo(kind, before, behind));
3921 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3922 LyXParagraph const * behind) const
3924 int before_number = -1;
3925 int behind_number = -1;
3927 before_number = before->id();
3929 behind_number = behind->id();
3930 // Undo::EDIT and Undo::FINISH are
3931 // always finished. (no overlapping there)
3932 // overlapping only with insert and delete inside one paragraph:
3933 // Nobody wants all removed character
3934 // appear one by one when undoing.
3935 // EDIT is special since only layout information, not the
3936 // contents of a paragaph are stored.
3937 if (!undo_finished && kind != Undo::EDIT &&
3938 kind != Undo::FINISH){
3939 // check wether storing is needed
3940 if (!buffer->undostack.empty() &&
3941 buffer->undostack.top()->kind == kind &&
3942 buffer->undostack.top()->number_of_before_par == before_number &&
3943 buffer->undostack.top()->number_of_behind_par == behind_number ){
3948 // create a new Undo
3949 LyXParagraph * undopar;
3950 LyXParagraph * tmppar;
3951 LyXParagraph * tmppar2;
3953 LyXParagraph * start = 0;
3954 LyXParagraph * end = 0;
3957 start = before->next;
3959 start = FirstParagraph();
3961 end = behind->previous;
3963 end = FirstParagraph();
3969 && start != end->next
3970 && (before != behind || (!before && !behind))) {
3972 tmppar2 = tmppar->Clone();
3973 tmppar2->id(tmppar->id());
3975 // a memory optimization: Just store the layout information
3977 if (kind == Undo::EDIT){
3978 //tmppar2->text.clear();
3979 tmppar2->clearContents();
3984 while (tmppar != end && tmppar->next) {
3985 tmppar = tmppar->next;
3986 tmppar2->next = tmppar->Clone();
3987 tmppar2->next->id(tmppar->id());
3988 // a memory optimization: Just store the layout
3989 // information when only edit
3990 if (kind == Undo::EDIT){
3991 //tmppar2->next->text.clear();
3992 tmppar2->clearContents();
3994 tmppar2->next->previous = tmppar2;
3995 tmppar2 = tmppar2->next;
3999 undopar = 0; // nothing to replace (undo of delete maybe)
4001 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
4002 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
4004 Undo * undo = new Undo(kind,
4005 before_number, behind_number,
4006 cursor_par, cursor_pos,
4009 undo_finished = false;
4014 void LyXText::SetCursorParUndo()
4016 SetUndo(Undo::FINISH,
4017 cursor.par->ParFromPos(cursor.pos)->previous,
4018 cursor.par->ParFromPos(cursor.pos)->next);
4022 void LyXText::RemoveTableRow(LyXCursor * cur) const
4028 // move to the previous row
4029 int cell_act = NumberOfCell(cur->par, cur->pos);
4032 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4035 !cur->par->table->IsFirstCell(cell_act)) {
4037 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4042 // now we have to pay attention if the actual table is the
4043 // main row of TableContRows and if yes to delete all of them
4048 // delete up to the next row
4049 while (cur->pos < cur->par->Last() &&
4051 || !cur->par->table->IsFirstCell(cell_act))) {
4052 while (cur->pos < cur->par->Last() &&
4053 !cur->par->IsNewline(cur->pos))
4054 cur->par->Erase(cur->pos);
4057 if (cur->pos < cur->par->Last())
4058 cur->par->Erase(cur->pos);
4060 if (cur->pos && cur->pos == cur->par->Last()) {
4062 cur->par->Erase(cur->pos); // no newline at very end!
4064 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4065 !cur->par->table->IsContRow(cell_org) &&
4066 cur->par->table->IsContRow(cell));
4067 cur->par->table->DeleteRow(cell_org);
4072 bool LyXText::IsEmptyTableCell() const
4074 LyXParagraph::size_type pos = cursor.pos - 1;
4075 while (pos >= 0 && pos < cursor.par->Last()
4076 && !cursor.par->IsNewline(pos))
4078 return cursor.par->IsNewline(pos + 1);
4082 void LyXText::toggleAppendix(){
4083 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4084 bool start = !par->start_of_appendix;
4086 // ensure that we have only one start_of_appendix in this document
4087 LyXParagraph * tmp = FirstParagraph();
4088 for (; tmp; tmp = tmp->next)
4089 tmp->start_of_appendix = 0;
4090 par->start_of_appendix = start;
4092 // we can set the refreshing parameters now
4093 status = LyXText::NEED_MORE_REFRESH;
4095 refresh_row = 0; // not needed for full update
4097 SetCursor(cursor.par, cursor.pos);