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);
478 // set layout over selection and make a total rebreak of those paragraphs
479 void LyXText::SetLayout(LyXTextClass::size_type layout)
483 // if there is no selection just set the layout
484 // of the current paragraph */
486 sel_start_cursor = cursor; // dummy selection
487 sel_end_cursor = cursor;
490 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
491 LyXParagraph * undoendpar = endpar;
493 if (endpar && endpar->GetDepth()) {
494 while (endpar && endpar->GetDepth()) {
495 endpar = endpar->LastPhysicalPar()->Next();
500 endpar = endpar->Next(); // because of parindents etc.
504 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
507 tmpcursor = cursor; /* store the current cursor */
509 /* ok we have a selection. This is always between sel_start_cursor
510 * and sel_end cursor */
511 cursor = sel_start_cursor;
513 LyXLayout const & lyxlayout =
514 textclasslist.Style(buffer->params.textclass, layout);
516 while (cursor.par != sel_end_cursor.par) {
517 if (cursor.par->footnoteflag ==
518 sel_start_cursor.par->footnoteflag) {
519 cursor.par->SetLayout(layout);
520 MakeFontEntriesLayoutSpecific(cursor.par);
521 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
522 fppar->added_space_top = lyxlayout.fill_top ?
523 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
524 fppar->added_space_bottom = lyxlayout.fill_bottom ?
525 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
526 if (lyxlayout.margintype == MARGIN_MANUAL)
527 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
528 if (lyxlayout.labeltype != LABEL_BIBLIO
530 delete fppar->bibkey;
534 cursor.par = cursor.par->Next();
536 if (cursor.par->footnoteflag ==
537 sel_start_cursor.par->footnoteflag) {
538 cursor.par->SetLayout(layout);
539 MakeFontEntriesLayoutSpecific(cursor.par);
540 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
541 fppar->added_space_top = lyxlayout.fill_top ?
542 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
543 fppar->added_space_bottom = lyxlayout.fill_bottom ?
544 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
545 if (lyxlayout.margintype == MARGIN_MANUAL)
546 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
547 if (lyxlayout.labeltype != LABEL_BIBLIO
549 delete fppar->bibkey;
554 RedoParagraphs(sel_start_cursor, endpar);
556 // we have to reset the selection, because the
557 // geometry could have changed */
558 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
560 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
561 UpdateCounters(cursor.row);
564 SetCursor(tmpcursor.par, tmpcursor.pos, true);
568 // increment depth over selection and
569 // make a total rebreak of those paragraphs
570 void LyXText::IncDepth()
572 // If there is no selection, just use the current paragraph
574 sel_start_cursor = cursor; // dummy selection
575 sel_end_cursor = cursor;
578 // We end at the next paragraph with depth 0
579 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
580 LyXParagraph * undoendpar = endpar;
582 if (endpar && endpar->GetDepth()) {
583 while (endpar && endpar->GetDepth()) {
584 endpar = endpar->LastPhysicalPar()->Next();
589 endpar = endpar->Next(); // because of parindents etc.
594 .par->ParFromPos(sel_start_cursor.pos)->previous,
597 LyXCursor tmpcursor = cursor; // store the current cursor
599 // ok we have a selection. This is always between sel_start_cursor
600 // and sel_end cursor
601 cursor = sel_start_cursor;
603 bool anything_changed = false;
606 // NOTE: you can't change the depth of a bibliography entry
607 if (cursor.par->footnoteflag ==
608 sel_start_cursor.par->footnoteflag
609 && textclasslist.Style(buffer->params.textclass,
610 cursor.par->GetLayout()
611 ).labeltype != LABEL_BIBLIO) {
612 LyXParagraph * prev =
613 cursor.par->FirstPhysicalPar()->Previous();
615 && (prev->GetDepth() - cursor.par->GetDepth() > 0
616 || (prev->GetDepth() == cursor.par->GetDepth()
617 && textclasslist.Style(buffer->params.textclass,
618 prev->GetLayout()).isEnvironment()))) {
619 cursor.par->FirstPhysicalPar()->depth++;
620 anything_changed = true;
623 if (cursor.par == sel_end_cursor.par)
625 cursor.par = cursor.par->Next();
628 // if nothing changed set all depth to 0
629 if (!anything_changed) {
630 cursor = sel_start_cursor;
631 while (cursor.par != sel_end_cursor.par) {
632 cursor.par->FirstPhysicalPar()->depth = 0;
633 cursor.par = cursor.par->Next();
635 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
636 cursor.par->FirstPhysicalPar()->depth = 0;
639 RedoParagraphs(sel_start_cursor, endpar);
641 // we have to reset the selection, because the
642 // geometry could have changed
643 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
645 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
646 UpdateCounters(cursor.row);
649 SetCursor(tmpcursor.par, tmpcursor.pos);
653 // decrement depth over selection and
654 // make a total rebreak of those paragraphs
655 void LyXText::DecDepth()
657 // if there is no selection just set the layout
658 // of the current paragraph
660 sel_start_cursor = cursor; // dummy selection
661 sel_end_cursor = cursor;
664 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
665 LyXParagraph * undoendpar = endpar;
667 if (endpar && endpar->GetDepth()) {
668 while (endpar && endpar->GetDepth()) {
669 endpar = endpar->LastPhysicalPar()->Next();
674 endpar = endpar->Next(); // because of parindents etc.
679 .par->ParFromPos(sel_start_cursor.pos)->previous,
682 LyXCursor tmpcursor = cursor; // store the current cursor
684 // ok we have a selection. This is always between sel_start_cursor
685 // and sel_end cursor
686 cursor = sel_start_cursor;
689 if (cursor.par->footnoteflag ==
690 sel_start_cursor.par->footnoteflag) {
691 if (cursor.par->FirstPhysicalPar()->depth)
692 cursor.par->FirstPhysicalPar()->depth--;
694 if (cursor.par == sel_end_cursor.par)
696 cursor.par = cursor.par->Next();
699 RedoParagraphs(sel_start_cursor, endpar);
701 // we have to reset the selection, because the
702 // geometry could have changed
703 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
705 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
706 UpdateCounters(cursor.row);
709 SetCursor(tmpcursor.par, tmpcursor.pos);
713 // set font over selection and make a total rebreak of those paragraphs
714 void LyXText::SetFont(LyXFont const & font, bool toggleall)
716 // if there is no selection just set the current_font
718 // Determine basis font
720 if (cursor.pos < BeginningOfMainBody(cursor.par))
721 layoutfont = GetFont(cursor.par, -2);
723 layoutfont = GetFont(cursor.par, -1);
724 // Update current font
725 real_current_font.update(font,
726 buffer->params.language_info,
729 // Reduce to implicit settings
730 current_font = real_current_font;
731 current_font.reduce(layoutfont);
732 // And resolve it completely
733 real_current_font.realize(layoutfont);
737 LyXCursor tmpcursor = cursor; // store the current cursor
739 // ok we have a selection. This is always between sel_start_cursor
740 // and sel_end cursor
743 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
744 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
745 cursor = sel_start_cursor;
746 while (cursor.par != sel_end_cursor.par ||
747 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
748 && cursor.pos < sel_end_cursor.pos))
750 if (cursor.pos < cursor.par->Last()
751 && cursor.par->footnoteflag
752 == sel_start_cursor.par->footnoteflag) {
753 // an open footnote should behave
755 LyXFont newfont = GetFont(cursor.par, cursor.pos);
757 buffer->params.language_info,
759 SetCharFont(cursor.par, cursor.pos, newfont);
763 cursor.par = cursor.par->Next();
767 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
769 // we have to reset the selection, because the
770 // geometry could have changed
771 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
773 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
776 SetCursor(tmpcursor.par, tmpcursor.pos);
780 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
782 Row * tmprow = cur.row;
783 long y = cur.y - tmprow->baseline;
785 SetHeightOfRow(tmprow);
786 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
787 // find the first row of the paragraph
788 if (first_phys_par != tmprow->par)
789 while (tmprow->previous
790 && tmprow->previous->par != first_phys_par) {
791 tmprow = tmprow->previous;
793 SetHeightOfRow(tmprow);
795 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
796 tmprow = tmprow->previous;
798 SetHeightOfRow(tmprow);
801 // we can set the refreshing parameters now
802 status = LyXText::NEED_MORE_REFRESH;
804 refresh_row = tmprow;
805 SetCursor(cur.par, cur.pos);
809 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
811 Row * tmprow = cur.row;
813 long y = cur.y - tmprow->baseline;
814 SetHeightOfRow(tmprow);
815 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
816 // find the first row of the paragraph
817 if (first_phys_par != tmprow->par)
818 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
819 tmprow = tmprow->previous;
822 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
823 tmprow = tmprow->previous;
827 // we can set the refreshing parameters now
828 if (status == LyXText::UNCHANGED || y < refresh_y) {
830 refresh_row = tmprow;
832 status = LyXText::NEED_MORE_REFRESH;
833 SetCursor(cur.par, cur.pos);
837 /* deletes and inserts again all paragaphs between the cursor
838 * and the specified par
839 * This function is needed after SetLayout and SetFont etc. */
840 void LyXText::RedoParagraphs(LyXCursor const & cur,
841 LyXParagraph const * endpar) const
844 LyXParagraph * tmppar, * first_phys_par;
846 Row * tmprow = cur.row;
848 long y = cur.y - tmprow->baseline;
850 if (!tmprow->previous){
851 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
853 first_phys_par = tmprow->par->FirstPhysicalPar();
854 // find the first row of the paragraph
855 if (first_phys_par != tmprow->par)
856 while (tmprow->previous &&
857 (tmprow->previous->par != first_phys_par)) {
858 tmprow = tmprow->previous;
861 while (tmprow->previous
862 && tmprow->previous->par == first_phys_par) {
863 tmprow = tmprow->previous;
868 // we can set the refreshing parameters now
869 status = LyXText::NEED_MORE_REFRESH;
871 refresh_row = tmprow->previous; /* the real refresh row will
872 be deleted, so I store
876 tmppar = tmprow->next->par;
879 while (tmppar != endpar) {
880 RemoveRow(tmprow->next);
882 tmppar = tmprow->next->par;
887 // remove the first one
888 tmprow2 = tmprow; /* this is because tmprow->previous
890 tmprow = tmprow->previous;
893 tmppar = first_phys_par;
897 InsertParagraph(tmppar, tmprow);
900 while (tmprow->next && tmprow->next->par == tmppar)
901 tmprow = tmprow->next;
902 tmppar = tmppar->Next();
904 } while (tmppar != endpar);
906 // this is because of layout changes
908 refresh_y -= refresh_row->height;
909 SetHeightOfRow(refresh_row);
911 refresh_row = firstrow;
913 SetHeightOfRow(refresh_row);
916 if (tmprow && tmprow->next)
917 SetHeightOfRow(tmprow->next);
921 bool LyXText::FullRebreak()
923 if (need_break_row) {
924 BreakAgain(need_break_row);
932 /* important for the screen */
935 /* the cursor set functions have a special mechanism. When they
936 * realize, that you left an empty paragraph, they will delete it.
937 * They also delet the corresponding row */
939 // need the selection cursor:
940 void LyXText::SetSelection()
943 last_sel_cursor = sel_cursor;
944 sel_start_cursor = sel_cursor;
945 sel_end_cursor = sel_cursor;
950 // first the toggling area
951 if (cursor.y < last_sel_cursor.y ||
952 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
953 toggle_end_cursor = last_sel_cursor;
954 toggle_cursor = cursor;
957 toggle_end_cursor = cursor;
958 toggle_cursor = last_sel_cursor;
961 last_sel_cursor = cursor;
963 // and now the whole selection
965 if (sel_cursor.par == cursor.par)
966 if (sel_cursor.pos < cursor.pos) {
967 sel_end_cursor = cursor;
968 sel_start_cursor = sel_cursor;
970 sel_end_cursor = sel_cursor;
971 sel_start_cursor = cursor;
973 else if (sel_cursor.y < cursor.y ||
974 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
975 sel_end_cursor = cursor;
976 sel_start_cursor = sel_cursor;
979 sel_end_cursor = sel_cursor;
980 sel_start_cursor = cursor;
983 // a selection with no contents is not a selection
984 if (sel_start_cursor.x == sel_end_cursor.x &&
985 sel_start_cursor.y == sel_end_cursor.y)
990 void LyXText::ClearSelection() const
997 void LyXText::CursorHome() const
999 SetCursor(cursor.par, cursor.row->pos);
1003 void LyXText::CursorEnd() const
1005 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1006 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1008 if (cursor.par->Last() &&
1009 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1010 || cursor.par->IsNewline(RowLast(cursor.row))))
1011 SetCursor(cursor.par, RowLast(cursor.row));
1013 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1015 if (cursor.par->table) {
1016 int cell = NumberOfCell(cursor.par, cursor.pos);
1017 if (cursor.par->table->RowHasContRow(cell) &&
1018 cursor.par->table->CellHasContRow(cell)<0) {
1019 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1020 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1022 if (cursor.par->Last() &&
1023 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1024 || cursor.par->IsNewline(RowLast(cursor.row))))
1025 SetCursor(cursor.par, RowLast(cursor.row));
1027 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1034 void LyXText::CursorTop() const
1036 while (cursor.par->Previous())
1037 cursor.par = cursor.par->Previous();
1038 SetCursor(cursor.par, 0);
1042 void LyXText::CursorBottom() const
1044 while (cursor.par->Next())
1045 cursor.par = cursor.par->Next();
1046 SetCursor(cursor.par, cursor.par->Last());
1050 /* returns a pointer to the row near the specified y-coordinate
1051 * (relative to the whole text). y is set to the real beginning
1053 Row * LyXText::GetRowNearY(long & y) const
1055 Row * tmprow = firstrow;
1058 while (tmprow->next && tmpy + tmprow->height <= y) {
1059 tmpy += tmprow->height;
1060 tmprow = tmprow->next;
1063 y = tmpy; // return the real y
1068 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1070 // If the mask is completely neutral, tell user
1071 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1072 // Could only happen with user style
1073 owner_->owner()->getMiniBuffer()
1074 ->Set(_("No font change defined. Use Character under"
1075 " the Layout menu to define font change."));
1079 // Try implicit word selection
1080 // If there is a change in the language the implicit word selection
1082 LyXCursor resetCursor = cursor;
1083 bool implicitSelection = (font.language() == ignore_language)
1084 ? SelectWordWhenUnderCursor() : false;
1087 SetFont(font, toggleall);
1089 /* Implicit selections are cleared afterwards and cursor is set to the
1090 original position. */
1091 if (implicitSelection) {
1093 cursor = resetCursor;
1094 SetCursor( cursor.par, cursor.pos );
1095 sel_cursor = cursor;
1100 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1102 if (textclasslist.Style(buffer->params.textclass,
1103 par->GetLayout()).labeltype != LABEL_MANUAL)
1106 return par->BeginningOfMainBody();
1110 /* if there is a selection, reset every environment you can find
1111 * in the selection, otherwise just the environment you are in */
1112 void LyXText::MeltFootnoteEnvironment()
1114 LyXParagraph * tmppar, * firsttmppar;
1118 /* is is only allowed, if the cursor is IN an open footnote.
1119 * Otherwise it is too dangerous */
1120 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1123 SetUndo(Undo::FINISH,
1124 cursor.par->PreviousBeforeFootnote()->previous,
1125 cursor.par->NextAfterFootnote()->next);
1127 /* ok, move to the beginning of the footnote. */
1128 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1129 cursor.par = cursor.par->Previous();
1131 SetCursor(cursor.par, cursor.par->Last());
1132 /* this is just faster than using CursorLeft(); */
1134 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1135 tmppar = firsttmppar;
1136 /* tmppar is now the paragraph right before the footnote */
1138 bool first_footnote_par_is_not_empty = tmppar->next->size();
1141 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1142 tmppar = tmppar->next; /* I use next instead of Next(),
1143 * because there cannot be any
1144 * footnotes in a footnote
1146 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1148 /* remember the captions and empty paragraphs */
1149 if ((textclasslist.Style(buffer->params.textclass,
1150 tmppar->GetLayout())
1151 .labeltype == LABEL_SENSITIVE)
1153 tmppar->SetLayout(0);
1156 // now we will paste the ex-footnote, if the layouts allow it
1157 // first restore the layout of the paragraph right behind
1160 tmppar->next->MakeSameLayout(cursor.par);
1163 if ((!tmppar->GetLayout() && !tmppar->table)
1165 && (!tmppar->Next()->Last()
1166 || tmppar->Next()->HasSameLayout(tmppar)))) {
1167 if (tmppar->Next()->Last()
1168 && tmppar->Next()->IsLineSeparator(0))
1169 tmppar->Next()->Erase(0);
1170 tmppar->PasteParagraph();
1173 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1174 * by the pasting of the beginning */
1176 /* then the beginning */
1177 /* if there is no space between the text and the footnote, so we insert
1179 * (only if the previous par and the footnotepar are not empty!) */
1180 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1181 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1182 if (firsttmppar->size()
1183 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1184 && first_footnote_par_is_not_empty) {
1185 firsttmppar->next->InsertChar(0, ' ');
1187 firsttmppar->PasteParagraph();
1190 /* now redo the paragaphs */
1191 RedoParagraphs(cursor, tmppar);
1193 SetCursor(cursor.par, cursor.pos);
1195 /* sometimes it can happen, that there is a counter change */
1196 Row * row = cursor.row;
1197 while (row->next && row->par != tmppar && row->next->par != tmppar)
1199 UpdateCounters(row);
1206 /* the DTP switches for paragraphs. LyX will store them in the
1207 * first physicla paragraph. When a paragraph is broken, the top settings
1208 * rest, the bottom settings are given to the new one. So I can make shure,
1209 * they do not duplicate themself and you cannnot make dirty things with
1212 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1213 bool pagebreak_top, bool pagebreak_bottom,
1214 VSpace const & space_top,
1215 VSpace const & space_bottom,
1217 string labelwidthstring,
1220 LyXCursor tmpcursor = cursor;
1222 sel_start_cursor = cursor;
1223 sel_end_cursor = cursor;
1226 // make sure that the depth behind the selection are restored, too
1227 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1228 LyXParagraph * undoendpar = endpar;
1230 if (endpar && endpar->GetDepth()) {
1231 while (endpar && endpar->GetDepth()) {
1232 endpar = endpar->LastPhysicalPar()->Next();
1233 undoendpar = endpar;
1237 endpar = endpar->Next(); // because of parindents etc.
1242 .par->ParFromPos(sel_start_cursor.pos)->previous,
1246 LyXParagraph * tmppar = sel_end_cursor.par;
1247 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1248 SetCursor(tmppar->FirstPhysicalPar(), 0);
1249 status = LyXText::NEED_MORE_REFRESH;
1250 refresh_row = cursor.row;
1251 refresh_y = cursor.y - cursor.row->baseline;
1252 if (cursor.par->footnoteflag ==
1253 sel_start_cursor.par->footnoteflag) {
1254 cursor.par->line_top = line_top;
1255 cursor.par->line_bottom = line_bottom;
1256 cursor.par->pagebreak_top = pagebreak_top;
1257 cursor.par->pagebreak_bottom = pagebreak_bottom;
1258 cursor.par->added_space_top = space_top;
1259 cursor.par->added_space_bottom = space_bottom;
1260 // does the layout allow the new alignment?
1261 if (align == LYX_ALIGN_LAYOUT)
1262 align = textclasslist
1263 .Style(buffer->params.textclass,
1264 cursor.par->GetLayout()).align;
1265 if (align & textclasslist
1266 .Style(buffer->params.textclass,
1267 cursor.par->GetLayout()).alignpossible) {
1268 if (align == textclasslist
1269 .Style(buffer->params.textclass,
1270 cursor.par->GetLayout()).align)
1271 cursor.par->align = LYX_ALIGN_LAYOUT;
1273 cursor.par->align = align;
1275 cursor.par->SetLabelWidthString(labelwidthstring);
1276 cursor.par->noindent = noindent;
1279 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1282 RedoParagraphs(sel_start_cursor, endpar);
1285 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1286 sel_cursor = cursor;
1287 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1289 SetCursor(tmpcursor.par, tmpcursor.pos);
1293 void LyXText::SetParagraphExtraOpt(int type,
1295 char const * widthp,
1296 int alignment, bool hfill,
1297 bool start_minipage)
1299 LyXCursor tmpcursor = cursor;
1300 LyXParagraph * tmppar;
1302 sel_start_cursor = cursor;
1303 sel_end_cursor = cursor;
1306 // make sure that the depth behind the selection are restored, too
1307 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1308 LyXParagraph * undoendpar = endpar;
1310 if (endpar && endpar->GetDepth()) {
1311 while (endpar && endpar->GetDepth()) {
1312 endpar = endpar->LastPhysicalPar()->Next();
1313 undoendpar = endpar;
1317 endpar = endpar->Next(); // because of parindents etc.
1322 .par->ParFromPos(sel_start_cursor.pos)->previous,
1325 tmppar = sel_end_cursor.par;
1326 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1327 SetCursor(tmppar->FirstPhysicalPar(), 0);
1328 status = LyXText::NEED_MORE_REFRESH;
1329 refresh_row = cursor.row;
1330 refresh_y = cursor.y - cursor.row->baseline;
1331 if (cursor.par->footnoteflag ==
1332 sel_start_cursor.par->footnoteflag) {
1333 if (type == LyXParagraph::PEXTRA_NONE) {
1334 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1335 cursor.par->UnsetPExtraType();
1336 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1339 cursor.par->SetPExtraType(type, width, widthp);
1340 cursor.par->pextra_hfill = hfill;
1341 cursor.par->pextra_start_minipage = start_minipage;
1342 cursor.par->pextra_alignment = alignment;
1345 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1347 RedoParagraphs(sel_start_cursor, endpar);
1349 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1350 sel_cursor = cursor;
1351 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1353 SetCursor(tmpcursor.par, tmpcursor.pos);
1357 char loweralphaCounter(int n)
1359 if (n < 1 || n > 26)
1365 char alphaCounter(int n)
1367 if (n < 1 || n > 26)
1373 char hebrewCounter(int n)
1375 static const char hebrew[22] = {
1376 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1377 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1378 '÷', 'ø', 'ù', 'ú'
1380 if (n < 1 || n > 22)
1386 static char const * romanCounter(int n)
1388 static char const * roman[20] = {
1389 "i", "ii", "iii", "iv", "v",
1390 "vi", "vii", "viii", "ix", "x",
1391 "xi", "xii", "xiii", "xiv", "xv",
1392 "xvi", "xvii", "xviii", "xix", "xx"
1394 if (n < 1 || n > 20)
1400 // set the counter of a paragraph. This includes the labels
1401 void LyXText::SetCounter(LyXParagraph * par) const
1403 // this is only relevant for the beginning of paragraph
1404 par = par->FirstPhysicalPar();
1406 LyXLayout const & layout =
1407 textclasslist.Style(buffer->params.textclass,
1410 LyXTextClass const & textclass =
1411 textclasslist.TextClass(buffer->params.textclass);
1413 /* copy the prev-counters to this one, unless this is the start of a
1414 footnote or of a bibliography or the very first paragraph */
1416 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1417 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1418 && par->footnotekind == LyXParagraph::FOOTNOTE)
1419 && !(textclasslist.Style(buffer->params.textclass,
1420 par->Previous()->GetLayout()
1421 ).labeltype != LABEL_BIBLIO
1422 && layout.labeltype == LABEL_BIBLIO)) {
1423 for (int i = 0; i < 10; ++i) {
1424 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1426 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1427 if (!par->appendix && par->start_of_appendix){
1428 par->appendix = true;
1429 for (int i = 0; i < 10; ++i) {
1430 par->setCounter(i, 0);
1433 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1434 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1437 for (int i = 0; i < 10; ++i) {
1438 par->setCounter(i, 0);
1440 par->appendix = par->start_of_appendix;
1445 // if this is an open marginnote and this is the first
1446 // entry in the marginnote and the enclosing
1447 // environment is an enum/item then correct for the
1448 // LaTeX behaviour (ARRae)
1449 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1450 && par->footnotekind == LyXParagraph::MARGIN
1452 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1453 && (par->PreviousBeforeFootnote()
1454 && textclasslist.Style(buffer->params.textclass,
1455 par->PreviousBeforeFootnote()->GetLayout()
1456 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1457 // Any itemize or enumerate environment in a marginnote
1458 // that is embedded in an itemize or enumerate
1459 // paragraph is seen by LaTeX as being at a deeper
1460 // level within that enclosing itemization/enumeration
1461 // even if there is a "standard" layout at the start of
1467 /* Maybe we have to increment the enumeration depth.
1468 * BUT, enumeration in a footnote is considered in isolation from its
1469 * surrounding paragraph so don't increment if this is the
1470 * first line of the footnote
1471 * AND, bibliographies can't have their depth changed ie. they
1472 * are always of depth 0
1475 && par->Previous()->GetDepth() < par->GetDepth()
1476 && textclasslist.Style(buffer->params.textclass,
1477 par->Previous()->GetLayout()
1478 ).labeltype == LABEL_COUNTER_ENUMI
1479 && par->enumdepth < 3
1480 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1481 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1482 && par->footnotekind == LyXParagraph::FOOTNOTE)
1483 && layout.labeltype != LABEL_BIBLIO) {
1487 /* Maybe we have to decrement the enumeration depth, see note above */
1489 && par->Previous()->GetDepth() > par->GetDepth()
1490 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1491 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1492 && par->footnotekind == LyXParagraph::FOOTNOTE)
1493 && layout.labeltype != LABEL_BIBLIO) {
1494 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1495 par->setCounter(6 + par->enumdepth,
1496 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1497 /* reset the counters.
1498 * A depth change is like a breaking layout
1500 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1501 par->setCounter(i, 0);
1504 if (!par->labelstring.empty()) {
1505 par->labelstring.clear();
1508 if (layout.margintype == MARGIN_MANUAL) {
1509 if (par->labelwidthstring.empty()) {
1510 par->SetLabelWidthString(layout.labelstring());
1513 par->SetLabelWidthString(string());
1516 /* is it a layout that has an automatic label ? */
1517 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1519 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1520 if (i >= 0 && i<= buffer->params.secnumdepth) {
1521 par->incCounter(i); // increment the counter
1523 // Is there a label? Useful for Chapter layout
1524 if (!par->appendix){
1525 if (!layout.labelstring().empty())
1526 par->labelstring = layout.labelstring();
1528 par->labelstring.clear();
1530 if (!layout.labelstring_appendix().empty())
1531 par->labelstring = layout.labelstring_appendix();
1533 par->labelstring.clear();
1537 std::ostringstream s;
1541 if (!par->appendix) {
1542 switch (2 * LABEL_FIRST_COUNTER -
1543 textclass.maxcounter() + i) {
1544 case LABEL_COUNTER_CHAPTER:
1545 s << par->getCounter(i);
1547 case LABEL_COUNTER_SECTION:
1548 s << par->getCounter(i - 1) << '.'
1549 << par->getCounter(i);
1551 case LABEL_COUNTER_SUBSECTION:
1552 s << par->getCounter(i - 2) << '.'
1553 << par->getCounter(i - 1) << '.'
1554 << par->getCounter(i);
1556 case LABEL_COUNTER_SUBSUBSECTION:
1557 s << par->getCounter(i - 3) << '.'
1558 << par->getCounter(i - 2) << '.'
1559 << par->getCounter(i - 1) << '.'
1560 << par->getCounter(i);
1563 case LABEL_COUNTER_PARAGRAPH:
1564 s << par->getCounter(i - 4) << '.'
1565 << par->getCounter(i - 3) << '.'
1566 << par->getCounter(i - 2) << '.'
1567 << par->getCounter(i - 1) << '.'
1568 << par->getCounter(i);
1570 case LABEL_COUNTER_SUBPARAGRAPH:
1571 s << par->getCounter(i - 5) << '.'
1572 << par->getCounter(i - 4) << '.'
1573 << par->getCounter(i - 3) << '.'
1574 << par->getCounter(i - 2) << '.'
1575 << par->getCounter(i - 1) << '.'
1576 << par->getCounter(i);
1580 s << par->getCounter(i) << '.';
1583 } else { // appendix
1584 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1585 case LABEL_COUNTER_CHAPTER:
1586 if (par->isRightToLeftPar())
1587 s << hebrewCounter(par->getCounter(i));
1589 s << alphaCounter(par->getCounter(i));
1591 case LABEL_COUNTER_SECTION:
1592 if (par->isRightToLeftPar())
1593 s << hebrewCounter(par->getCounter(i - 1));
1595 s << alphaCounter(par->getCounter(i - 1));
1598 << par->getCounter(i);
1601 case LABEL_COUNTER_SUBSECTION:
1602 if (par->isRightToLeftPar())
1603 s << hebrewCounter(par->getCounter(i - 2));
1605 s << alphaCounter(par->getCounter(i - 2));
1608 << par->getCounter(i-1) << '.'
1609 << par->getCounter(i);
1612 case LABEL_COUNTER_SUBSUBSECTION:
1613 if (par->isRightToLeftPar())
1614 s << hebrewCounter(par->getCounter(i-3));
1616 s << alphaCounter(par->getCounter(i-3));
1619 << par->getCounter(i-2) << '.'
1620 << par->getCounter(i-1) << '.'
1621 << par->getCounter(i);
1624 case LABEL_COUNTER_PARAGRAPH:
1625 if (par->isRightToLeftPar())
1626 s << hebrewCounter(par->getCounter(i-4));
1628 s << alphaCounter(par->getCounter(i-4));
1631 << par->getCounter(i-3) << '.'
1632 << par->getCounter(i-2) << '.'
1633 << par->getCounter(i-1) << '.'
1634 << par->getCounter(i);
1637 case LABEL_COUNTER_SUBPARAGRAPH:
1638 if (par->isRightToLeftPar())
1639 s << hebrewCounter(par->getCounter(i-5));
1641 s << alphaCounter(par->getCounter(i-5));
1644 << par->getCounter(i-4) << '.'
1645 << par->getCounter(i-3) << '.'
1646 << par->getCounter(i-2) << '.'
1647 << par->getCounter(i-1) << '.'
1648 << par->getCounter(i);
1652 // Can this ever be reached? And in the
1653 // case it is, how can this be correct?
1655 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1661 par->labelstring += s.str().c_str();
1662 // We really want to remove the c_str as soon as
1666 char * tmps = s.str();
1667 par->labelstring += tmps;
1671 for (i++; i < 10; ++i) {
1672 // reset the following counters
1673 par->setCounter(i, 0);
1675 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1676 for (i++; i < 10; ++i) {
1677 // reset the following counters
1678 par->setCounter(i, 0);
1680 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1681 par->incCounter(i + par->enumdepth);
1682 int number = par->getCounter(i + par->enumdepth);
1685 std::ostringstream s;
1689 switch (par->enumdepth) {
1691 if (par->isRightToLeftPar())
1693 << hebrewCounter(number)
1697 << loweralphaCounter(number)
1701 if (par->isRightToLeftPar())
1702 s << '.' << romanCounter(number);
1704 s << romanCounter(number) << '.';
1707 if (par->isRightToLeftPar())
1709 << alphaCounter(number);
1711 s << alphaCounter(number)
1715 if (par->isRightToLeftPar())
1722 par->labelstring = s.str().c_str();
1723 // we really want to get rid of that c_str()
1726 char * tmps = s.str();
1727 par->labelstring = tmps;
1731 for (i += par->enumdepth + 1; i < 10; ++i)
1732 par->setCounter(i, 0); /* reset the following counters */
1735 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1736 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1738 int number = par->getCounter(i);
1740 par->bibkey = new InsetBibKey();
1741 par->bibkey->setCounter(number);
1742 par->labelstring = layout.labelstring();
1744 // In biblio should't be following counters but...
1746 string s = layout.labelstring();
1748 // the caption hack:
1750 if (layout.labeltype == LABEL_SENSITIVE) {
1751 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1752 && (par->footnotekind == LyXParagraph::FIG
1753 || par->footnotekind == LyXParagraph::WIDE_FIG))
1754 s = (par->getParLanguage()->lang == "hebrew")
1755 ? ":øåéà " : "Figure:";
1756 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1757 && (par->footnotekind == LyXParagraph::TAB
1758 || par->footnotekind == LyXParagraph::WIDE_TAB))
1759 s = (par->getParLanguage()->lang == "hebrew")
1760 ? ":äìáè" : "Table:";
1761 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1762 && par->footnotekind == LyXParagraph::ALGORITHM)
1763 s = (par->getParLanguage()->lang == "hebrew")
1764 ? ":Ãúéøåâìà " : "Algorithm:";
1766 /* par->SetLayout(0);
1767 s = layout->labelstring; */
1768 s = (par->getParLanguage()->lang == "hebrew")
1769 ? " :úåòîùî øñç" : "Senseless: ";
1772 par->labelstring = s;
1774 /* reset the enumeration counter. They are always resetted
1775 * when there is any other layout between */
1776 for (int i = 6 + par->enumdepth; i < 10; ++i)
1777 par->setCounter(i, 0);
1782 /* Updates all counters BEHIND the row. Changed paragraphs
1783 * with a dynamic left margin will be rebroken. */
1784 void LyXText::UpdateCounters(Row * row) const
1793 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1794 par = row->par->LastPhysicalPar()->Next();
1796 par = row->par->next;
1801 while (row->par != par)
1806 /* now check for the headline layouts. remember that they
1807 * have a dynamic left margin */
1809 && ( textclasslist.Style(buffer->params.textclass,
1810 par->layout).margintype == MARGIN_DYNAMIC
1811 || textclasslist.Style(buffer->params.textclass,
1812 par->layout).labeltype == LABEL_SENSITIVE)
1815 /* Rebreak the paragraph */
1816 RemoveParagraph(row);
1817 AppendParagraph(row);
1819 /* think about the damned open footnotes! */
1820 while (par->Next() &&
1821 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1822 || par->Next()->IsDummy())){
1824 if (par->IsDummy()) {
1825 while (row->par != par)
1827 RemoveParagraph(row);
1828 AppendParagraph(row);
1833 par = par->LastPhysicalPar()->Next();
1839 /* insets an inset. */
1840 void LyXText::InsertInset(Inset *inset)
1842 if (!cursor.par->InsertInsetAllowed(inset))
1844 SetUndo(Undo::INSERT,
1845 cursor.par->ParFromPos(cursor.pos)->previous,
1846 cursor.par->ParFromPos(cursor.pos)->next);
1847 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1848 cursor.par->InsertInset(cursor.pos, inset);
1849 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1850 * The character will not be inserted a
1855 #ifdef USE_OLD_CUT_AND_PASTE
1856 // this is for the simple cut and paste mechanism
1857 static LyXParagraph * simple_cut_buffer = 0;
1858 static char simple_cut_buffer_textclass = 0;
1860 void DeleteSimpleCutBuffer()
1862 if (!simple_cut_buffer)
1864 LyXParagraph * tmppar;
1866 while (simple_cut_buffer) {
1867 tmppar = simple_cut_buffer;
1868 simple_cut_buffer = simple_cut_buffer->next;
1871 simple_cut_buffer = 0;
1875 void LyXText::copyEnvironmentType()
1877 copylayouttype = cursor.par->GetLayout();
1881 void LyXText::pasteEnvironmentType()
1883 SetLayout(copylayouttype);
1886 #ifdef USE_OLD_CUT_AND_PASTE
1887 void LyXText::CutSelection(bool doclear)
1889 // This doesn't make sense, if there is no selection
1893 // OK, we have a selection. This is always between sel_start_cursor
1894 // and sel_end cursor
1895 LyXParagraph * tmppar;
1897 // Check whether there are half footnotes in the selection
1898 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1899 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1900 tmppar = sel_start_cursor.par;
1901 while (tmppar != sel_end_cursor.par){
1902 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1903 WriteAlert(_("Impossible operation"),
1904 _("Don't know what to do with half floats."),
1908 tmppar = tmppar->Next();
1912 /* table stuff -- begin */
1913 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1914 if ( sel_start_cursor.par != sel_end_cursor.par) {
1915 WriteAlert(_("Impossible operation"),
1916 _("Don't know what to do with half tables."),
1920 sel_start_cursor.par->table->Reinit();
1922 /* table stuff -- end */
1924 // make sure that the depth behind the selection are restored, too
1925 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1926 LyXParagraph * undoendpar = endpar;
1928 if (endpar && endpar->GetDepth()) {
1929 while (endpar && endpar->GetDepth()) {
1930 endpar = endpar->LastPhysicalPar()->Next();
1931 undoendpar = endpar;
1933 } else if (endpar) {
1934 endpar = endpar->Next(); // because of parindents etc.
1937 SetUndo(Undo::DELETE,
1939 .par->ParFromPos(sel_start_cursor.pos)->previous,
1942 // clear the simple_cut_buffer
1943 DeleteSimpleCutBuffer();
1945 // set the textclass
1946 simple_cut_buffer_textclass = buffer->params.textclass;
1948 #ifdef WITH_WARNINGS
1949 #warning Asger: Make cut more intelligent here.
1952 White paper for "intelligent" cutting:
1954 Example: "This is our text."
1955 Using " our " as selection, cutting will give "This istext.".
1956 Using "our" as selection, cutting will give "This is text.".
1957 Using " our" as selection, cutting will give "This is text.".
1958 Using "our " as selection, cutting will give "This is text.".
1960 All those four selections will (however) paste identically:
1961 Pasting with the cursor right after the "is" will give the
1962 original text with all four selections.
1964 The rationale is to be intelligent such that words are copied,
1965 cut and pasted in a functional manner.
1967 This is not implemented yet. (Asger)
1969 The changes below sees to do a lot of what you want. However
1970 I have not verified that all cases work as they should:
1972 - cut in multiple row
1974 - cut across footnotes and paragraph
1975 My simplistic tests show that the idea are basically sound but
1976 there are some items to fix up...we only need to find them
1979 As do redo Asger's example above (with | beeing the cursor in the
1980 result after cutting.):
1982 Example: "This is our text."
1983 Using " our " as selection, cutting will give "This is|text.".
1984 Using "our" as selection, cutting will give "This is | text.".
1985 Using " our" as selection, cutting will give "This is| text.".
1986 Using "our " as selection, cutting will give "This is |text.".
1991 // there are two cases: cut only within one paragraph or
1992 // more than one paragraph
1994 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
1995 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1996 // only within one paragraph
1997 simple_cut_buffer = new LyXParagraph;
1998 LyXParagraph::size_type i =
1999 sel_start_cursor.pos;
2000 for (; i < sel_end_cursor.pos; ++i) {
2001 /* table stuff -- begin */
2002 if (sel_start_cursor.par->table
2003 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2004 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2005 sel_start_cursor.pos++;
2007 /* table stuff -- end */
2008 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2009 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2011 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2013 endpar = sel_end_cursor.par->Next();
2015 // cut more than one paragraph
2018 ->BreakParagraphConservative(sel_end_cursor.pos);
2019 sel_end_cursor.par = sel_end_cursor.par->Next();
2020 sel_end_cursor.pos = 0;
2022 cursor = sel_end_cursor;
2024 sel_start_cursor.par
2025 ->BreakParagraphConservative(sel_start_cursor.pos);
2026 // store the endparagraph for redoing later
2027 endpar = sel_end_cursor.par->Next(); /* needed because
2032 // store the selection
2033 simple_cut_buffer = sel_start_cursor.par
2034 ->ParFromPos(sel_start_cursor.pos)->next;
2035 simple_cut_buffer->previous = 0;
2036 sel_end_cursor.par->previous->next = 0;
2038 // cut the selection
2039 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2040 = sel_end_cursor.par;
2042 sel_end_cursor.par->previous
2043 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2045 // care about footnotes
2046 if (simple_cut_buffer->footnoteflag) {
2047 LyXParagraph * tmppar = simple_cut_buffer;
2049 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2050 tmppar = tmppar->next;
2054 // the cut selection should begin with standard layout
2055 simple_cut_buffer->Clear();
2057 // paste the paragraphs again, if possible
2059 sel_start_cursor.par->Next()->ClearParagraph();
2060 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2062 !sel_start_cursor.par->Next()->Last())
2063 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2066 // sometimes necessary
2068 sel_start_cursor.par->ClearParagraph();
2070 RedoParagraphs(sel_start_cursor, endpar);
2073 cursor = sel_start_cursor;
2074 SetCursor(cursor.par, cursor.pos);
2075 sel_cursor = cursor;
2076 UpdateCounters(cursor.row);
2079 #else ///////////////////////////////////////////////////////////////////
2081 void LyXText::CutSelection(bool doclear)
2083 // This doesn't make sense, if there is no selection
2087 // OK, we have a selection. This is always between sel_start_cursor
2088 // and sel_end cursor
2089 LyXParagraph * tmppar;
2091 // Check whether there are half footnotes in the selection
2092 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2093 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2094 tmppar = sel_start_cursor.par;
2095 while (tmppar != sel_end_cursor.par){
2096 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2097 WriteAlert(_("Impossible operation"),
2098 _("Don't know what to do with half floats."),
2102 tmppar = tmppar->Next();
2106 /* table stuff -- begin */
2107 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2108 if ( sel_start_cursor.par != sel_end_cursor.par) {
2109 WriteAlert(_("Impossible operation"),
2110 _("Don't know what to do with half tables."),
2114 sel_start_cursor.par->table->Reinit();
2116 /* table stuff -- end */
2118 // make sure that the depth behind the selection are restored, too
2119 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2120 LyXParagraph * undoendpar = endpar;
2122 if (endpar && endpar->GetDepth()) {
2123 while (endpar && endpar->GetDepth()) {
2124 endpar = endpar->LastPhysicalPar()->Next();
2125 undoendpar = endpar;
2127 } else if (endpar) {
2128 endpar = endpar->Next(); // because of parindents etc.
2131 SetUndo(Undo::DELETE, sel_start_cursor
2132 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2136 // there are two cases: cut only within one paragraph or
2137 // more than one paragraph
2138 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2139 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2140 // only within one paragraph
2141 endpar = sel_start_cursor.par;
2142 cap.cutSelection(sel_start_cursor.par, &endpar,
2143 sel_start_cursor.pos, sel_end_cursor.pos,
2144 buffer->params.textclass, doclear);
2146 endpar = sel_end_cursor.par;
2148 cap.cutSelection(sel_start_cursor.par, &endpar,
2149 sel_start_cursor.pos, sel_end_cursor.pos,
2150 buffer->params.textclass, doclear);
2151 cursor.par = sel_end_cursor.par = endpar;
2152 cursor.pos = sel_end_cursor.pos;
2154 endpar = sel_end_cursor.par->Next();
2156 // sometimes necessary
2158 sel_start_cursor.par->ClearParagraph();
2160 RedoParagraphs(sel_start_cursor, endpar);
2163 cursor = sel_start_cursor;
2164 SetCursor(cursor.par, cursor.pos);
2165 sel_cursor = cursor;
2166 UpdateCounters(cursor.row);
2170 #ifdef USE_OLD_CUT_AND_PASTE
2171 void LyXText::CopySelection()
2173 // this doesnt make sense, if there is no selection
2177 // ok we have a selection. This is always between sel_start_cursor
2178 // and sel_end cursor
2179 LyXParagraph * tmppar;
2181 /* check wether there are half footnotes in the selection */
2182 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2183 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2184 tmppar = sel_start_cursor.par;
2185 while (tmppar != sel_end_cursor.par) {
2186 if (tmppar->footnoteflag !=
2187 sel_end_cursor.par->footnoteflag) {
2188 WriteAlert(_("Impossible operation"),
2189 _("Don't know what to do"
2190 " with half floats."),
2194 tmppar = tmppar->Next();
2198 /* table stuff -- begin */
2199 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2200 if ( sel_start_cursor.par != sel_end_cursor.par){
2201 WriteAlert(_("Impossible operation"),
2202 _("Don't know what to do with half tables."),
2207 /* table stuff -- end */
2209 // delete the simple_cut_buffer
2210 DeleteSimpleCutBuffer();
2212 // set the textclass
2213 simple_cut_buffer_textclass = buffer->params->textclass;
2215 // copy behind a space if there is one
2216 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2217 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2218 && (sel_start_cursor.par != sel_end_cursor.par
2219 || sel_start_cursor.pos < sel_end_cursor.pos))
2220 sel_start_cursor.pos++;
2222 // there are two cases: copy only within one paragraph
2223 // or more than one paragraph
2224 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2225 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2226 // only within one paragraph
2227 simple_cut_buffer = new LyXParagraph;
2228 LyXParagraph::size_type i = 0;
2229 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2230 sel_start_cursor.par->CopyIntoMinibuffer(i);
2231 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2234 // copy more than one paragraph
2235 // clone the paragraphs within the selection
2237 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2238 simple_cut_buffer = tmppar->Clone();
2239 LyXParagraph *tmppar2 = simple_cut_buffer;
2241 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2243 tmppar = tmppar->next;
2244 tmppar2->next = tmppar->Clone();
2245 tmppar2->next->previous = tmppar2;
2246 tmppar2 = tmppar2->next;
2250 // care about footnotes
2251 if (simple_cut_buffer->footnoteflag) {
2252 tmppar = simple_cut_buffer;
2254 tmppar->footnoteflag =
2255 LyXParagraph::NO_FOOTNOTE;
2256 tmppar = tmppar->next;
2260 // the simple_cut_buffer paragraph is too big
2261 LyXParagraph::size_type tmpi2 =
2262 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2263 for (; tmpi2; --tmpi2)
2264 simple_cut_buffer->Erase(0);
2266 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2268 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2269 while (tmppar2->size() > tmpi2) {
2270 tmppar2->Erase(tmppar2->size() - 1);
2275 #else //////////////////////////////////////////////////////////////////////
2277 void LyXText::CopySelection()
2279 // this doesnt make sense, if there is no selection
2283 // ok we have a selection. This is always between sel_start_cursor
2284 // and sel_end cursor
2285 LyXParagraph * tmppar;
2287 /* check wether there are half footnotes in the selection */
2288 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2289 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2290 tmppar = sel_start_cursor.par;
2291 while (tmppar != sel_end_cursor.par) {
2292 if (tmppar->footnoteflag !=
2293 sel_end_cursor.par->footnoteflag) {
2294 WriteAlert(_("Impossible operation"),
2295 _("Don't know what to do"
2296 " with half floats."),
2300 tmppar = tmppar->Next();
2304 /* table stuff -- begin */
2305 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2306 if ( sel_start_cursor.par != sel_end_cursor.par){
2307 WriteAlert(_("Impossible operation"),
2308 _("Don't know what to do with half tables."),
2313 /* table stuff -- end */
2315 // copy behind a space if there is one
2316 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2317 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2318 && (sel_start_cursor.par != sel_end_cursor.par
2319 || sel_start_cursor.pos < sel_end_cursor.pos))
2320 sel_start_cursor.pos++;
2324 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2325 sel_start_cursor.pos, sel_end_cursor.pos,
2326 buffer->params.textclass);
2330 #ifdef USE_OLD_CUT_AND_PASTE
2331 void LyXText::PasteSelection()
2333 // this does not make sense, if there is nothing to paste
2334 if (!simple_cut_buffer)
2337 LyXParagraph * tmppar;
2338 LyXParagraph * endpar;
2340 LyXCursor tmpcursor;
2342 // be carefull with footnotes in footnotes
2343 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2345 // check whether the cut_buffer includes a footnote
2346 tmppar = simple_cut_buffer;
2348 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2349 tmppar = tmppar->next;
2352 WriteAlert(_("Impossible operation"),
2353 _("Can't paste float into float!"),
2359 /* table stuff -- begin */
2360 if (cursor.par->table) {
2361 if (simple_cut_buffer->next) {
2362 WriteAlert(_("Impossible operation"),
2363 _("Table cell cannot include more than one paragraph!"),
2368 /* table stuff -- end */
2370 SetUndo(Undo::INSERT,
2371 cursor.par->ParFromPos(cursor.pos)->previous,
2372 cursor.par->ParFromPos(cursor.pos)->next);
2376 // There are two cases: cutbuffer only one paragraph or many
2377 if (!simple_cut_buffer->next) {
2378 // only within a paragraph
2380 tmppar = simple_cut_buffer->Clone();
2381 /* table stuff -- begin */
2382 bool table_too_small = false;
2383 if (tmpcursor.par->table) {
2384 while (simple_cut_buffer->size()
2385 && !table_too_small) {
2386 if (simple_cut_buffer->IsNewline(0)){
2387 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2389 simple_cut_buffer->Erase(0);
2390 if (tmpcursor.pos < tmpcursor.par->Last())
2393 table_too_small = true;
2395 // This is an attempt to fix the
2396 // "never insert a space at the
2397 // beginning of a paragraph" problem.
2398 if (tmpcursor.pos == 0
2399 && simple_cut_buffer->IsLineSeparator(0)) {
2400 simple_cut_buffer->Erase(0);
2402 simple_cut_buffer->CutIntoMinibuffer(0);
2403 simple_cut_buffer->Erase(0);
2404 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2410 /* table stuff -- end */
2411 // Some provisions should be done here for checking
2412 // if we are inserting at the beginning of a
2413 // paragraph. If there are a space at the beginning
2414 // of the text to insert and we are inserting at
2415 // the beginning of the paragraph the space should
2417 while (simple_cut_buffer->size()) {
2418 // This is an attempt to fix the
2419 // "never insert a space at the
2420 // beginning of a paragraph" problem.
2421 if (tmpcursor.pos == 0
2422 && simple_cut_buffer->IsLineSeparator(0)) {
2423 simple_cut_buffer->Erase(0);
2425 simple_cut_buffer->CutIntoMinibuffer(0);
2426 simple_cut_buffer->Erase(0);
2427 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2432 delete simple_cut_buffer;
2433 simple_cut_buffer = tmppar;
2434 endpar = tmpcursor.par->Next();
2439 // make a copy of the simple cut_buffer
2440 tmppar = simple_cut_buffer;
2441 LyXParagraph * simple_cut_clone = tmppar->Clone();
2442 LyXParagraph * tmppar2 = simple_cut_clone;
2443 if (cursor.par->footnoteflag){
2444 tmppar->footnoteflag = cursor.par->footnoteflag;
2445 tmppar->footnotekind = cursor.par->footnotekind;
2447 while (tmppar->next) {
2448 tmppar = tmppar->next;
2449 tmppar2->next = tmppar->Clone();
2450 tmppar2->next->previous = tmppar2;
2451 tmppar2 = tmppar2->next;
2452 if (cursor.par->footnoteflag){
2453 tmppar->footnoteflag = cursor.par->footnoteflag;
2454 tmppar->footnotekind = cursor.par->footnotekind;
2458 // make sure there is no class difference
2459 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2460 buffer->params->textclass,
2463 // make the simple_cut_buffer exactly the same layout than
2464 // the cursor paragraph
2465 simple_cut_buffer->MakeSameLayout(cursor.par);
2467 // find the end of the buffer
2468 LyXParagraph * lastbuffer = simple_cut_buffer;
2469 while (lastbuffer->Next())
2470 lastbuffer = lastbuffer->Next();
2472 bool paste_the_end = false;
2474 // open the paragraph for inserting the simple_cut_buffer
2476 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2477 cursor.par->BreakParagraphConservative(cursor.pos);
2478 paste_the_end = true;
2481 // set the end for redoing later
2482 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2485 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2486 cursor.par->ParFromPos(cursor.pos)->next;
2487 cursor.par->ParFromPos(cursor.pos)->next->previous =
2488 lastbuffer->ParFromPos(lastbuffer->Last());
2490 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2491 simple_cut_buffer->previous =
2492 cursor.par->ParFromPos(cursor.pos);
2494 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2495 lastbuffer = cursor.par;
2497 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2499 // store the new cursor position
2500 tmpcursor.par = lastbuffer;
2501 tmpcursor.pos = lastbuffer->Last();
2503 // maybe some pasting
2504 if (lastbuffer->Next() && paste_the_end) {
2505 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2506 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2508 } else if (!lastbuffer->Next()->Last()) {
2509 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2510 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2512 } else if (!lastbuffer->Last()) {
2513 lastbuffer->MakeSameLayout(lastbuffer->next);
2514 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2517 lastbuffer->Next()->ClearParagraph();
2520 // restore the simple cut buffer
2521 simple_cut_buffer = simple_cut_clone;
2524 RedoParagraphs(cursor, endpar);
2526 SetCursor(cursor.par, cursor.pos);
2529 sel_cursor = cursor;
2530 SetCursor(tmpcursor.par, tmpcursor.pos);
2532 UpdateCounters(cursor.row);
2535 #else ////////////////////////////////////////////////////////////////////
2537 void LyXText::PasteSelection()
2541 // this does not make sense, if there is nothing to paste
2542 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2545 SetUndo(Undo::INSERT,
2546 cursor.par->ParFromPos(cursor.pos)->previous,
2547 cursor.par->ParFromPos(cursor.pos)->next);
2549 LyXParagraph *endpar;
2550 LyXParagraph *actpar = cursor.par;
2551 int endpos = cursor.pos;
2553 cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2555 RedoParagraphs(cursor, endpar);
2557 SetCursor(cursor.par, cursor.pos);
2560 sel_cursor = cursor;
2561 SetCursor(actpar, endpos);
2563 UpdateCounters(cursor.row);
2567 // returns a pointer to the very first LyXParagraph
2568 LyXParagraph * LyXText::FirstParagraph() const
2570 return buffer->paragraph;
2574 // returns true if the specified string is at the specified position
2575 bool LyXText::IsStringInText(LyXParagraph * par,
2576 LyXParagraph::size_type pos,
2577 char const * str) const
2581 while (pos + i < par->Last() && str[i] &&
2582 str[i] == par->GetChar(pos + i)) {
2592 // sets the selection over the number of characters of string, no check!!
2593 void LyXText::SetSelectionOverString(char const * string)
2595 sel_cursor = cursor;
2596 for (int i = 0; string[i]; ++i)
2602 // simple replacing. The font of the first selected character is used
2603 void LyXText::ReplaceSelectionWithString(char const * str)
2608 if (!selection) { // create a dummy selection
2609 sel_end_cursor = cursor;
2610 sel_start_cursor = cursor;
2613 // Get font setting before we cut
2614 LyXParagraph::size_type pos = sel_end_cursor.pos;
2615 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2617 // Insert the new string
2618 for (int i = 0; str[i]; ++i) {
2619 sel_end_cursor.par->InsertChar(pos, str[i]);
2620 sel_end_cursor.par->SetFont(pos, font);
2624 // Cut the selection
2631 // if the string can be found: return true and set the cursor to
2633 bool LyXText::SearchForward(char const * str) const
2635 LyXParagraph * par = cursor.par;
2636 LyXParagraph::size_type pos = cursor.pos;
2637 while (par && !IsStringInText(par, pos, str)) {
2638 if (pos < par->Last() - 1)
2646 SetCursor(par, pos);
2654 bool LyXText::SearchBackward(char const * string) const
2656 LyXParagraph * par = cursor.par;
2657 int pos = cursor.pos;
2663 // We skip empty paragraphs (Asger)
2665 par = par->Previous();
2667 pos = par->Last() - 1;
2668 } while (par && pos < 0);
2670 } while (par && !IsStringInText(par, pos, string));
2673 SetCursor(par, pos);
2680 // needed to insert the selection
2681 void LyXText::InsertStringA(string const & str)
2683 LyXParagraph * par = cursor.par;
2684 LyXParagraph::size_type pos = cursor.pos;
2685 LyXParagraph::size_type a = 0;
2687 LyXParagraph * endpar = cursor.par->Next();
2692 textclasslist.Style(buffer->params.textclass,
2693 cursor.par->GetLayout()).isEnvironment();
2694 // only to be sure, should not be neccessary
2697 // insert the string, don't insert doublespace
2698 string::size_type i = 0;
2699 while (i < str.length()) {
2700 if (str[i] != '\n') {
2702 && i + 1 < str.length() && str[i + 1] != ' '
2703 && pos && par->GetChar(pos - 1)!= ' ') {
2704 par->InsertChar(pos,' ');
2705 par->SetFont(pos, current_font);
2707 } else if (par->table) {
2708 if (str[i] == '\t') {
2709 while((pos < par->size()) &&
2710 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2712 if (pos < par->size())
2714 else // no more fields to fill skip the rest
2716 } else if ((str[i] != 13) &&
2717 ((str[i] & 127) >= ' ')) {
2718 par->InsertChar(pos, str[i]);
2719 par->SetFont(pos, current_font);
2722 } else if (str[i] == ' ') {
2723 InsetSpecialChar * new_inset =
2724 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2725 if (par->InsertInsetAllowed(new_inset)) {
2726 par->InsertChar(pos, LyXParagraph::META_INSET);
2727 par->SetFont(pos, current_font);
2728 par->InsertInset(pos, new_inset);
2733 } else if (str[i] == '\t') {
2734 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2735 InsetSpecialChar * new_inset =
2736 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2737 if (par->InsertInsetAllowed(new_inset)) {
2738 par->InsertChar(pos, LyXParagraph::META_INSET);
2739 par->SetFont(pos, current_font);
2740 par->InsertInset(pos, new_inset);
2746 } else if (str[i] != 13 &&
2747 // Ignore unprintables
2748 (str[i] & 127) >= ' ') {
2749 par->InsertChar(pos, str[i]);
2750 par->SetFont(pos, current_font);
2755 if (i + 1 >= str.length()) {
2759 while((pos < par->size()) &&
2760 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2763 cell = NumberOfCell(par, pos);
2764 while((pos < par->size()) &&
2765 !(par->table->IsFirstCell(cell))) {
2767 while((pos < par->size()) &&
2768 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2771 cell = NumberOfCell(par, pos);
2773 if (pos >= par->size())
2774 // no more fields to fill skip the rest
2777 if (!par->size()) { // par is empty
2778 InsetSpecialChar * new_inset =
2779 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2780 if (par->InsertInsetAllowed(new_inset)) {
2781 par->InsertChar(pos, LyXParagraph::META_INSET);
2782 par->SetFont(pos, current_font);
2783 par->InsertInset(pos, new_inset);
2789 par->BreakParagraph(pos, flag);
2797 RedoParagraphs(cursor, endpar);
2798 SetCursor(cursor.par, cursor.pos);
2799 sel_cursor = cursor;
2800 SetCursor(par, pos);
2805 /* turns double-CR to single CR, others where converted into one blank and 13s
2806 * that are ignored .Double spaces are also converted into one. Spaces at
2807 * the beginning of a paragraph are forbidden. tabs are converted into one
2808 * space. then InsertStringA is called */
2809 void LyXText::InsertStringB(string const & s)
2812 LyXParagraph * par = cursor.par;
2813 string::size_type i = 1;
2814 while (i < str.length()) {
2815 if (str[i] == '\t' && !par->table)
2817 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2819 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2820 if (str[i + 1] != '\n') {
2821 if (str[i - 1] != ' ')
2826 while (i + 1 < str.length()
2827 && (str[i + 1] == ' '
2828 || str[i + 1] == '\t'
2829 || str[i + 1] == '\n'
2830 || str[i + 1] == 13)) {
2841 bool LyXText::GotoNextError() const
2843 LyXCursor res = cursor;
2845 if (res.pos < res.par->Last() - 1) {
2849 res.par = res.par->Next();
2854 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2855 && res.par->GetInset(res.pos)->AutoDelete()));
2858 SetCursor(res.par, res.pos);
2865 bool LyXText::GotoNextNote() const
2867 LyXCursor res = cursor;
2869 if (res.pos < res.par->Last() - 1) {
2872 res.par = res.par->Next();
2877 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2878 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2881 SetCursor(res.par, res.pos);
2888 void LyXText::CheckParagraph(LyXParagraph * par,
2889 LyXParagraph::size_type pos)
2891 LyXCursor tmpcursor;
2894 /* table stuff -- begin*/
2897 CheckParagraphInTable(par, pos);
2900 /* table stuff -- end*/
2903 LyXParagraph::size_type z;
2904 Row * row = GetRow(par, pos, y);
2906 // is there a break one row above
2907 if (row->previous && row->previous->par == row->par) {
2908 z = NextBreakPoint(row->previous, paperwidth);
2909 if ( z >= row->pos) {
2910 // set the dimensions of the row above
2911 y -= row->previous->height;
2913 refresh_row = row->previous;
2914 status = LyXText::NEED_MORE_REFRESH;
2916 BreakAgain(row->previous);
2918 // set the cursor again. Otherwise
2919 // dangling pointers are possible
2920 SetCursor(cursor.par, cursor.pos);
2921 sel_cursor = cursor;
2926 int tmpheight = row->height;
2927 LyXParagraph::size_type tmplast = RowLast(row);
2932 if (row->height == tmpheight && RowLast(row) == tmplast)
2933 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2935 status = LyXText::NEED_MORE_REFRESH;
2937 // check the special right address boxes
2938 if (textclasslist.Style(buffer->params.textclass,
2939 par->GetLayout()).margintype
2940 == MARGIN_RIGHT_ADDRESS_BOX) {
2941 tmpcursor.par = par;
2942 tmpcursor.row = row;
2945 tmpcursor.x_fix = 0;
2946 tmpcursor.pos = pos;
2947 RedoDrawingOfParagraph(tmpcursor);
2952 // set the cursor again. Otherwise dangling pointers are possible
2953 // also set the selection
2957 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2958 sel_cursor = cursor;
2959 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2960 sel_start_cursor = cursor;
2961 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2962 sel_end_cursor = cursor;
2963 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2964 last_sel_cursor = cursor;
2967 SetCursorIntern(cursor.par, cursor.pos);
2971 // returns 0 if inset wasn't found
2972 int LyXText::UpdateInset(Inset * inset)
2974 // first check the current paragraph
2975 int pos = cursor.par->GetPositionOfInset(inset);
2977 CheckParagraph(cursor.par, pos);
2981 // check every paragraph
2983 LyXParagraph * par = FirstParagraph();
2985 // make sure the paragraph is open
2986 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2987 pos = par->GetPositionOfInset(inset);
2989 CheckParagraph(par, pos);
3000 void LyXText::SetCursor(LyXParagraph * par,
3001 LyXParagraph::size_type pos, bool setfont) const
3003 LyXCursor old_cursor = cursor;
3004 SetCursorIntern(par, pos, setfont);
3005 DeleteEmptyParagraphMechanism(old_cursor);
3009 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3010 LyXParagraph::size_type pos) const
3012 // correct the cursor position if impossible
3013 if (pos > par->Last()){
3014 LyXParagraph * tmppar = par->ParFromPos(pos);
3015 pos = par->PositionInParFromPos(pos);
3018 if (par->IsDummy() && par->previous &&
3019 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3020 while (par->previous &&
3021 ((par->previous->IsDummy() &&
3022 (par->previous->previous->footnoteflag ==
3023 LyXParagraph::CLOSED_FOOTNOTE)) ||
3024 (par->previous->footnoteflag ==
3025 LyXParagraph::CLOSED_FOOTNOTE))) {
3026 par = par->previous ;
3027 if (par->IsDummy() &&
3028 (par->previous->footnoteflag ==
3029 LyXParagraph::CLOSED_FOOTNOTE))
3030 pos += par->size() + 1;
3032 if (par->previous) {
3033 par = par->previous;
3035 pos += par->size() + 1;
3041 /* get the cursor y position in text */
3043 Row * row = GetRow(par, pos, y);
3044 /* y is now the beginning of the cursor row */
3046 /* y is now the cursor baseline */
3049 /* now get the cursors x position */
3051 float fill_separator, fill_hfill, fill_label_hfill;
3052 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3053 LyXParagraph::size_type cursor_vpos;
3054 LyXParagraph::size_type last = RowLastPrintable(row);
3056 if (pos > last + 1) // This shouldn't happen.
3059 if (last < row->pos)
3061 else if ((pos > last) ||
3062 ((pos - 1 >= row->pos) &&
3063 (row->par->IsSeparator(pos) ||
3064 (row->par->table && row->par->IsNewline(pos)))))
3065 /// Place cursor after char at (logical) position pos-1
3066 cursor_vpos = !(bidi_level(pos-1) % 2)
3067 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3069 /// Place cursor before char at (logical) position pos
3070 cursor_vpos = !(bidi_level(pos) % 2)
3071 ? log2vis(pos) : log2vis(pos) + 1;
3073 /* table stuff -- begin*/
3074 if (row->par->table) {
3075 int cell = NumberOfCell(row->par, row->pos);
3077 x += row->par->table->GetBeginningOfTextInCell(cell);
3078 for (LyXParagraph::size_type vpos = row->pos;
3079 vpos < cursor_vpos; ++vpos) {
3080 pos = vis2log(vpos);
3081 if (row->par->IsNewline(pos)) {
3082 x = x_old + row->par->table->WidthOfColumn(cell);
3085 x += row->par->table->GetBeginningOfTextInCell(cell);
3087 x += SingleWidth(row->par, pos);
3091 /* table stuff -- end*/
3092 LyXParagraph::size_type main_body =
3093 BeginningOfMainBody(row->par);
3094 if ((main_body > 0) &&
3095 ((main_body-1 > last) ||
3096 !row->par->IsLineSeparator(main_body-1)))
3099 for (LyXParagraph::size_type vpos = row->pos;
3100 vpos < cursor_vpos; ++vpos) {
3101 pos = vis2log(vpos);
3102 if (main_body > 0 && pos == main_body-1) {
3103 x += fill_label_hfill +
3104 lyxfont::width(textclasslist.Style(
3105 buffer->params.textclass,
3106 row->par->GetLayout())
3108 GetFont(row->par, -2));
3109 if (row->par->IsLineSeparator(main_body-1))
3110 x -= SingleWidth(row->par,main_body-1);
3112 if (HfillExpansion(row, pos)) {
3113 x += SingleWidth(row->par, pos);
3114 if (pos >= main_body)
3117 x += fill_label_hfill;
3118 } else if (row->par->IsSeparator(pos)) {
3119 x += SingleWidth(row->par, pos);
3120 if (pos >= main_body)
3121 x += fill_separator;
3123 x += SingleWidth(row->par, pos);
3133 void LyXText::SetCursorIntern(LyXParagraph * par,
3134 LyXParagraph::size_type pos, bool setfont) const
3136 SetCursor(cursor, par, pos);
3137 #warning Remove this when verified working (Jug 20000413)
3139 // correct the cursor position if impossible
3140 if (pos > par->Last()){
3141 LyXParagraph * tmppar = par->ParFromPos(pos);
3142 pos = par->PositionInParFromPos(pos);
3145 if (par->IsDummy() && par->previous &&
3146 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3147 while (par->previous &&
3148 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3149 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3150 par = par->previous ;
3151 if (par->IsDummy() &&
3152 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3153 pos += par->size() + 1;
3155 if (par->previous) {
3156 par = par->previous;
3158 pos += par->size() + 1;
3164 /* get the cursor y position in text */
3166 Row * row = GetRow(par, pos, y);
3167 /* y is now the beginning of the cursor row */
3169 /* y is now the cursor baseline */
3172 /* now get the cursors x position */
3174 float fill_separator, fill_hfill, fill_label_hfill;
3175 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3176 LyXParagraph::size_type cursor_vpos;
3177 LyXParagraph::size_type last = RowLastPrintable(row);
3179 if (pos > last + 1) // This shouldn't happen.
3182 if (last < row->pos)
3184 else if (pos > last ||
3185 (pos - 1 >= row->pos &&
3186 (row->par->IsSeparator(pos) ||
3187 (row->par->table && row->par->IsNewline(pos))
3189 /// Place cursor after char at (logical) position pos-1
3190 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3191 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3193 /// Place cursor before char at (logical) position pos
3194 cursor_vpos = (bidi_level(pos) % 2 == 0)
3195 ? log2vis(pos) : log2vis(pos) + 1;
3197 /* table stuff -- begin*/
3198 if (row->par->table) {
3199 int cell = NumberOfCell(row->par, row->pos);
3201 x += row->par->table->GetBeginningOfTextInCell(cell);
3202 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3203 pos = vis2log(vpos);
3204 if (row->par->IsNewline(pos)) {
3205 x = x_old + row->par->table->WidthOfColumn(cell);
3208 x += row->par->table->GetBeginningOfTextInCell(cell);
3210 x += SingleWidth(row->par, pos);
3214 /* table stuff -- end*/
3215 LyXParagraph::size_type main_body =
3216 BeginningOfMainBody(row->par);
3217 if (main_body > 0 &&
3218 (main_body-1 > last ||
3219 !row->par->IsLineSeparator(main_body-1)))
3222 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3223 pos = vis2log(vpos);
3224 if (main_body > 0 && pos == main_body-1) {
3225 x += fill_label_hfill +
3226 lyxfont::width(textclasslist
3227 .Style(buffer->params.textclass,
3228 row->par->GetLayout())
3230 GetFont(row->par, -2));
3231 if (row->par->IsLineSeparator(main_body-1))
3232 x -= SingleWidth(row->par, main_body-1);
3234 if (HfillExpansion(row, pos)) {
3235 x += SingleWidth(row->par, pos);
3236 if (pos >= main_body)
3239 x += fill_label_hfill;
3241 else if (row->par->IsSeparator(pos)) {
3242 x += SingleWidth(row->par, pos);
3243 if (pos >= main_body)
3244 x += fill_separator;
3246 x += SingleWidth(row->par, pos);
3252 cursor.x_fix = cursor.x;
3257 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3258 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3260 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3261 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3263 current_font = cursor.par->GetFontSettings(cursor.pos);
3264 real_current_font = GetFont(cursor.par, cursor.pos);
3270 void LyXText::SetCursorFromCoordinates(int x, long y) const
3272 LyXCursor old_cursor = cursor;
3274 /* get the row first */
3276 Row * row = GetRowNearY(y);
3278 cursor.par = row->par;
3280 int column = GetColumnNearX(row, x);
3281 cursor.pos = row->pos + column;
3283 cursor.y = y + row->baseline;
3288 (cursor.pos == cursor.par->Last()
3289 || cursor.par->IsSeparator(cursor.pos)
3290 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3291 && !cursor.par->IsSeparator(cursor.pos))
3292 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3294 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3295 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3297 current_font = cursor.par->GetFontSettings(cursor.pos);
3298 real_current_font = GetFont(cursor.par, cursor.pos);
3300 DeleteEmptyParagraphMechanism(old_cursor);
3303 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3305 /* get the row first */
3307 Row * row = GetRowNearY(y);
3308 int column = GetColumnNearX(row, x);
3311 cur.pos = row->pos + column;
3313 cur.y = y + row->baseline;
3318 void LyXText::CursorLeft() const
3321 if (cursor.par->table) {
3322 int cell = NumberOfCell(cursor.par, cursor.pos);
3323 if (cursor.par->table->IsContRow(cell) &&
3324 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3331 void LyXText::CursorLeftIntern() const
3333 if (cursor.pos > 0) {
3334 SetCursor(cursor.par, cursor.pos - 1);
3336 else if (cursor.par->Previous()) { // steps into the above paragraph.
3337 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3342 void LyXText::CursorRight() const
3344 CursorRightIntern();
3345 if (cursor.par->table) {
3346 int cell = NumberOfCell(cursor.par, cursor.pos);
3347 if (cursor.par->table->IsContRow(cell) &&
3348 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3355 void LyXText::CursorRightIntern() const
3357 if (cursor.pos < cursor.par->Last()) {
3358 SetCursor(cursor.par, cursor.pos + 1);
3360 else if (cursor.par->Next()) {
3361 SetCursor(cursor.par->Next(), 0);
3366 void LyXText::CursorUp() const
3368 SetCursorFromCoordinates(cursor.x_fix,
3369 cursor.y - cursor.row->baseline - 1);
3370 if (cursor.par->table) {
3371 int cell = NumberOfCell(cursor.par, cursor.pos);
3372 if (cursor.par->table->IsContRow(cell) &&
3373 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3380 void LyXText::CursorDown() const
3382 if (cursor.par->table &&
3383 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3386 SetCursorFromCoordinates(cursor.x_fix,
3387 cursor.y - cursor.row->baseline
3388 + cursor.row->height + 1);
3389 if (cursor.par->table) {
3390 int cell = NumberOfCell(cursor.par, cursor.pos);
3391 int cell_above = cursor.par->table->GetCellAbove(cell);
3392 while(cursor.par->table &&
3393 cursor.par->table->IsContRow(cell) &&
3394 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3395 SetCursorFromCoordinates(cursor.x_fix,
3396 cursor.y - cursor.row->baseline
3397 + cursor.row->height + 1);
3398 if (cursor.par->table) {
3399 cell = NumberOfCell(cursor.par, cursor.pos);
3400 cell_above = cursor.par->table->GetCellAbove(cell);
3407 void LyXText::CursorUpParagraph() const
3409 if (cursor.pos > 0) {
3410 SetCursor(cursor.par, 0);
3412 else if (cursor.par->Previous()) {
3413 SetCursor(cursor.par->Previous(), 0);
3418 void LyXText::CursorDownParagraph() const
3420 if (cursor.par->Next()) {
3421 SetCursor(cursor.par->Next(), 0);
3423 SetCursor(cursor.par, cursor.par->Last());
3429 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3431 // Would be wrong to delete anything if we have a selection.
3432 if (selection) return;
3434 // We allow all kinds of "mumbo-jumbo" when freespacing.
3435 if (textclasslist.Style(buffer->params.textclass,
3436 old_cursor.par->GetLayout()).free_spacing)
3439 bool deleted = false;
3441 /* Ok I'll put some comments here about what is missing.
3442 I have fixed BackSpace (and thus Delete) to not delete
3443 double-spaces automagically. I have also changed Cut,
3444 Copy and Paste to hopefully do some sensible things.
3445 There are still some small problems that can lead to
3446 double spaces stored in the document file or space at
3447 the beginning of paragraphs. This happens if you have
3448 the cursor betwenn to spaces and then save. Or if you
3449 cut and paste and the selection have a space at the
3450 beginning and then save right after the paste. I am
3451 sure none of these are very hard to fix, but I will
3452 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3453 that I can get some feedback. (Lgb)
3456 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3457 // delete the LineSeparator.
3460 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3461 // delete the LineSeparator.
3464 // If the pos around the old_cursor were spaces, delete one of them.
3465 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3467 if (old_cursor.pos > 0
3468 && old_cursor.pos < old_cursor.par->Last()
3469 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3470 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3471 old_cursor.par->Erase(old_cursor.pos - 1);
3472 RedoParagraphs(old_cursor, old_cursor.par->Next());
3474 if (old_cursor.par == cursor.par &&
3475 cursor.pos > old_cursor.pos) {
3476 SetCursorIntern(cursor.par, cursor.pos - 1);
3478 SetCursorIntern(cursor.par, cursor.pos);
3483 // Do not delete empty paragraphs with keepempty set.
3484 if ((textclasslist.Style(buffer->params.textclass,
3485 old_cursor.par->GetLayout())).keepempty)
3488 LyXCursor tmpcursor;
3490 if (old_cursor.par != cursor.par) {
3491 if ( (old_cursor.par->Last() == 0
3492 || (old_cursor.par->Last() == 1
3493 && old_cursor.par->IsLineSeparator(0)))
3494 && old_cursor.par->FirstPhysicalPar()
3495 == old_cursor.par->LastPhysicalPar()) {
3496 // ok, we will delete anything
3498 // make sure that you do not delete any environments
3499 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3500 !(old_cursor.row->previous
3501 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3502 && !(old_cursor.row->next
3503 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3504 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3505 && ((old_cursor.row->previous
3506 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3507 || (old_cursor.row->next
3508 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3510 status = LyXText::NEED_MORE_REFRESH;
3513 if (old_cursor.row->previous) {
3514 refresh_row = old_cursor.row->previous;
3515 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3517 cursor = old_cursor; // that undo can restore the right cursor position
3518 LyXParagraph * endpar = old_cursor.par->next;
3519 if (endpar && endpar->GetDepth()) {
3520 while (endpar && endpar->GetDepth()) {
3521 endpar = endpar->LastPhysicalPar()->Next();
3524 SetUndo(Undo::DELETE,
3525 old_cursor.par->previous,
3530 RemoveRow(old_cursor.row);
3531 if (buffer->paragraph == old_cursor.par) {
3532 buffer->paragraph = buffer->paragraph->next;
3535 delete old_cursor.par;
3537 /* Breakagain the next par. Needed
3538 * because of the parindent that
3539 * can occur or dissappear. The
3540 * next row can change its height,
3541 * if there is another layout before */
3542 if (refresh_row->next) {
3543 BreakAgain(refresh_row->next);
3544 UpdateCounters(refresh_row);
3546 SetHeightOfRow(refresh_row);
3548 refresh_row = old_cursor.row->next;
3549 refresh_y = old_cursor.y - old_cursor.row->baseline;
3552 cursor = old_cursor; // that undo can restore the right cursor position
3553 LyXParagraph *endpar = old_cursor.par->next;
3554 if (endpar && endpar->GetDepth()) {
3555 while (endpar && endpar->GetDepth()) {
3556 endpar = endpar->LastPhysicalPar()->Next();
3559 SetUndo(Undo::DELETE,
3560 old_cursor.par->previous,
3565 RemoveRow(old_cursor.row);
3567 if (buffer->paragraph == old_cursor.par) {
3568 buffer->paragraph = buffer->paragraph->next;
3570 delete old_cursor.par;
3572 /* Breakagain the next par. Needed
3573 because of the parindent that can
3574 occur or dissappear.
3575 The next row can change its height,
3576 if there is another layout before
3579 BreakAgain(refresh_row);
3580 UpdateCounters(refresh_row->previous);
3586 SetCursorIntern(cursor.par, cursor.pos);
3588 if (sel_cursor.par == old_cursor.par
3589 && sel_cursor.pos == sel_cursor.pos) {
3590 // correct selection
3591 sel_cursor = cursor;
3596 if (old_cursor.par->ClearParagraph()) {
3597 RedoParagraphs(old_cursor, old_cursor.par->Next());
3599 SetCursorIntern(cursor.par, cursor.pos);
3600 sel_cursor = cursor;
3607 LyXParagraph * LyXText::GetParFromID(int id)
3609 LyXParagraph * result = FirstParagraph();
3610 while (result && result->id() != id)
3611 result = result->next;
3617 bool LyXText::TextUndo()
3619 // returns false if no undo possible
3620 Undo * undo = buffer->undostack.pop();
3625 .push(CreateUndo(undo->kind,
3626 GetParFromID(undo->number_of_before_par),
3627 GetParFromID(undo->number_of_behind_par)));
3629 return TextHandleUndo(undo);
3633 bool LyXText::TextRedo()
3635 // returns false if no redo possible
3636 Undo * undo = buffer->redostack.pop();
3641 .push(CreateUndo(undo->kind,
3642 GetParFromID(undo->number_of_before_par),
3643 GetParFromID(undo->number_of_behind_par)));
3645 return TextHandleUndo(undo);
3649 bool LyXText::TextHandleUndo(Undo * undo)
3651 // returns false if no undo possible
3652 bool result = false;
3654 LyXParagraph * before =
3655 GetParFromID(undo->number_of_before_par);
3656 LyXParagraph * behind =
3657 GetParFromID(undo->number_of_behind_par);
3658 LyXParagraph * tmppar;
3659 LyXParagraph * tmppar2;
3660 LyXParagraph * endpar;
3661 LyXParagraph * tmppar5;
3663 // if there's no before take the beginning
3664 // of the document for redoing
3666 SetCursorIntern(FirstParagraph(), 0);
3668 // replace the paragraphs with the undo informations
3670 LyXParagraph * tmppar3 = undo->par;
3671 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3672 LyXParagraph * tmppar4 = tmppar3;
3674 while (tmppar4->next)
3675 tmppar4 = tmppar4->next;
3676 } // get last undo par
3678 // now remove the old text if there is any
3679 if (before != behind || (!behind && !before)){
3681 tmppar5 = before->next;
3683 tmppar5 = buffer->paragraph;
3685 while (tmppar5 && tmppar5 != behind){
3687 tmppar5 = tmppar5->next;
3688 // a memory optimization for edit: Only layout information
3689 // is stored in the undo. So restore the text informations.
3690 if (undo->kind == Undo::EDIT) {
3691 tmppar2->setContentsFromPar(tmppar);
3692 tmppar->clearContents();
3693 tmppar2 = tmppar2->next;
3698 // put the new stuff in the list if there is one
3701 before->next = tmppar3;
3703 buffer->paragraph = tmppar3;
3704 tmppar3->previous = before;
3708 buffer->paragraph = behind;
3711 tmppar4->next = behind;
3713 behind->previous = tmppar4;
3717 // Set the cursor for redoing
3719 SetCursorIntern(before->FirstSelfrowPar(), 0);
3720 // check wether before points to a closed float and open it if necessary
3721 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3722 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3724 while (tmppar4->previous &&
3725 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3726 tmppar4 = tmppar4->previous;
3727 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3728 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3729 tmppar4 = tmppar4->next;
3734 // open a cosed footnote at the end if necessary
3735 if (behind && behind->previous &&
3736 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3737 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3738 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3739 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3740 behind = behind->next;
3744 // calculate the endpar for redoing the paragraphs.
3746 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3747 endpar = behind->LastPhysicalPar()->Next();
3749 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3754 tmppar = GetParFromID(undo->number_of_cursor_par);
3755 RedoParagraphs(cursor, endpar);
3757 SetCursorIntern(tmppar, undo->cursor_pos);
3758 UpdateCounters(cursor.row);
3768 void LyXText::FinishUndo()
3770 // makes sure the next operation will be stored
3771 undo_finished = True;
3775 void LyXText::FreezeUndo()
3777 // this is dangerous and for internal use only
3782 void LyXText::UnFreezeUndo()
3784 // this is dangerous and for internal use only
3785 undo_frozen = false;
3789 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3790 LyXParagraph const * behind) const
3793 buffer->undostack.push(CreateUndo(kind, before, behind));
3794 buffer->redostack.clear();
3798 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3799 LyXParagraph const * behind)
3801 buffer->redostack.push(CreateUndo(kind, before, behind));
3805 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3806 LyXParagraph const * behind) const
3808 int before_number = -1;
3809 int behind_number = -1;
3811 before_number = before->id();
3813 behind_number = behind->id();
3814 // Undo::EDIT and Undo::FINISH are
3815 // always finished. (no overlapping there)
3816 // overlapping only with insert and delete inside one paragraph:
3817 // Nobody wants all removed character
3818 // appear one by one when undoing.
3819 // EDIT is special since only layout information, not the
3820 // contents of a paragaph are stored.
3821 if (!undo_finished && kind != Undo::EDIT &&
3822 kind != Undo::FINISH){
3823 // check wether storing is needed
3824 if (!buffer->undostack.empty() &&
3825 buffer->undostack.top()->kind == kind &&
3826 buffer->undostack.top()->number_of_before_par == before_number &&
3827 buffer->undostack.top()->number_of_behind_par == behind_number ){
3832 // create a new Undo
3833 LyXParagraph * undopar;
3834 LyXParagraph * tmppar;
3835 LyXParagraph * tmppar2;
3837 LyXParagraph * start = 0;
3838 LyXParagraph * end = 0;
3841 start = before->next;
3843 start = FirstParagraph();
3845 end = behind->previous;
3847 end = FirstParagraph();
3853 && start != end->next
3854 && (before != behind || (!before && !behind))) {
3856 tmppar2 = tmppar->Clone();
3857 tmppar2->id(tmppar->id());
3859 // a memory optimization: Just store the layout information
3861 if (kind == Undo::EDIT){
3862 //tmppar2->text.clear();
3863 tmppar2->clearContents();
3868 while (tmppar != end && tmppar->next) {
3869 tmppar = tmppar->next;
3870 tmppar2->next = tmppar->Clone();
3871 tmppar2->next->id(tmppar->id());
3872 // a memory optimization: Just store the layout
3873 // information when only edit
3874 if (kind == Undo::EDIT){
3875 //tmppar2->next->text.clear();
3876 tmppar2->clearContents();
3878 tmppar2->next->previous = tmppar2;
3879 tmppar2 = tmppar2->next;
3883 undopar = 0; // nothing to replace (undo of delete maybe)
3885 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3886 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3888 Undo * undo = new Undo(kind,
3889 before_number, behind_number,
3890 cursor_par, cursor_pos,
3893 undo_finished = false;
3898 void LyXText::SetCursorParUndo()
3900 SetUndo(Undo::FINISH,
3901 cursor.par->ParFromPos(cursor.pos)->previous,
3902 cursor.par->ParFromPos(cursor.pos)->next);
3906 void LyXText::RemoveTableRow(LyXCursor * cur) const
3912 // move to the previous row
3913 int cell_act = NumberOfCell(cur->par, cur->pos);
3916 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3919 !cur->par->table->IsFirstCell(cell_act)) {
3921 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3926 // now we have to pay attention if the actual table is the
3927 // main row of TableContRows and if yes to delete all of them
3932 // delete up to the next row
3933 while (cur->pos < cur->par->Last() &&
3935 || !cur->par->table->IsFirstCell(cell_act))) {
3936 while (cur->pos < cur->par->Last() &&
3937 !cur->par->IsNewline(cur->pos))
3938 cur->par->Erase(cur->pos);
3941 if (cur->pos < cur->par->Last())
3942 cur->par->Erase(cur->pos);
3944 if (cur->pos && cur->pos == cur->par->Last()) {
3946 cur->par->Erase(cur->pos); // no newline at very end!
3948 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3949 !cur->par->table->IsContRow(cell_org) &&
3950 cur->par->table->IsContRow(cell));
3951 cur->par->table->DeleteRow(cell_org);
3956 bool LyXText::IsEmptyTableCell() const
3958 LyXParagraph::size_type pos = cursor.pos - 1;
3959 while (pos >= 0 && pos < cursor.par->Last()
3960 && !cursor.par->IsNewline(pos))
3962 return cursor.par->IsNewline(pos + 1);
3966 void LyXText::toggleAppendix(){
3967 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3968 bool start = !par->start_of_appendix;
3970 // ensure that we have only one start_of_appendix in this document
3971 LyXParagraph * tmp = FirstParagraph();
3972 for (; tmp; tmp = tmp->next)
3973 tmp->start_of_appendix = 0;
3974 par->start_of_appendix = start;
3976 // we can set the refreshing parameters now
3977 status = LyXText::NEED_MORE_REFRESH;
3979 refresh_row = 0; // not needed for full update
3981 SetCursor(cursor.par, cursor.pos);