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 FIX_DOUBLE_SPACE 1
44 //#define USE_OLD_CUT_AND_PASTE 1
50 LyXText::LyXText(BufferView * bv, int pw, Buffer * p)
58 //bparams = &p->params;
62 status = LyXText::UNCHANGED;
63 LyXParagraph * par = p->paragraph;
64 current_font = GetFont(par, 0);
69 InsertParagraph(par, lastrow);
73 // set cursor at the very top position
74 selection = true; /* these setting is necessary
75 because of the delete-empty-
76 paragraph mechanism in
78 SetCursor(firstrow->par, 0);
83 // no rebreak necessary
89 // Default layouttype for copy environment type
96 // Delete all rows, this does not touch the paragraphs!
97 Row * tmprow = firstrow;
99 tmprow = firstrow->next;
106 void LyXText::owner(BufferView * bv)
108 if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
112 // Gets the fully instantiated font at a given position in a paragraph
113 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
114 // The difference is that this one is used for displaying, and thus we
115 // are allowed to make cosmetic improvements. For instance make footnotes
117 // If position is -1, we get the layout font of the paragraph.
118 // If position is -2, we get the font of the manual label of the paragraph.
119 LyXFont LyXText::GetFont(LyXParagraph * par,
120 LyXParagraph::size_type pos) const
122 LyXLayout const & layout =
123 textclasslist.Style(buffer->params.textclass,
126 char par_depth = par->GetDepth();
127 // We specialize the 95% common case:
128 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
131 if (layout.labeltype == LABEL_MANUAL
132 && pos < BeginningOfMainBody(par)) {
134 return par->GetFontSettings(pos).
135 realize(layout.reslabelfont);
137 return par->GetFontSettings(pos).
138 realize(layout.resfont);
141 // process layoutfont for pos == -1 and labelfont for pos < -1
143 return layout.resfont;
145 return layout.reslabelfont;
149 // The uncommon case need not be optimized as much
151 LyXFont layoutfont, tmpfont;
155 if (pos < BeginningOfMainBody(par)) {
157 layoutfont = layout.labelfont;
160 layoutfont = layout.font;
162 tmpfont = par->GetFontSettings(pos);
163 tmpfont.realize(layoutfont);
166 // process layoutfont for pos == -1 and labelfont for pos < -1
168 tmpfont = layout.font;
170 tmpfont = layout.labelfont;
173 // Resolve against environment font information
174 while (par && par_depth && !tmpfont.resolved()) {
175 par = par->DepthHook(par_depth - 1);
177 tmpfont.realize(textclasslist.
178 Style(buffer->params.textclass,
179 par->GetLayout()).font);
180 par_depth = par->GetDepth();
184 tmpfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
186 // Cosmetic improvement: If this is an open footnote, make the font
188 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
189 && par->footnotekind == LyXParagraph::FOOTNOTE) {
197 void LyXText::SetCharFont(LyXParagraph * par,
198 LyXParagraph::size_type pos,
202 // Let the insets convert their font
203 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
204 if (par->GetInset(pos))
205 font = par->GetInset(pos)->ConvertFont(font);
208 LyXLayout const & layout =
209 textclasslist.Style(buffer->params.textclass,
212 // Get concrete layout font to reduce against
215 if (pos < BeginningOfMainBody(par))
216 layoutfont = layout.labelfont;
218 layoutfont = layout.font;
220 // Realize against environment font information
221 if (par->GetDepth()){
222 LyXParagraph * tp = par;
223 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
224 tp = tp->DepthHook(tp->GetDepth()-1);
226 layoutfont.realize(textclasslist.
227 Style(buffer->params.textclass,
228 tp->GetLayout()).font);
232 layoutfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
234 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
235 && par->footnotekind == LyXParagraph::FOOTNOTE) {
236 layoutfont.decSize();
239 // Now, reduce font against full layout font
240 font.reduce(layoutfont);
242 par->SetFont(pos, font);
246 /* inserts a new row behind the specified row, increments
247 * the touched counters */
248 void LyXText::InsertRow(Row * row, LyXParagraph * par,
249 LyXParagraph::size_type pos) const
251 Row * tmprow = new Row;
253 tmprow->previous = 0;
254 tmprow->next = firstrow;
257 tmprow->previous = row;
258 tmprow->next = row->next;
263 tmprow->next->previous = tmprow;
265 if (tmprow->previous)
266 tmprow->previous->next = tmprow;
274 ++number_of_rows; // one more row
278 // removes the row and reset the touched counters
279 void LyXText::RemoveRow(Row * row) const
281 /* this must not happen before the currentrow for clear reasons.
282 so the trick is just to set the current row onto the previous
285 GetRow(row->par, row->pos, unused_y);
286 currentrow = currentrow->previous;
288 currentrow_y -= currentrow->height;
293 row->next->previous = row->previous;
294 if (!row->previous) {
295 firstrow = row->next;
297 row->previous->next = row->next;
300 lastrow = row->previous;
302 height -= row->height; // the text becomes smaller
305 --number_of_rows; // one row less
309 // remove all following rows of the paragraph of the specified row.
310 void LyXText::RemoveParagraph(Row * row) const
312 LyXParagraph * tmppar = row->par;
316 while (row && row->par == tmppar) {
324 // insert the specified paragraph behind the specified row
325 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
327 InsertRow(row, par, 0); /* insert a new row, starting
330 SetCounter(par); // set the counters
332 // and now append the whole paragraph behind the new row
334 firstrow->height = 0;
335 AppendParagraph(firstrow);
337 row->next->height = 0;
338 AppendParagraph(row->next);
343 void LyXText::ToggleFootnote()
345 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
347 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
349 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
351 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
357 void LyXText::OpenStuff()
359 if (cursor.pos == 0 && cursor.par->bibkey){
360 cursor.par->bibkey->Edit(owner_, 0, 0, 0);
362 else if (cursor.pos < cursor.par->Last()
363 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
364 && cursor.par->GetInset(cursor.pos)->Editable()) {
365 owner_->owner()->getMiniBuffer()
366 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
367 if (cursor.par->GetInset(cursor.pos)->Editable() != Inset::HIGHLY_EDITABLE)
369 cursor.par->GetInset(cursor.pos)->Edit(owner_, 0, 0, 0);
376 void LyXText::CloseFootnote()
378 LyXParagraph * tmppar;
379 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
381 // if the cursor is not in an open footnote, or
382 // there is no open footnote in this paragraph, just return.
383 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
386 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
387 owner_->owner()->getMiniBuffer()
388 ->Set(_("Nothing to do"));
392 // ok, move the cursor right before the footnote
393 // just a little faster than using CursorRight()
395 cursor.par->ParFromPos(cursor.pos) != par;
399 // now the cursor is at the beginning of the physical par
400 SetCursor(cursor.par,
402 cursor.par->ParFromPos(cursor.pos)->size());
404 /* we are in a footnote, so let us move at the beginning */
405 /* this is just faster than using just CursorLeft() */
408 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
409 // just a little bit faster than movin the cursor
410 tmppar = tmppar->Previous();
412 SetCursor(tmppar, tmppar->Last());
415 // the cursor must be exactly before the footnote
416 par = cursor.par->ParFromPos(cursor.pos);
418 status = LyXText::NEED_MORE_REFRESH;
419 refresh_row = cursor.row;
420 refresh_y = cursor.y - cursor.row->baseline;
423 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
424 Row * row = cursor.row;
426 tmppar->CloseFootnote(cursor.pos);
428 while (tmppar != endpar) {
429 RemoveRow(row->next);
431 tmppar = row->next->par;
436 AppendParagraph(cursor.row);
438 SetCursor(cursor.par, cursor.pos);
442 if (cursor.row->next)
443 SetHeightOfRow(cursor.row->next);
447 /* used in setlayout */
448 // Asger is not sure we want to do this...
449 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
452 LyXLayout const & layout =
453 textclasslist.Style(buffer->params.textclass,
456 LyXFont layoutfont, tmpfont;
457 for (LyXParagraph::size_type pos = 0;
458 pos < par->Last(); ++pos) {
459 if (pos < BeginningOfMainBody(par))
460 layoutfont = layout.labelfont;
462 layoutfont = layout.font;
464 tmpfont = par->GetFontSettings(pos);
465 tmpfont.reduce(layoutfont);
466 par->SetFont(pos, tmpfont);
471 // set layout over selection and make a total rebreak of those paragraphs
472 void LyXText::SetLayout(LyXTextClass::size_type layout)
476 // if there is no selection just set the layout
477 // of the current paragraph */
479 sel_start_cursor = cursor; // dummy selection
480 sel_end_cursor = cursor;
483 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
484 LyXParagraph * undoendpar = endpar;
486 if (endpar && endpar->GetDepth()) {
487 while (endpar && endpar->GetDepth()) {
488 endpar = endpar->LastPhysicalPar()->Next();
493 endpar = endpar->Next(); // because of parindents etc.
497 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
500 tmpcursor = cursor; /* store the current cursor */
502 /* ok we have a selection. This is always between sel_start_cursor
503 * and sel_end cursor */
504 cursor = sel_start_cursor;
506 LyXLayout const & lyxlayout =
507 textclasslist.Style(buffer->params.textclass, layout);
509 while (cursor.par != sel_end_cursor.par) {
510 if (cursor.par->footnoteflag ==
511 sel_start_cursor.par->footnoteflag) {
512 cursor.par->SetLayout(layout);
513 MakeFontEntriesLayoutSpecific(cursor.par);
514 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
515 fppar->added_space_top = lyxlayout.fill_top ?
516 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
517 fppar->added_space_bottom = lyxlayout.fill_bottom ?
518 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
519 if (lyxlayout.margintype == MARGIN_MANUAL)
520 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
521 if (lyxlayout.labeltype != LABEL_BIBLIO
523 delete fppar->bibkey;
527 cursor.par = cursor.par->Next();
529 if (cursor.par->footnoteflag ==
530 sel_start_cursor.par->footnoteflag) {
531 cursor.par->SetLayout(layout);
532 MakeFontEntriesLayoutSpecific(cursor.par);
533 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
534 fppar->added_space_top = lyxlayout.fill_top ?
535 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
536 fppar->added_space_bottom = lyxlayout.fill_bottom ?
537 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
538 if (lyxlayout.margintype == MARGIN_MANUAL)
539 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
540 if (lyxlayout.labeltype != LABEL_BIBLIO
542 delete fppar->bibkey;
547 RedoParagraphs(sel_start_cursor, endpar);
549 // we have to reset the selection, because the
550 // geometry could have changed */
551 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
553 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
554 UpdateCounters(cursor.row);
557 SetCursor(tmpcursor.par, tmpcursor.pos, true);
561 // increment depth over selection and
562 // make a total rebreak of those paragraphs
563 void LyXText::IncDepth()
565 // If there is no selection, just use the current paragraph
567 sel_start_cursor = cursor; // dummy selection
568 sel_end_cursor = cursor;
571 // We end at the next paragraph with depth 0
572 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
573 LyXParagraph * undoendpar = endpar;
575 if (endpar && endpar->GetDepth()) {
576 while (endpar && endpar->GetDepth()) {
577 endpar = endpar->LastPhysicalPar()->Next();
582 endpar = endpar->Next(); // because of parindents etc.
587 .par->ParFromPos(sel_start_cursor.pos)->previous,
590 LyXCursor tmpcursor = cursor; // store the current cursor
592 // ok we have a selection. This is always between sel_start_cursor
593 // and sel_end cursor
594 cursor = sel_start_cursor;
596 bool anything_changed = false;
599 // NOTE: you can't change the depth of a bibliography entry
600 if (cursor.par->footnoteflag ==
601 sel_start_cursor.par->footnoteflag
602 && textclasslist.Style(buffer->params.textclass,
603 cursor.par->GetLayout()
604 ).labeltype != LABEL_BIBLIO) {
605 LyXParagraph * prev =
606 cursor.par->FirstPhysicalPar()->Previous();
608 && (prev->GetDepth() - cursor.par->GetDepth() > 0
609 || (prev->GetDepth() == cursor.par->GetDepth()
610 && textclasslist.Style(buffer->params.textclass,
611 prev->GetLayout()).isEnvironment()))) {
612 cursor.par->FirstPhysicalPar()->depth++;
613 anything_changed = true;
616 if (cursor.par == sel_end_cursor.par)
618 cursor.par = cursor.par->Next();
621 // if nothing changed set all depth to 0
622 if (!anything_changed) {
623 cursor = sel_start_cursor;
624 while (cursor.par != sel_end_cursor.par) {
625 cursor.par->FirstPhysicalPar()->depth = 0;
626 cursor.par = cursor.par->Next();
628 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
629 cursor.par->FirstPhysicalPar()->depth = 0;
632 RedoParagraphs(sel_start_cursor, endpar);
634 // we have to reset the selection, because the
635 // geometry could have changed
636 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
638 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
639 UpdateCounters(cursor.row);
642 SetCursor(tmpcursor.par, tmpcursor.pos);
646 // decrement depth over selection and
647 // make a total rebreak of those paragraphs
648 void LyXText::DecDepth()
650 // if there is no selection just set the layout
651 // of the current paragraph
653 sel_start_cursor = cursor; // dummy selection
654 sel_end_cursor = cursor;
657 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
658 LyXParagraph * undoendpar = endpar;
660 if (endpar && endpar->GetDepth()) {
661 while (endpar && endpar->GetDepth()) {
662 endpar = endpar->LastPhysicalPar()->Next();
667 endpar = endpar->Next(); // because of parindents etc.
672 .par->ParFromPos(sel_start_cursor.pos)->previous,
675 LyXCursor tmpcursor = cursor; // store the current cursor
677 // ok we have a selection. This is always between sel_start_cursor
678 // and sel_end cursor
679 cursor = sel_start_cursor;
682 if (cursor.par->footnoteflag ==
683 sel_start_cursor.par->footnoteflag) {
684 if (cursor.par->FirstPhysicalPar()->depth)
685 cursor.par->FirstPhysicalPar()->depth--;
687 if (cursor.par == sel_end_cursor.par)
689 cursor.par = cursor.par->Next();
692 RedoParagraphs(sel_start_cursor, endpar);
694 // we have to reset the selection, because the
695 // geometry could have changed
696 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
698 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
699 UpdateCounters(cursor.row);
702 SetCursor(tmpcursor.par, tmpcursor.pos);
706 // set font over selection and make a total rebreak of those paragraphs
707 void LyXText::SetFont(LyXFont const & font, bool toggleall)
709 // if there is no selection just set the current_font
711 // Determine basis font
713 if (cursor.pos < BeginningOfMainBody(cursor.par))
714 layoutfont = GetFont(cursor.par, -2);
716 layoutfont = GetFont(cursor.par, -1);
717 // Update current font
718 real_current_font.update(font,
719 buffer->params.language_info,
722 // Reduce to implicit settings
723 current_font = real_current_font;
724 current_font.reduce(layoutfont);
725 // And resolve it completely
726 real_current_font.realize(layoutfont);
730 LyXCursor tmpcursor = cursor; // store the current cursor
732 // ok we have a selection. This is always between sel_start_cursor
733 // and sel_end cursor
736 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
737 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
738 cursor = sel_start_cursor;
739 while (cursor.par != sel_end_cursor.par ||
740 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
741 && cursor.pos < sel_end_cursor.pos))
743 if (cursor.pos < cursor.par->Last()
744 && cursor.par->footnoteflag
745 == sel_start_cursor.par->footnoteflag) {
746 // an open footnote should behave
748 LyXFont newfont = GetFont(cursor.par, cursor.pos);
750 buffer->params.language_info,
752 SetCharFont(cursor.par, cursor.pos, newfont);
756 cursor.par = cursor.par->Next();
760 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
762 // we have to reset the selection, because the
763 // geometry could have changed
764 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
766 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
769 SetCursor(tmpcursor.par, tmpcursor.pos);
773 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
775 Row * tmprow = cur.row;
776 long y = cur.y - tmprow->baseline;
778 SetHeightOfRow(tmprow);
779 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
780 // find the first row of the paragraph
781 if (first_phys_par != tmprow->par)
782 while (tmprow->previous
783 && tmprow->previous->par != first_phys_par) {
784 tmprow = tmprow->previous;
786 SetHeightOfRow(tmprow);
788 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
789 tmprow = tmprow->previous;
791 SetHeightOfRow(tmprow);
794 // we can set the refreshing parameters now
795 status = LyXText::NEED_MORE_REFRESH;
797 refresh_row = tmprow;
798 SetCursor(cur.par, cur.pos);
802 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
804 Row * tmprow = cur.row;
806 long y = cur.y - tmprow->baseline;
807 SetHeightOfRow(tmprow);
808 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
809 // find the first row of the paragraph
810 if (first_phys_par != tmprow->par)
811 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
812 tmprow = tmprow->previous;
815 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
816 tmprow = tmprow->previous;
820 // we can set the refreshing parameters now
821 if (status == LyXText::UNCHANGED || y < refresh_y) {
823 refresh_row = tmprow;
825 status = LyXText::NEED_MORE_REFRESH;
826 SetCursor(cur.par, cur.pos);
830 /* deletes and inserts again all paragaphs between the cursor
831 * and the specified par
832 * This function is needed after SetLayout and SetFont etc. */
833 void LyXText::RedoParagraphs(LyXCursor const & cur,
834 LyXParagraph const * endpar) const
837 LyXParagraph * tmppar, * first_phys_par;
839 Row * tmprow = cur.row;
841 long y = cur.y - tmprow->baseline;
843 if (!tmprow->previous){
844 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
846 first_phys_par = tmprow->par->FirstPhysicalPar();
847 // find the first row of the paragraph
848 if (first_phys_par != tmprow->par)
849 while (tmprow->previous &&
850 (tmprow->previous->par != first_phys_par)) {
851 tmprow = tmprow->previous;
854 while (tmprow->previous
855 && tmprow->previous->par == first_phys_par) {
856 tmprow = tmprow->previous;
861 // we can set the refreshing parameters now
862 status = LyXText::NEED_MORE_REFRESH;
864 refresh_row = tmprow->previous; /* the real refresh row will
865 be deleted, so I store
869 tmppar = tmprow->next->par;
872 while (tmppar != endpar) {
873 RemoveRow(tmprow->next);
875 tmppar = tmprow->next->par;
880 // remove the first one
881 tmprow2 = tmprow; /* this is because tmprow->previous
883 tmprow = tmprow->previous;
886 tmppar = first_phys_par;
890 InsertParagraph(tmppar, tmprow);
893 while (tmprow->next && tmprow->next->par == tmppar)
894 tmprow = tmprow->next;
895 tmppar = tmppar->Next();
897 } while (tmppar != endpar);
899 // this is because of layout changes
901 refresh_y -= refresh_row->height;
902 SetHeightOfRow(refresh_row);
904 refresh_row = firstrow;
906 SetHeightOfRow(refresh_row);
909 if (tmprow && tmprow->next)
910 SetHeightOfRow(tmprow->next);
914 int LyXText::FullRebreak()
916 if (need_break_row) {
917 BreakAgain(need_break_row);
925 /* important for the screen */
928 /* the cursor set functions have a special mechanism. When they
929 * realize, that you left an empty paragraph, they will delete it.
930 * They also delet the corresponding row */
932 // need the selection cursor:
933 void LyXText::SetSelection()
936 last_sel_cursor = sel_cursor;
937 sel_start_cursor = sel_cursor;
938 sel_end_cursor = sel_cursor;
943 // first the toggling area
944 if (cursor.y < last_sel_cursor.y ||
945 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
946 toggle_end_cursor = last_sel_cursor;
947 toggle_cursor = cursor;
950 toggle_end_cursor = cursor;
951 toggle_cursor = last_sel_cursor;
954 last_sel_cursor = cursor;
956 // and now the whole selection
958 if (sel_cursor.par == cursor.par)
959 if (sel_cursor.pos < cursor.pos) {
960 sel_end_cursor = cursor;
961 sel_start_cursor = sel_cursor;
963 sel_end_cursor = sel_cursor;
964 sel_start_cursor = cursor;
966 else if (sel_cursor.y < cursor.y ||
967 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
968 sel_end_cursor = cursor;
969 sel_start_cursor = sel_cursor;
972 sel_end_cursor = sel_cursor;
973 sel_start_cursor = cursor;
976 // a selection with no contents is not a selection
977 if (sel_start_cursor.x == sel_end_cursor.x &&
978 sel_start_cursor.y == sel_end_cursor.y)
983 void LyXText::ClearSelection() const
990 void LyXText::CursorHome() const
992 SetCursor(cursor.par, cursor.row->pos);
996 void LyXText::CursorEnd() const
998 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
999 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1001 if (cursor.par->Last() &&
1002 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1003 || cursor.par->IsNewline(RowLast(cursor.row))))
1004 SetCursor(cursor.par, RowLast(cursor.row));
1006 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1008 if (cursor.par->table) {
1009 int cell = NumberOfCell(cursor.par, cursor.pos);
1010 if (cursor.par->table->RowHasContRow(cell) &&
1011 cursor.par->table->CellHasContRow(cell)<0) {
1012 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1013 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1015 if (cursor.par->Last() &&
1016 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1017 || cursor.par->IsNewline(RowLast(cursor.row))))
1018 SetCursor(cursor.par, RowLast(cursor.row));
1020 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1027 void LyXText::CursorTop() const
1029 while (cursor.par->Previous())
1030 cursor.par = cursor.par->Previous();
1031 SetCursor(cursor.par, 0);
1035 void LyXText::CursorBottom() const
1037 while (cursor.par->Next())
1038 cursor.par = cursor.par->Next();
1039 SetCursor(cursor.par, cursor.par->Last());
1043 /* returns a pointer to the row near the specified y-coordinate
1044 * (relative to the whole text). y is set to the real beginning
1046 Row * LyXText::GetRowNearY(long & y) const
1052 tmprow = currentrow;
1053 tmpy = currentrow_y;
1060 while (tmprow->next && tmpy + tmprow->height <= y) {
1061 tmpy += tmprow->height;
1062 tmprow = tmprow->next;
1065 while (tmprow->previous && tmpy > y) {
1066 tmprow = tmprow->previous;
1067 tmpy -= tmprow->height;
1070 currentrow = tmprow;
1071 currentrow_y = tmpy;
1073 y = tmpy; // return the real y
1078 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1080 // If the mask is completely neutral, tell user
1081 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1082 // Could only happen with user style
1083 owner_->owner()->getMiniBuffer()
1084 ->Set(_("No font change defined. Use Character under"
1085 " the Layout menu to define font change."));
1089 // Try implicit word selection
1090 LyXCursor resetCursor = cursor;
1091 int implicitSelection = SelectWordWhenUnderCursor();
1094 SetFont(font, toggleall);
1096 /* Implicit selections are cleared afterwards and cursor is set to the
1097 original position. */
1098 if (implicitSelection) {
1100 cursor = resetCursor;
1101 SetCursor( cursor.par, cursor.pos );
1102 sel_cursor = cursor;
1107 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1109 if (textclasslist.Style(buffer->params.textclass,
1110 par->GetLayout()).labeltype != LABEL_MANUAL)
1113 return par->BeginningOfMainBody();
1117 /* if there is a selection, reset every environment you can find
1118 * in the selection, otherwise just the environment you are in */
1119 void LyXText::MeltFootnoteEnvironment()
1121 LyXParagraph * tmppar, * firsttmppar;
1125 /* is is only allowed, if the cursor is IN an open footnote.
1126 * Otherwise it is too dangerous */
1127 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1130 SetUndo(Undo::FINISH,
1131 cursor.par->PreviousBeforeFootnote()->previous,
1132 cursor.par->NextAfterFootnote()->next);
1134 /* ok, move to the beginning of the footnote. */
1135 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1136 cursor.par = cursor.par->Previous();
1138 SetCursor(cursor.par, cursor.par->Last());
1139 /* this is just faster than using CursorLeft(); */
1141 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1142 tmppar = firsttmppar;
1143 /* tmppar is now the paragraph right before the footnote */
1145 bool first_footnote_par_is_not_empty = tmppar->next->size();
1148 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1149 tmppar = tmppar->next; /* I use next instead of Next(),
1150 * because there cannot be any
1151 * footnotes in a footnote
1153 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1155 /* remember the captions and empty paragraphs */
1156 if ((textclasslist.Style(buffer->params.textclass,
1157 tmppar->GetLayout())
1158 .labeltype == LABEL_SENSITIVE)
1160 tmppar->SetLayout(0);
1163 // now we will paste the ex-footnote, if the layouts allow it
1164 // first restore the layout of the paragraph right behind
1167 tmppar->next->MakeSameLayout(cursor.par);
1170 if ((!tmppar->GetLayout() && !tmppar->table)
1172 && (!tmppar->Next()->Last()
1173 || tmppar->Next()->HasSameLayout(tmppar)))) {
1174 if (tmppar->Next()->Last()
1175 && tmppar->Next()->IsLineSeparator(0))
1176 tmppar->Next()->Erase(0);
1177 tmppar->PasteParagraph();
1180 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1181 * by the pasting of the beginning */
1183 /* then the beginning */
1184 /* if there is no space between the text and the footnote, so we insert
1186 * (only if the previous par and the footnotepar are not empty!) */
1187 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1188 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1189 if (firsttmppar->size()
1190 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1191 && first_footnote_par_is_not_empty) {
1192 firsttmppar->next->InsertChar(0, ' ');
1194 firsttmppar->PasteParagraph();
1197 /* now redo the paragaphs */
1198 RedoParagraphs(cursor, tmppar);
1200 SetCursor(cursor.par, cursor.pos);
1202 /* sometimes it can happen, that there is a counter change */
1203 Row * row = cursor.row;
1204 while (row->next && row->par != tmppar && row->next->par != tmppar)
1206 UpdateCounters(row);
1213 /* the DTP switches for paragraphs. LyX will store them in the
1214 * first physicla paragraph. When a paragraph is broken, the top settings
1215 * rest, the bottom settings are given to the new one. So I can make shure,
1216 * they do not duplicate themself and you cannnot make dirty things with
1219 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1220 bool pagebreak_top, bool pagebreak_bottom,
1221 VSpace const & space_top,
1222 VSpace const & space_bottom,
1224 string labelwidthstring,
1227 LyXCursor tmpcursor = cursor;
1229 sel_start_cursor = cursor;
1230 sel_end_cursor = cursor;
1233 // make sure that the depth behind the selection are restored, too
1234 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1235 LyXParagraph * undoendpar = endpar;
1237 if (endpar && endpar->GetDepth()) {
1238 while (endpar && endpar->GetDepth()) {
1239 endpar = endpar->LastPhysicalPar()->Next();
1240 undoendpar = endpar;
1244 endpar = endpar->Next(); // because of parindents etc.
1249 .par->ParFromPos(sel_start_cursor.pos)->previous,
1253 LyXParagraph * tmppar = sel_end_cursor.par;
1254 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1255 SetCursor(tmppar->FirstPhysicalPar(), 0);
1256 status = LyXText::NEED_MORE_REFRESH;
1257 refresh_row = cursor.row;
1258 refresh_y = cursor.y - cursor.row->baseline;
1259 if (cursor.par->footnoteflag ==
1260 sel_start_cursor.par->footnoteflag) {
1261 cursor.par->line_top = line_top;
1262 cursor.par->line_bottom = line_bottom;
1263 cursor.par->pagebreak_top = pagebreak_top;
1264 cursor.par->pagebreak_bottom = pagebreak_bottom;
1265 cursor.par->added_space_top = space_top;
1266 cursor.par->added_space_bottom = space_bottom;
1267 // does the layout allow the new alignment?
1268 if (align == LYX_ALIGN_LAYOUT)
1269 align = textclasslist
1270 .Style(buffer->params.textclass,
1271 cursor.par->GetLayout()).align;
1272 if (align & textclasslist
1273 .Style(buffer->params.textclass,
1274 cursor.par->GetLayout()).alignpossible) {
1275 if (align == textclasslist
1276 .Style(buffer->params.textclass,
1277 cursor.par->GetLayout()).align)
1278 cursor.par->align = LYX_ALIGN_LAYOUT;
1280 cursor.par->align = align;
1282 cursor.par->SetLabelWidthString(labelwidthstring);
1283 cursor.par->noindent = noindent;
1286 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1289 RedoParagraphs(sel_start_cursor, endpar);
1292 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1293 sel_cursor = cursor;
1294 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1296 SetCursor(tmpcursor.par, tmpcursor.pos);
1300 void LyXText::SetParagraphExtraOpt(int type,
1302 char const * widthp,
1303 int alignment, bool hfill,
1304 bool start_minipage)
1306 LyXCursor tmpcursor = cursor;
1307 LyXParagraph * tmppar;
1309 sel_start_cursor = cursor;
1310 sel_end_cursor = cursor;
1313 // make sure that the depth behind the selection are restored, too
1314 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1315 LyXParagraph * undoendpar = endpar;
1317 if (endpar && endpar->GetDepth()) {
1318 while (endpar && endpar->GetDepth()) {
1319 endpar = endpar->LastPhysicalPar()->Next();
1320 undoendpar = endpar;
1324 endpar = endpar->Next(); // because of parindents etc.
1329 .par->ParFromPos(sel_start_cursor.pos)->previous,
1332 tmppar = sel_end_cursor.par;
1333 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1334 SetCursor(tmppar->FirstPhysicalPar(), 0);
1335 status = LyXText::NEED_MORE_REFRESH;
1336 refresh_row = cursor.row;
1337 refresh_y = cursor.y - cursor.row->baseline;
1338 if (cursor.par->footnoteflag ==
1339 sel_start_cursor.par->footnoteflag) {
1340 if (type == LyXParagraph::PEXTRA_NONE) {
1341 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1342 cursor.par->UnsetPExtraType();
1343 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1346 cursor.par->SetPExtraType(type, width, widthp);
1347 cursor.par->pextra_hfill = hfill;
1348 cursor.par->pextra_start_minipage = start_minipage;
1349 cursor.par->pextra_alignment = alignment;
1352 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1354 RedoParagraphs(sel_start_cursor, endpar);
1356 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1357 sel_cursor = cursor;
1358 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1360 SetCursor(tmpcursor.par, tmpcursor.pos);
1364 char loweralphaCounter(int n)
1366 if (n < 1 || n > 26)
1372 char alphaCounter(int n)
1374 if (n < 1 || n > 26)
1380 char hebrewCounter(int n)
1382 static const char hebrew[22] = {
1383 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1384 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1385 '÷', 'ø', 'ù', 'ú'
1387 if (n < 1 || n > 22)
1393 static char const * romanCounter(int n)
1395 static char const * roman[20] = {
1396 "i", "ii", "iii", "iv", "v",
1397 "vi", "vii", "viii", "ix", "x",
1398 "xi", "xii", "xiii", "xiv", "xv",
1399 "xvi", "xvii", "xviii", "xix", "xx"
1401 if (n < 1 || n > 20)
1407 // set the counter of a paragraph. This includes the labels
1408 void LyXText::SetCounter(LyXParagraph * par) const
1410 // this is only relevant for the beginning of paragraph
1411 par = par->FirstPhysicalPar();
1413 LyXLayout const & layout =
1414 textclasslist.Style(buffer->params.textclass,
1417 LyXTextClass const & textclass =
1418 textclasslist.TextClass(buffer->params.textclass);
1420 /* copy the prev-counters to this one, unless this is the start of a
1421 footnote or of a bibliography or the very first paragraph */
1423 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1424 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1425 && par->footnotekind == LyXParagraph::FOOTNOTE)
1426 && !(textclasslist.Style(buffer->params.textclass,
1427 par->Previous()->GetLayout()
1428 ).labeltype != LABEL_BIBLIO
1429 && layout.labeltype == LABEL_BIBLIO)) {
1430 for (int i = 0; i < 10; ++i) {
1431 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1433 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1434 if (!par->appendix && par->start_of_appendix){
1435 par->appendix = true;
1436 for (int i = 0; i < 10; ++i) {
1437 par->setCounter(i, 0);
1440 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1441 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1444 for (int i = 0; i < 10; ++i) {
1445 par->setCounter(i, 0);
1447 par->appendix = par->start_of_appendix;
1452 // if this is an open marginnote and this is the first
1453 // entry in the marginnote and the enclosing
1454 // environment is an enum/item then correct for the
1455 // LaTeX behaviour (ARRae)
1456 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1457 && par->footnotekind == LyXParagraph::MARGIN
1459 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1460 && (par->PreviousBeforeFootnote()
1461 && textclasslist.Style(buffer->params.textclass,
1462 par->PreviousBeforeFootnote()->GetLayout()
1463 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1464 // Any itemize or enumerate environment in a marginnote
1465 // that is embedded in an itemize or enumerate
1466 // paragraph is seen by LaTeX as being at a deeper
1467 // level within that enclosing itemization/enumeration
1468 // even if there is a "standard" layout at the start of
1474 /* Maybe we have to increment the enumeration depth.
1475 * BUT, enumeration in a footnote is considered in isolation from its
1476 * surrounding paragraph so don't increment if this is the
1477 * first line of the footnote
1478 * AND, bibliographies can't have their depth changed ie. they
1479 * are always of depth 0
1482 && par->Previous()->GetDepth() < par->GetDepth()
1483 && textclasslist.Style(buffer->params.textclass,
1484 par->Previous()->GetLayout()
1485 ).labeltype == LABEL_COUNTER_ENUMI
1486 && par->enumdepth < 3
1487 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1488 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1489 && par->footnotekind == LyXParagraph::FOOTNOTE)
1490 && layout.labeltype != LABEL_BIBLIO) {
1494 /* Maybe we have to decrement the enumeration depth, see note above */
1496 && par->Previous()->GetDepth() > par->GetDepth()
1497 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1498 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1499 && par->footnotekind == LyXParagraph::FOOTNOTE)
1500 && layout.labeltype != LABEL_BIBLIO) {
1501 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1502 par->setCounter(6 + par->enumdepth,
1503 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1504 /* reset the counters.
1505 * A depth change is like a breaking layout
1507 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1508 par->setCounter(i, 0);
1511 if (!par->labelstring.empty()) {
1512 par->labelstring.clear();
1515 if (layout.margintype == MARGIN_MANUAL) {
1516 if (par->labelwidthstring.empty()) {
1517 par->SetLabelWidthString(layout.labelstring());
1520 par->SetLabelWidthString(string());
1523 /* is it a layout that has an automatic label ? */
1524 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1526 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1527 if (i >= 0 && i<= buffer->params.secnumdepth) {
1528 par->incCounter(i); // increment the counter
1530 // Is there a label? Useful for Chapter layout
1531 if (!par->appendix){
1532 if (!layout.labelstring().empty())
1533 par->labelstring = layout.labelstring();
1535 par->labelstring.clear();
1537 if (!layout.labelstring_appendix().empty())
1538 par->labelstring = layout.labelstring_appendix();
1540 par->labelstring.clear();
1544 std::ostringstream s;
1548 if (!par->appendix) {
1549 switch (2 * LABEL_FIRST_COUNTER -
1550 textclass.maxcounter() + i) {
1551 case LABEL_COUNTER_CHAPTER:
1552 s << par->getCounter(i);
1554 case LABEL_COUNTER_SECTION:
1555 s << par->getCounter(i - 1) << '.'
1556 << par->getCounter(i);
1558 case LABEL_COUNTER_SUBSECTION:
1559 s << par->getCounter(i - 2) << '.'
1560 << par->getCounter(i - 1) << '.'
1561 << par->getCounter(i);
1563 case LABEL_COUNTER_SUBSUBSECTION:
1564 s << par->getCounter(i - 3) << '.'
1565 << par->getCounter(i - 2) << '.'
1566 << par->getCounter(i - 1) << '.'
1567 << par->getCounter(i);
1570 case LABEL_COUNTER_PARAGRAPH:
1571 s << par->getCounter(i - 4) << '.'
1572 << par->getCounter(i - 3) << '.'
1573 << par->getCounter(i - 2) << '.'
1574 << par->getCounter(i - 1) << '.'
1575 << par->getCounter(i);
1577 case LABEL_COUNTER_SUBPARAGRAPH:
1578 s << par->getCounter(i - 5) << '.'
1579 << par->getCounter(i - 4) << '.'
1580 << par->getCounter(i - 3) << '.'
1581 << par->getCounter(i - 2) << '.'
1582 << par->getCounter(i - 1) << '.'
1583 << par->getCounter(i);
1587 s << par->getCounter(i) << '.';
1590 } else { // appendix
1591 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1592 case LABEL_COUNTER_CHAPTER:
1593 if (par->isRightToLeftPar())
1594 s << hebrewCounter(par->getCounter(i));
1596 s << alphaCounter(par->getCounter(i));
1598 case LABEL_COUNTER_SECTION:
1599 if (par->isRightToLeftPar())
1600 s << hebrewCounter(par->getCounter(i - 1));
1602 s << alphaCounter(par->getCounter(i - 1));
1605 << par->getCounter(i);
1608 case LABEL_COUNTER_SUBSECTION:
1609 if (par->isRightToLeftPar())
1610 s << hebrewCounter(par->getCounter(i - 2));
1612 s << alphaCounter(par->getCounter(i - 2));
1615 << par->getCounter(i-1) << '.'
1616 << par->getCounter(i);
1619 case LABEL_COUNTER_SUBSUBSECTION:
1620 if (par->isRightToLeftPar())
1621 s << hebrewCounter(par->getCounter(i-3));
1623 s << alphaCounter(par->getCounter(i-3));
1626 << par->getCounter(i-2) << '.'
1627 << par->getCounter(i-1) << '.'
1628 << par->getCounter(i);
1631 case LABEL_COUNTER_PARAGRAPH:
1632 if (par->isRightToLeftPar())
1633 s << hebrewCounter(par->getCounter(i-4));
1635 s << alphaCounter(par->getCounter(i-4));
1638 << par->getCounter(i-3) << '.'
1639 << par->getCounter(i-2) << '.'
1640 << par->getCounter(i-1) << '.'
1641 << par->getCounter(i);
1644 case LABEL_COUNTER_SUBPARAGRAPH:
1645 if (par->isRightToLeftPar())
1646 s << hebrewCounter(par->getCounter(i-5));
1648 s << alphaCounter(par->getCounter(i-5));
1651 << par->getCounter(i-4) << '.'
1652 << par->getCounter(i-3) << '.'
1653 << par->getCounter(i-2) << '.'
1654 << par->getCounter(i-1) << '.'
1655 << par->getCounter(i);
1659 // Can this ever be reached? And in the
1660 // case it is, how can this be correct?
1662 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1668 par->labelstring += s.str().c_str();
1669 // We really want to remove the c_str as soon as
1673 char * tmps = s.str();
1674 par->labelstring += tmps;
1678 for (i++; i < 10; ++i) {
1679 // reset the following counters
1680 par->setCounter(i, 0);
1682 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1683 for (i++; i < 10; ++i) {
1684 // reset the following counters
1685 par->setCounter(i, 0);
1687 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1688 par->incCounter(i + par->enumdepth);
1689 int number = par->getCounter(i + par->enumdepth);
1692 std::ostringstream s;
1696 switch (par->enumdepth) {
1698 if (par->isRightToLeftPar())
1700 << hebrewCounter(number)
1704 << loweralphaCounter(number)
1708 if (par->isRightToLeftPar())
1709 s << '.' << romanCounter(number);
1711 s << romanCounter(number) << '.';
1714 if (par->isRightToLeftPar())
1716 << alphaCounter(number);
1718 s << alphaCounter(number)
1722 if (par->isRightToLeftPar())
1729 par->labelstring = s.str().c_str();
1730 // we really want to get rid of that c_str()
1733 char * tmps = s.str();
1734 par->labelstring = tmps;
1738 for (i += par->enumdepth + 1; i < 10; ++i)
1739 par->setCounter(i, 0); /* reset the following counters */
1742 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1743 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1745 int number = par->getCounter(i);
1747 par->bibkey = new InsetBibKey();
1748 par->bibkey->setCounter(number);
1749 par->labelstring = layout.labelstring();
1751 // In biblio should't be following counters but...
1753 string s = layout.labelstring();
1755 // the caption hack:
1757 if (layout.labeltype == LABEL_SENSITIVE) {
1758 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1759 && (par->footnotekind == LyXParagraph::FIG
1760 || par->footnotekind == LyXParagraph::WIDE_FIG))
1761 s = (par->getParLanguage()->lang == "hebrew")
1762 ? ":øåéà " : "Figure:";
1763 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1764 && (par->footnotekind == LyXParagraph::TAB
1765 || par->footnotekind == LyXParagraph::WIDE_TAB))
1766 s = (par->getParLanguage()->lang == "hebrew")
1767 ? ":äìáè" : "Table:";
1768 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1769 && par->footnotekind == LyXParagraph::ALGORITHM)
1770 s = (par->getParLanguage()->lang == "hebrew")
1771 ? ":Ãúéøåâìà " : "Algorithm:";
1773 /* par->SetLayout(0);
1774 s = layout->labelstring; */
1775 s = (par->getParLanguage()->lang == "hebrew")
1776 ? " :úåòîùî øñç" : "Senseless: ";
1779 par->labelstring = s;
1781 /* reset the enumeration counter. They are always resetted
1782 * when there is any other layout between */
1783 for (int i = 6 + par->enumdepth; i < 10; ++i)
1784 par->setCounter(i, 0);
1789 /* Updates all counters BEHIND the row. Changed paragraphs
1790 * with a dynamic left margin will be rebroken. */
1791 void LyXText::UpdateCounters(Row * row) const
1800 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1801 par = row->par->LastPhysicalPar()->Next();
1803 par = row->par->next;
1808 while (row->par != par)
1813 /* now check for the headline layouts. remember that they
1814 * have a dynamic left margin */
1816 && ( textclasslist.Style(buffer->params.textclass,
1817 par->layout).margintype == MARGIN_DYNAMIC
1818 || textclasslist.Style(buffer->params.textclass,
1819 par->layout).labeltype == LABEL_SENSITIVE)
1822 /* Rebreak the paragraph */
1823 RemoveParagraph(row);
1824 AppendParagraph(row);
1826 /* think about the damned open footnotes! */
1827 while (par->Next() &&
1828 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1829 || par->Next()->IsDummy())){
1831 if (par->IsDummy()) {
1832 while (row->par != par)
1834 RemoveParagraph(row);
1835 AppendParagraph(row);
1840 par = par->LastPhysicalPar()->Next();
1846 /* insets an inset. */
1847 void LyXText::InsertInset(Inset *inset)
1849 if (!cursor.par->InsertInsetAllowed(inset))
1851 SetUndo(Undo::INSERT,
1852 cursor.par->ParFromPos(cursor.pos)->previous,
1853 cursor.par->ParFromPos(cursor.pos)->next);
1854 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1855 cursor.par->InsertInset(cursor.pos, inset);
1856 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1857 * The character will not be inserted a
1862 #ifdef USE_OLD_CUT_AND_PASTE
1863 // this is for the simple cut and paste mechanism
1864 static LyXParagraph * simple_cut_buffer = 0;
1865 static char simple_cut_buffer_textclass = 0;
1867 void DeleteSimpleCutBuffer()
1869 if (!simple_cut_buffer)
1871 LyXParagraph * tmppar;
1873 while (simple_cut_buffer) {
1874 tmppar = simple_cut_buffer;
1875 simple_cut_buffer = simple_cut_buffer->next;
1878 simple_cut_buffer = 0;
1882 void LyXText::copyEnvironmentType()
1884 copylayouttype = cursor.par->GetLayout();
1888 void LyXText::pasteEnvironmentType()
1890 SetLayout(copylayouttype);
1893 #ifdef USE_OLD_CUT_AND_PASTE
1894 void LyXText::CutSelection(bool doclear)
1896 // This doesn't make sense, if there is no selection
1900 // OK, we have a selection. This is always between sel_start_cursor
1901 // and sel_end cursor
1902 LyXParagraph * tmppar;
1904 // Check whether there are half footnotes in the selection
1905 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1906 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1907 tmppar = sel_start_cursor.par;
1908 while (tmppar != sel_end_cursor.par){
1909 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1910 WriteAlert(_("Impossible operation"),
1911 _("Don't know what to do with half floats."),
1915 tmppar = tmppar->Next();
1919 /* table stuff -- begin */
1920 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1921 if ( sel_start_cursor.par != sel_end_cursor.par) {
1922 WriteAlert(_("Impossible operation"),
1923 _("Don't know what to do with half tables."),
1927 sel_start_cursor.par->table->Reinit();
1929 /* table stuff -- end */
1931 // make sure that the depth behind the selection are restored, too
1932 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1933 LyXParagraph * undoendpar = endpar;
1935 if (endpar && endpar->GetDepth()) {
1936 while (endpar && endpar->GetDepth()) {
1937 endpar = endpar->LastPhysicalPar()->Next();
1938 undoendpar = endpar;
1940 } else if (endpar) {
1941 endpar = endpar->Next(); // because of parindents etc.
1944 SetUndo(Undo::DELETE,
1946 .par->ParFromPos(sel_start_cursor.pos)->previous,
1949 // clear the simple_cut_buffer
1950 DeleteSimpleCutBuffer();
1952 // set the textclass
1953 simple_cut_buffer_textclass = buffer->params.textclass;
1955 #ifdef WITH_WARNINGS
1956 #warning Asger: Make cut more intelligent here.
1959 White paper for "intelligent" cutting:
1961 Example: "This is our text."
1962 Using " our " as selection, cutting will give "This istext.".
1963 Using "our" as selection, cutting will give "This is text.".
1964 Using " our" as selection, cutting will give "This is text.".
1965 Using "our " as selection, cutting will give "This is text.".
1967 All those four selections will (however) paste identically:
1968 Pasting with the cursor right after the "is" will give the
1969 original text with all four selections.
1971 The rationale is to be intelligent such that words are copied,
1972 cut and pasted in a functional manner.
1974 This is not implemented yet. (Asger)
1976 The changes below sees to do a lot of what you want. However
1977 I have not verified that all cases work as they should:
1979 - cut in multiple row
1981 - cut across footnotes and paragraph
1982 My simplistic tests show that the idea are basically sound but
1983 there are some items to fix up...we only need to find them
1986 As do redo Asger's example above (with | beeing the cursor in the
1987 result after cutting.):
1989 Example: "This is our text."
1990 Using " our " as selection, cutting will give "This is|text.".
1991 Using "our" as selection, cutting will give "This is | text.".
1992 Using " our" as selection, cutting will give "This is| text.".
1993 Using "our " as selection, cutting will give "This is |text.".
1998 #ifndef FIX_DOUBLE_SPACE
1999 bool space_wrapped =
2000 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
2001 if (sel_end_cursor.pos > 0
2002 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
2003 // please break before a space at the end
2004 sel_end_cursor.pos--;
2005 space_wrapped = true;
2007 // cut behind a space if there is one
2008 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2009 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2010 && (sel_start_cursor.par != sel_end_cursor.par
2011 || sel_start_cursor.pos < sel_end_cursor.pos))
2012 sel_start_cursor.pos++;
2014 // there are two cases: cut only within one paragraph or
2015 // more than one paragraph
2017 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2018 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2019 // only within one paragraph
2020 simple_cut_buffer = new LyXParagraph;
2021 LyXParagraph::size_type i =
2022 sel_start_cursor.pos;
2023 for (; i < sel_end_cursor.pos; ++i) {
2024 /* table stuff -- begin */
2025 if (sel_start_cursor.par->table
2026 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2027 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2028 sel_start_cursor.pos++;
2030 /* table stuff -- end */
2031 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2032 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2034 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2036 #ifndef FIX_DOUBLE_SPACE
2037 // check for double spaces
2038 if (sel_start_cursor.pos &&
2039 sel_start_cursor.par->Last() > sel_start_cursor.pos
2040 && sel_start_cursor.par
2041 ->IsLineSeparator(sel_start_cursor.pos - 1)
2042 && sel_start_cursor.par
2043 ->IsLineSeparator(sel_start_cursor.pos)) {
2044 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2047 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
2050 endpar = sel_end_cursor.par->Next();
2052 // cut more than one paragraph
2055 ->BreakParagraphConservative(sel_end_cursor.pos);
2056 #ifndef FIX_DOUBLE_SPACE
2057 // insert a space at the end if there was one
2060 ->InsertChar(sel_end_cursor.par->Last(), ' ');
2062 sel_end_cursor.par = sel_end_cursor.par->Next();
2063 sel_end_cursor.pos = 0;
2065 cursor = sel_end_cursor;
2067 #ifndef FIX_DOUBLE_SPACE
2068 // please break behind a space, if there is one.
2069 // The space should be copied too
2070 if (sel_start_cursor.par
2071 ->IsLineSeparator(sel_start_cursor.pos))
2072 sel_start_cursor.pos++;
2074 sel_start_cursor.par
2075 ->BreakParagraphConservative(sel_start_cursor.pos);
2076 #ifndef FIX_DOUBLE_SPACE
2077 if (!sel_start_cursor.pos
2078 || sel_start_cursor.par
2079 ->IsLineSeparator(sel_start_cursor.pos - 1)
2080 || sel_start_cursor.par
2081 ->IsNewline(sel_start_cursor.pos - 1)) {
2082 sel_start_cursor.par->Next()->InsertChar(0, ' ');
2085 // store the endparagraph for redoing later
2086 endpar = sel_end_cursor.par->Next(); /* needed because
2091 // store the selection
2092 simple_cut_buffer = sel_start_cursor.par
2093 ->ParFromPos(sel_start_cursor.pos)->next;
2094 simple_cut_buffer->previous = 0;
2095 sel_end_cursor.par->previous->next = 0;
2097 // cut the selection
2098 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2099 = sel_end_cursor.par;
2101 sel_end_cursor.par->previous
2102 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2104 // care about footnotes
2105 if (simple_cut_buffer->footnoteflag) {
2106 LyXParagraph * tmppar = simple_cut_buffer;
2108 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2109 tmppar = tmppar->next;
2113 // the cut selection should begin with standard layout
2114 simple_cut_buffer->Clear();
2116 // paste the paragraphs again, if possible
2118 sel_start_cursor.par->Next()->ClearParagraph();
2119 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2121 !sel_start_cursor.par->Next()->Last())
2122 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2124 #ifndef FIX_DOUBLE_SPACE
2125 // maybe a forgotten blank
2126 if (sel_start_cursor.pos
2127 && sel_start_cursor.par
2128 ->IsLineSeparator(sel_start_cursor.pos)
2129 && sel_start_cursor.par
2130 ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2131 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2136 // sometimes necessary
2138 sel_start_cursor.par->ClearParagraph();
2140 RedoParagraphs(sel_start_cursor, endpar);
2143 cursor = sel_start_cursor;
2144 SetCursor(cursor.par, cursor.pos);
2145 sel_cursor = cursor;
2146 UpdateCounters(cursor.row);
2149 #else ///////////////////////////////////////////////////////////////////
2151 void LyXText::CutSelection(bool doclear)
2153 // This doesn't make sense, if there is no selection
2157 // OK, we have a selection. This is always between sel_start_cursor
2158 // and sel_end cursor
2159 LyXParagraph * tmppar;
2161 // Check whether there are half footnotes in the selection
2162 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2163 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2164 tmppar = sel_start_cursor.par;
2165 while (tmppar != sel_end_cursor.par){
2166 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2167 WriteAlert(_("Impossible operation"),
2168 _("Don't know what to do with half floats."),
2172 tmppar = tmppar->Next();
2176 /* table stuff -- begin */
2177 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2178 if ( sel_start_cursor.par != sel_end_cursor.par) {
2179 WriteAlert(_("Impossible operation"),
2180 _("Don't know what to do with half tables."),
2184 sel_start_cursor.par->table->Reinit();
2186 /* table stuff -- end */
2188 // make sure that the depth behind the selection are restored, too
2189 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2190 LyXParagraph * undoendpar = endpar;
2192 if (endpar && endpar->GetDepth()) {
2193 while (endpar && endpar->GetDepth()) {
2194 endpar = endpar->LastPhysicalPar()->Next();
2195 undoendpar = endpar;
2197 } else if (endpar) {
2198 endpar = endpar->Next(); // because of parindents etc.
2201 SetUndo(Undo::DELETE, sel_start_cursor
2202 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2206 // there are two cases: cut only within one paragraph or
2207 // more than one paragraph
2208 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2209 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2210 // only within one paragraph
2211 endpar = sel_start_cursor.par;
2212 cap.cutSelection(sel_start_cursor.par, &endpar,
2213 sel_start_cursor.pos, sel_end_cursor.pos,
2214 buffer->params.textclass, doclear);
2216 endpar = sel_end_cursor.par;
2218 cap.cutSelection(sel_start_cursor.par, &endpar,
2219 sel_start_cursor.pos, sel_end_cursor.pos,
2220 buffer->params.textclass, doclear);
2221 cursor.par = sel_end_cursor.par = endpar;
2222 cursor.pos = sel_end_cursor.pos;
2224 endpar = sel_end_cursor.par->Next();
2226 // sometimes necessary
2228 sel_start_cursor.par->ClearParagraph();
2230 RedoParagraphs(sel_start_cursor, endpar);
2233 cursor = sel_start_cursor;
2234 SetCursor(cursor.par, cursor.pos);
2235 sel_cursor = cursor;
2236 UpdateCounters(cursor.row);
2240 #ifdef USE_OLD_CUT_AND_PASTE
2241 void LyXText::CopySelection()
2243 // this doesnt make sense, if there is no selection
2247 // ok we have a selection. This is always between sel_start_cursor
2248 // and sel_end cursor
2249 LyXParagraph * tmppar;
2251 /* check wether there are half footnotes in the selection */
2252 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2253 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2254 tmppar = sel_start_cursor.par;
2255 while (tmppar != sel_end_cursor.par) {
2256 if (tmppar->footnoteflag !=
2257 sel_end_cursor.par->footnoteflag) {
2258 WriteAlert(_("Impossible operation"),
2259 _("Don't know what to do"
2260 " with half floats."),
2264 tmppar = tmppar->Next();
2268 /* table stuff -- begin */
2269 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2270 if ( sel_start_cursor.par != sel_end_cursor.par){
2271 WriteAlert(_("Impossible operation"),
2272 _("Don't know what to do with half tables."),
2277 /* table stuff -- end */
2279 // delete the simple_cut_buffer
2280 DeleteSimpleCutBuffer();
2282 // set the textclass
2283 simple_cut_buffer_textclass = buffer->params->textclass;
2285 #ifdef FIX_DOUBLE_SPACE
2286 // copy behind a space if there is one
2287 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2288 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2289 && (sel_start_cursor.par != sel_end_cursor.par
2290 || sel_start_cursor.pos < sel_end_cursor.pos))
2291 sel_start_cursor.pos++;
2293 // there are two cases: copy only within one paragraph
2294 // or more than one paragraph
2295 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2296 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2297 // only within one paragraph
2298 simple_cut_buffer = new LyXParagraph;
2299 LyXParagraph::size_type i = 0;
2300 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2301 sel_start_cursor.par->CopyIntoMinibuffer(i);
2302 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2305 // copy more than one paragraph
2306 // clone the paragraphs within the selection
2308 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2309 simple_cut_buffer = tmppar->Clone();
2310 LyXParagraph *tmppar2 = simple_cut_buffer;
2312 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2314 tmppar = tmppar->next;
2315 tmppar2->next = tmppar->Clone();
2316 tmppar2->next->previous = tmppar2;
2317 tmppar2 = tmppar2->next;
2321 // care about footnotes
2322 if (simple_cut_buffer->footnoteflag) {
2323 tmppar = simple_cut_buffer;
2325 tmppar->footnoteflag =
2326 LyXParagraph::NO_FOOTNOTE;
2327 tmppar = tmppar->next;
2331 // the simple_cut_buffer paragraph is too big
2332 LyXParagraph::size_type tmpi2 =
2333 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2334 for (; tmpi2; --tmpi2)
2335 simple_cut_buffer->Erase(0);
2337 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2339 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2340 while (tmppar2->size() > tmpi2) {
2341 tmppar2->Erase(tmppar2->size() - 1);
2346 #else //////////////////////////////////////////////////////////////////////
2348 void LyXText::CopySelection()
2350 // this doesnt make sense, if there is no selection
2354 // ok we have a selection. This is always between sel_start_cursor
2355 // and sel_end cursor
2356 LyXParagraph * tmppar;
2358 /* check wether there are half footnotes in the selection */
2359 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2360 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2361 tmppar = sel_start_cursor.par;
2362 while (tmppar != sel_end_cursor.par) {
2363 if (tmppar->footnoteflag !=
2364 sel_end_cursor.par->footnoteflag) {
2365 WriteAlert(_("Impossible operation"),
2366 _("Don't know what to do"
2367 " with half floats."),
2371 tmppar = tmppar->Next();
2375 /* table stuff -- begin */
2376 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2377 if ( sel_start_cursor.par != sel_end_cursor.par){
2378 WriteAlert(_("Impossible operation"),
2379 _("Don't know what to do with half tables."),
2384 /* table stuff -- end */
2386 #ifdef FIX_DOUBLE_SPACE
2387 // copy behind a space if there is one
2388 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2389 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2390 && (sel_start_cursor.par != sel_end_cursor.par
2391 || sel_start_cursor.pos < sel_end_cursor.pos))
2392 sel_start_cursor.pos++;
2397 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2398 sel_start_cursor.pos, sel_end_cursor.pos,
2399 buffer->params.textclass);
2403 #ifdef USE_OLD_CUT_AND_PASTE
2404 void LyXText::PasteSelection()
2406 // this does not make sense, if there is nothing to paste
2407 if (!simple_cut_buffer)
2410 LyXParagraph * tmppar;
2411 LyXParagraph * endpar;
2413 LyXCursor tmpcursor;
2415 // be carefull with footnotes in footnotes
2416 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2418 // check whether the cut_buffer includes a footnote
2419 tmppar = simple_cut_buffer;
2421 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2422 tmppar = tmppar->next;
2425 WriteAlert(_("Impossible operation"),
2426 _("Can't paste float into float!"),
2432 /* table stuff -- begin */
2433 if (cursor.par->table) {
2434 if (simple_cut_buffer->next) {
2435 WriteAlert(_("Impossible operation"),
2436 _("Table cell cannot include more than one paragraph!"),
2441 /* table stuff -- end */
2443 SetUndo(Undo::INSERT,
2444 cursor.par->ParFromPos(cursor.pos)->previous,
2445 cursor.par->ParFromPos(cursor.pos)->next);
2449 // There are two cases: cutbuffer only one paragraph or many
2450 if (!simple_cut_buffer->next) {
2451 // only within a paragraph
2453 #ifndef FIX_DOUBLE_SPACE
2454 // please break behind a space, if there is one
2455 while (tmpcursor.par->Last() > tmpcursor.pos
2456 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2459 tmppar = simple_cut_buffer->Clone();
2460 /* table stuff -- begin */
2461 bool table_too_small = false;
2462 if (tmpcursor.par->table) {
2463 while (simple_cut_buffer->size()
2464 && !table_too_small) {
2465 if (simple_cut_buffer->IsNewline(0)){
2466 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2468 simple_cut_buffer->Erase(0);
2469 if (tmpcursor.pos < tmpcursor.par->Last())
2472 table_too_small = true;
2474 #ifdef FIX_DOUBLE_SPACE
2475 // This is an attempt to fix the
2476 // "never insert a space at the
2477 // beginning of a paragraph" problem.
2478 if (tmpcursor.pos == 0
2479 && simple_cut_buffer->IsLineSeparator(0)) {
2480 simple_cut_buffer->Erase(0);
2482 simple_cut_buffer->CutIntoMinibuffer(0);
2483 simple_cut_buffer->Erase(0);
2484 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2488 simple_cut_buffer->CutIntoMinibuffer(0);
2489 simple_cut_buffer->Erase(0);
2490 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2496 /* table stuff -- end */
2497 // Some provisions should be done here for checking
2498 // if we are inserting at the beginning of a
2499 // paragraph. If there are a space at the beginning
2500 // of the text to insert and we are inserting at
2501 // the beginning of the paragraph the space should
2503 while (simple_cut_buffer->size()) {
2504 #ifdef FIX_DOUBLE_SPACE
2505 // This is an attempt to fix the
2506 // "never insert a space at the
2507 // beginning of a paragraph" problem.
2508 if (tmpcursor.pos == 0
2509 && simple_cut_buffer->IsLineSeparator(0)) {
2510 simple_cut_buffer->Erase(0);
2512 simple_cut_buffer->CutIntoMinibuffer(0);
2513 simple_cut_buffer->Erase(0);
2514 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2518 simple_cut_buffer->CutIntoMinibuffer(0);
2519 simple_cut_buffer->Erase(0);
2520 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2525 delete simple_cut_buffer;
2526 simple_cut_buffer = tmppar;
2527 endpar = tmpcursor.par->Next();
2532 // make a copy of the simple cut_buffer
2533 tmppar = simple_cut_buffer;
2534 LyXParagraph * simple_cut_clone = tmppar->Clone();
2535 LyXParagraph * tmppar2 = simple_cut_clone;
2536 if (cursor.par->footnoteflag){
2537 tmppar->footnoteflag = cursor.par->footnoteflag;
2538 tmppar->footnotekind = cursor.par->footnotekind;
2540 while (tmppar->next) {
2541 tmppar = tmppar->next;
2542 tmppar2->next = tmppar->Clone();
2543 tmppar2->next->previous = tmppar2;
2544 tmppar2 = tmppar2->next;
2545 if (cursor.par->footnoteflag){
2546 tmppar->footnoteflag = cursor.par->footnoteflag;
2547 tmppar->footnotekind = cursor.par->footnotekind;
2551 // make sure there is no class difference
2552 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2553 buffer->params->textclass,
2556 // make the simple_cut_buffer exactly the same layout than
2557 // the cursor paragraph
2558 simple_cut_buffer->MakeSameLayout(cursor.par);
2560 // find the end of the buffer
2561 LyXParagraph * lastbuffer = simple_cut_buffer;
2562 while (lastbuffer->Next())
2563 lastbuffer = lastbuffer->Next();
2565 #ifndef FIX_DOUBLE_SPACE
2566 // Please break behind a space, if there is one. The space
2567 // should be copied too.
2568 if (cursor.par->Last() > cursor.pos
2569 && cursor.par->IsLineSeparator(cursor.pos))
2572 bool paste_the_end = false;
2574 // open the paragraph for inserting the simple_cut_buffer
2576 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2577 cursor.par->BreakParagraphConservative(cursor.pos);
2578 paste_the_end = true;
2581 #ifndef FIX_DOUBLE_SPACE
2582 // be careful with double spaces
2583 if ((!cursor.par->Last()
2584 || cursor.par->IsLineSeparator(cursor.pos - 1)
2585 || cursor.par->IsNewline(cursor.pos - 1))
2586 && simple_cut_buffer->text.size()
2587 && simple_cut_buffer->IsLineSeparator(0))
2588 simple_cut_buffer->Erase(0);
2590 // set the end for redoing later
2591 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2594 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2595 cursor.par->ParFromPos(cursor.pos)->next;
2596 cursor.par->ParFromPos(cursor.pos)->next->previous =
2597 lastbuffer->ParFromPos(lastbuffer->Last());
2599 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2600 simple_cut_buffer->previous =
2601 cursor.par->ParFromPos(cursor.pos);
2603 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2604 lastbuffer = cursor.par;
2606 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2608 // store the new cursor position
2609 tmpcursor.par = lastbuffer;
2610 tmpcursor.pos = lastbuffer->Last();
2612 // maybe some pasting
2613 if (lastbuffer->Next() && paste_the_end) {
2614 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2615 #ifndef FIX_DOUBLE_SPACE
2616 // be careful with double spaces
2617 if ((!lastbuffer->Last()
2618 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2619 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2620 && lastbuffer->Next()->Last()
2621 && lastbuffer->Next()->IsLineSeparator(0))
2622 lastbuffer->Next()->Erase(0);
2624 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2626 } else if (!lastbuffer->Next()->Last()) {
2627 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2628 #ifndef FIX_DOUBLE_SPACE
2629 // be careful witth double spaces
2630 if ((!lastbuffer->Last()
2631 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2632 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2633 && lastbuffer->Next()->Last()
2634 && lastbuffer->Next()->IsLineSeparator(0))
2635 lastbuffer->Next()->Erase(0);
2637 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2639 } else if (!lastbuffer->Last()) {
2640 lastbuffer->MakeSameLayout(lastbuffer->next);
2641 #ifndef FIX_DOUBLE_SPACE
2642 // be careful witth double spaces
2643 if ((!lastbuffer->Last()
2644 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2645 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2646 && lastbuffer->Next()->Last()
2647 && lastbuffer->Next()->IsLineSeparator(0))
2648 lastbuffer->Next()->Erase(0);
2650 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2653 lastbuffer->Next()->ClearParagraph();
2656 // restore the simple cut buffer
2657 simple_cut_buffer = simple_cut_clone;
2660 RedoParagraphs(cursor, endpar);
2662 SetCursor(cursor.par, cursor.pos);
2665 sel_cursor = cursor;
2666 SetCursor(tmpcursor.par, tmpcursor.pos);
2668 UpdateCounters(cursor.row);
2671 #else ////////////////////////////////////////////////////////////////////
2673 void LyXText::PasteSelection()
2677 // this does not make sense, if there is nothing to paste
2678 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2681 SetUndo(Undo::INSERT,
2682 cursor.par->ParFromPos(cursor.pos)->previous,
2683 cursor.par->ParFromPos(cursor.pos)->next);
2685 LyXParagraph *endpar;
2686 LyXParagraph *actpar = cursor.par;
2687 int endpos = cursor.pos;
2689 cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2691 RedoParagraphs(cursor, endpar);
2693 SetCursor(cursor.par, cursor.pos);
2696 sel_cursor = cursor;
2697 SetCursor(actpar, endpos);
2699 UpdateCounters(cursor.row);
2703 // returns a pointer to the very first LyXParagraph
2704 LyXParagraph * LyXText::FirstParagraph() const
2706 return buffer->paragraph;
2710 // returns true if the specified string is at the specified position
2711 bool LyXText::IsStringInText(LyXParagraph * par,
2712 LyXParagraph::size_type pos,
2713 char const * str) const
2717 while (pos + i < par->Last() && str[i] &&
2718 str[i] == par->GetChar(pos + i)) {
2728 // sets the selection over the number of characters of string, no check!!
2729 void LyXText::SetSelectionOverString(char const * string)
2731 sel_cursor = cursor;
2732 for (int i = 0; string[i]; ++i)
2738 // simple replacing. The font of the first selected character is used
2739 void LyXText::ReplaceSelectionWithString(char const * str)
2744 if (!selection) { // create a dummy selection
2745 sel_end_cursor = cursor;
2746 sel_start_cursor = cursor;
2749 // Get font setting before we cut
2750 LyXParagraph::size_type pos = sel_end_cursor.pos;
2751 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2753 // Insert the new string
2754 for (int i = 0; str[i]; ++i) {
2755 sel_end_cursor.par->InsertChar(pos, str[i]);
2756 sel_end_cursor.par->SetFont(pos, font);
2760 // Cut the selection
2767 // if the string can be found: return true and set the cursor to
2769 bool LyXText::SearchForward(char const * str) const
2771 LyXParagraph * par = cursor.par;
2772 LyXParagraph::size_type pos = cursor.pos;
2773 while (par && !IsStringInText(par, pos, str)) {
2774 if (pos < par->Last() - 1)
2782 SetCursor(par, pos);
2790 bool LyXText::SearchBackward(char const * string) const
2792 LyXParagraph * par = cursor.par;
2793 int pos = cursor.pos;
2799 // We skip empty paragraphs (Asger)
2801 par = par->Previous();
2803 pos = par->Last() - 1;
2804 } while (par && pos < 0);
2806 } while (par && !IsStringInText(par, pos, string));
2809 SetCursor(par, pos);
2816 // needed to insert the selection
2817 void LyXText::InsertStringA(string const & str)
2819 LyXParagraph * par = cursor.par;
2820 LyXParagraph::size_type pos = cursor.pos;
2821 LyXParagraph::size_type a = 0;
2823 LyXParagraph * endpar = cursor.par->Next();
2828 textclasslist.Style(buffer->params.textclass,
2829 cursor.par->GetLayout()).isEnvironment();
2830 // only to be sure, should not be neccessary
2833 // insert the string, don't insert doublespace
2834 string::size_type i = 0;
2835 while (i < str.length()) {
2836 if (str[i] != '\n') {
2838 && i + 1 < str.length() && str[i + 1] != ' '
2839 && pos && par->GetChar(pos - 1)!= ' ') {
2840 par->InsertChar(pos,' ');
2841 par->SetFont(pos, current_font);
2843 } else if (par->table) {
2844 if (str[i] == '\t') {
2845 while((pos < par->size()) &&
2846 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2848 if (pos < par->size())
2850 else // no more fields to fill skip the rest
2852 } else if ((str[i] != 13) &&
2853 ((str[i] & 127) >= ' ')) {
2854 par->InsertChar(pos, str[i]);
2855 par->SetFont(pos, current_font);
2858 } else if (str[i] == ' ') {
2860 InsetSpecialChar * new_inset =
2861 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2862 if (par->InsertInsetAllowed(new_inset)) {
2863 par->InsertChar(pos, LyXParagraph::META_INSET);
2864 par->SetFont(pos, current_font);
2865 par->InsertInset(pos, new_inset);
2870 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2871 par->SetFont(pos, current_font);
2874 } else if (str[i] == '\t') {
2875 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2877 InsetSpecialChar * new_inset =
2878 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2879 if (par->InsertInsetAllowed(new_inset)) {
2880 par->InsertChar(pos, LyXParagraph::META_INSET);
2881 par->SetFont(pos, current_font);
2882 par->InsertInset(pos, new_inset);
2887 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2888 par->SetFont(a, current_font);
2892 } else if (str[i] != 13 &&
2893 // Ignore unprintables
2894 (str[i] & 127) >= ' ') {
2895 par->InsertChar(pos, str[i]);
2896 par->SetFont(pos, current_font);
2901 if (i + 1 >= str.length()) {
2905 while((pos < par->size()) &&
2906 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2909 cell = NumberOfCell(par, pos);
2910 while((pos < par->size()) &&
2911 !(par->table->IsFirstCell(cell))) {
2913 while((pos < par->size()) &&
2914 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2917 cell = NumberOfCell(par, pos);
2919 if (pos >= par->size())
2920 // no more fields to fill skip the rest
2923 if (!par->size()) { // par is empty
2925 InsetSpecialChar * new_inset =
2926 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2927 if (par->InsertInsetAllowed(new_inset)) {
2928 par->InsertChar(pos, LyXParagraph::META_INSET);
2929 par->SetFont(pos, current_font);
2930 par->InsertInset(pos, new_inset);
2935 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2936 par->SetFont(pos, current_font);
2940 par->BreakParagraph(pos, flag);
2948 RedoParagraphs(cursor, endpar);
2949 SetCursor(cursor.par, cursor.pos);
2950 sel_cursor = cursor;
2951 SetCursor(par, pos);
2956 /* turns double-CR to single CR, others where converted into one blank and 13s
2957 * that are ignored .Double spaces are also converted into one. Spaces at
2958 * the beginning of a paragraph are forbidden. tabs are converted into one
2959 * space. then InsertStringA is called */
2960 void LyXText::InsertStringB(string const & s)
2963 LyXParagraph * par = cursor.par;
2964 string::size_type i = 1;
2965 while (i < str.length()) {
2966 if (str[i] == '\t' && !par->table)
2968 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2970 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2971 if (str[i + 1] != '\n') {
2972 if (str[i - 1] != ' ')
2977 while (i + 1 < str.length()
2978 && (str[i + 1] == ' '
2979 || str[i + 1] == '\t'
2980 || str[i + 1] == '\n'
2981 || str[i + 1] == 13)) {
2992 bool LyXText::GotoNextError() const
2994 LyXCursor res = cursor;
2996 if (res.pos < res.par->Last() - 1) {
3000 res.par = res.par->Next();
3005 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3006 && res.par->GetInset(res.pos)->AutoDelete()));
3009 SetCursor(res.par, res.pos);
3016 bool LyXText::GotoNextNote() const
3018 LyXCursor res = cursor;
3020 if (res.pos < res.par->Last() - 1) {
3023 res.par = res.par->Next();
3028 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3029 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
3032 SetCursor(res.par, res.pos);
3039 void LyXText::CheckParagraph(LyXParagraph * par,
3040 LyXParagraph::size_type pos)
3043 LyXCursor tmpcursor;
3045 /* table stuff -- begin*/
3048 CheckParagraphInTable(par, pos);
3051 /* table stuff -- end*/
3054 LyXParagraph::size_type z;
3055 Row * row = GetRow(par, pos, y);
3057 // is there a break one row above
3058 if (row->previous && row->previous->par == row->par) {
3059 z = NextBreakPoint(row->previous, paperwidth);
3060 if ( z >= row->pos) {
3061 // set the dimensions of the row above
3062 y -= row->previous->height;
3064 refresh_row = row->previous;
3065 status = LyXText::NEED_MORE_REFRESH;
3067 BreakAgain(row->previous);
3069 // set the cursor again. Otherwise
3070 // dangling pointers are possible
3071 SetCursor(cursor.par, cursor.pos);
3072 sel_cursor = cursor;
3077 int tmpheight = row->height;
3078 LyXParagraph::size_type tmplast = RowLast(row);
3083 if (row->height == tmpheight && RowLast(row) == tmplast)
3084 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3086 status = LyXText::NEED_MORE_REFRESH;
3088 // check the special right address boxes
3089 if (textclasslist.Style(buffer->params.textclass,
3090 par->GetLayout()).margintype
3091 == MARGIN_RIGHT_ADDRESS_BOX) {
3092 tmpcursor.par = par;
3093 tmpcursor.row = row;
3096 tmpcursor.x_fix = 0;
3097 tmpcursor.pos = pos;
3098 RedoDrawingOfParagraph(tmpcursor);
3103 // set the cursor again. Otherwise dangling pointers are possible
3104 // also set the selection
3108 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3109 sel_cursor = cursor;
3110 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3111 sel_start_cursor = cursor;
3112 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3113 sel_end_cursor = cursor;
3114 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3115 last_sel_cursor = cursor;
3118 SetCursorIntern(cursor.par, cursor.pos);
3122 // returns 0 if inset wasn't found
3123 int LyXText::UpdateInset(Inset * inset)
3125 // first check the current paragraph
3126 int pos = cursor.par->GetPositionOfInset(inset);
3128 CheckParagraph(cursor.par, pos);
3132 // check every paragraph
3134 LyXParagraph * par = FirstParagraph();
3136 // make sure the paragraph is open
3137 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3138 pos = par->GetPositionOfInset(inset);
3140 CheckParagraph(par, pos);
3151 void LyXText::SetCursor(LyXParagraph * par,
3152 LyXParagraph::size_type pos, bool setfont) const
3154 LyXCursor old_cursor = cursor;
3155 SetCursorIntern(par, pos, setfont);
3156 DeleteEmptyParagraphMechanism(old_cursor);
3160 void LyXText::SetCursorIntern(LyXParagraph * par,
3161 LyXParagraph::size_type pos, bool setfont) const
3163 // correct the cursor position if impossible
3164 if (pos > par->Last()){
3165 LyXParagraph * tmppar = par->ParFromPos(pos);
3166 pos = par->PositionInParFromPos(pos);
3169 if (par->IsDummy() && par->previous &&
3170 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3171 while (par->previous &&
3172 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3173 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3174 par = par->previous ;
3175 if (par->IsDummy() &&
3176 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3177 pos += par->size() + 1;
3179 if (par->previous) {
3180 par = par->previous;
3182 pos += par->size() + 1;
3190 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3191 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3193 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3194 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3196 current_font = cursor.par->GetFontSettings(cursor.pos);
3197 real_current_font = GetFont(cursor.par, cursor.pos);
3200 /* get the cursor y position in text */
3202 Row * row = GetRow(par, pos, y);
3203 /* y is now the beginning of the cursor row */
3205 /* y is now the cursor baseline */
3208 /* now get the cursors x position */
3210 float fill_separator, fill_hfill, fill_label_hfill;
3211 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3212 LyXParagraph::size_type cursor_vpos;
3213 LyXParagraph::size_type last = RowLastPrintable(row);
3215 if (pos > last + 1) // This shouldn't happen.
3218 if (last < row->pos)
3220 else if (pos > last ||
3221 (pos - 1 >= row->pos &&
3222 (row->par->IsSeparator(pos) ||
3223 (row->par->table && row->par->IsNewline(pos))
3225 /// Place cursor after char at (logical) position pos-1
3226 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3227 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3229 /// Place cursor before char at (logical) position pos
3230 cursor_vpos = (bidi_level(pos) % 2 == 0)
3231 ? log2vis(pos) : log2vis(pos) + 1;
3233 /* table stuff -- begin*/
3234 if (row->par->table) {
3235 int cell = NumberOfCell(row->par, row->pos);
3237 x += row->par->table->GetBeginningOfTextInCell(cell);
3238 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3239 pos = vis2log(vpos);
3240 if (row->par->IsNewline(pos)) {
3241 x = x_old + row->par->table->WidthOfColumn(cell);
3244 x += row->par->table->GetBeginningOfTextInCell(cell);
3246 x += SingleWidth(row->par, pos);
3250 /* table stuff -- end*/
3251 LyXParagraph::size_type main_body =
3252 BeginningOfMainBody(row->par);
3253 if (main_body > 0 &&
3254 (main_body-1 > last ||
3255 !row->par->IsLineSeparator(main_body-1)))
3258 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3259 pos = vis2log(vpos);
3260 if (main_body > 0 && pos == main_body-1) {
3261 x += fill_label_hfill +
3262 lyxfont::width(textclasslist
3263 .Style(buffer->params.textclass,
3264 row->par->GetLayout())
3266 GetFont(row->par, -2));
3267 if (row->par->IsLineSeparator(main_body-1))
3268 x -= SingleWidth(row->par, main_body-1);
3270 if (HfillExpansion(row, pos)) {
3271 x += SingleWidth(row->par, pos);
3272 if (pos >= main_body)
3275 x += fill_label_hfill;
3277 else if (row->par->IsSeparator(pos)) {
3278 x += SingleWidth(row->par, pos);
3279 if (pos >= main_body)
3280 x += fill_separator;
3282 x += SingleWidth(row->par, pos);
3288 cursor.x_fix = cursor.x;
3293 void LyXText::SetCursorFromCoordinates(int x, long y) const
3295 LyXCursor old_cursor = cursor;
3297 /* get the row first */
3299 Row * row = GetRowNearY(y);
3301 cursor.par = row->par;
3303 int column = GetColumnNearX(row, x);
3304 cursor.pos = row->pos + column;
3306 cursor.y = y + row->baseline;
3311 (cursor.pos == cursor.par->Last()
3312 || cursor.par->IsSeparator(cursor.pos)
3313 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3314 && !cursor.par->IsSeparator(cursor.pos))
3315 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3317 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3318 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3320 current_font = cursor.par->GetFontSettings(cursor.pos);
3321 real_current_font = GetFont(cursor.par, cursor.pos);
3323 DeleteEmptyParagraphMechanism(old_cursor);
3326 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3328 /* get the row first */
3330 Row * row = GetRowNearY(y);
3331 int column = GetColumnNearX(row, x);
3334 cur.pos = row->pos + column;
3336 cur.y = y + row->baseline;
3341 void LyXText::CursorLeft() const
3344 if (cursor.par->table) {
3345 int cell = NumberOfCell(cursor.par, cursor.pos);
3346 if (cursor.par->table->IsContRow(cell) &&
3347 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3354 void LyXText::CursorLeftIntern() const
3356 if (cursor.pos > 0) {
3357 SetCursor(cursor.par, cursor.pos - 1);
3359 else if (cursor.par->Previous()) { // steps into the above paragraph.
3360 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3365 void LyXText::CursorRight() const
3367 CursorRightIntern();
3368 if (cursor.par->table) {
3369 int cell = NumberOfCell(cursor.par, cursor.pos);
3370 if (cursor.par->table->IsContRow(cell) &&
3371 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3378 void LyXText::CursorRightIntern() const
3380 if (cursor.pos < cursor.par->Last()) {
3381 SetCursor(cursor.par, cursor.pos + 1);
3383 else if (cursor.par->Next()) {
3384 SetCursor(cursor.par->Next(), 0);
3389 void LyXText::CursorUp() const
3391 SetCursorFromCoordinates(cursor.x_fix,
3392 cursor.y - cursor.row->baseline - 1);
3393 if (cursor.par->table) {
3394 int cell = NumberOfCell(cursor.par, cursor.pos);
3395 if (cursor.par->table->IsContRow(cell) &&
3396 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3403 void LyXText::CursorDown() const
3405 if (cursor.par->table &&
3406 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3409 SetCursorFromCoordinates(cursor.x_fix,
3410 cursor.y - cursor.row->baseline
3411 + cursor.row->height + 1);
3412 if (cursor.par->table) {
3413 int cell = NumberOfCell(cursor.par, cursor.pos);
3414 int cell_above = cursor.par->table->GetCellAbove(cell);
3415 while(cursor.par->table &&
3416 cursor.par->table->IsContRow(cell) &&
3417 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3418 SetCursorFromCoordinates(cursor.x_fix,
3419 cursor.y - cursor.row->baseline
3420 + cursor.row->height + 1);
3421 if (cursor.par->table) {
3422 cell = NumberOfCell(cursor.par, cursor.pos);
3423 cell_above = cursor.par->table->GetCellAbove(cell);
3430 void LyXText::CursorUpParagraph() const
3432 if (cursor.pos > 0) {
3433 SetCursor(cursor.par, 0);
3435 else if (cursor.par->Previous()) {
3436 SetCursor(cursor.par->Previous(), 0);
3441 void LyXText::CursorDownParagraph() const
3443 if (cursor.par->Next()) {
3444 SetCursor(cursor.par->Next(), 0);
3446 SetCursor(cursor.par, cursor.par->Last());
3452 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3454 // Would be wrong to delete anything if we have a selection.
3455 if (selection) return;
3457 // We allow all kinds of "mumbo-jumbo" when freespacing.
3458 if (textclasslist.Style(buffer->params.textclass,
3459 old_cursor.par->GetLayout()).free_spacing)
3462 bool deleted = false;
3464 #ifdef FIX_DOUBLE_SPACE
3465 /* Ok I'll put some comments here about what is missing.
3466 I have fixed BackSpace (and thus Delete) to not delete
3467 double-spaces automagically. I have also changed Cut,
3468 Copy and Paste to hopefully do some sensible things.
3469 There are still some small problems that can lead to
3470 double spaces stored in the document file or space at
3471 the beginning of paragraphs. This happens if you have
3472 the cursor betwenn to spaces and then save. Or if you
3473 cut and paste and the selection have a space at the
3474 beginning and then save right after the paste. I am
3475 sure none of these are very hard to fix, but I will
3476 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3477 that I can get some feedback. (Lgb)
3480 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3481 // delete the LineSeparator.
3484 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3485 // delete the LineSeparator.
3488 // If the pos around the old_cursor were spaces, delete one of them.
3489 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3491 if (old_cursor.pos > 0
3492 && old_cursor.pos < old_cursor.par->Last()
3493 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3494 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3495 old_cursor.par->Erase(old_cursor.pos - 1);
3496 RedoParagraphs(old_cursor, old_cursor.par->Next());
3498 if (old_cursor.par == cursor.par &&
3499 cursor.pos > old_cursor.pos) {
3500 SetCursorIntern(cursor.par, cursor.pos - 1);
3502 SetCursorIntern(cursor.par, cursor.pos);
3508 // Do not delete empty paragraphs with keepempty set.
3509 if ((textclasslist.Style(buffer->params.textclass,
3510 old_cursor.par->GetLayout())).keepempty)
3513 LyXCursor tmpcursor;
3515 if (old_cursor.par != cursor.par) {
3516 if ( (old_cursor.par->Last() == 0
3517 || (old_cursor.par->Last() == 1
3518 && old_cursor.par->IsLineSeparator(0)))
3519 && old_cursor.par->FirstPhysicalPar()
3520 == old_cursor.par->LastPhysicalPar()) {
3521 // ok, we will delete anything
3523 // make sure that you do not delete any environments
3524 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3525 !(old_cursor.row->previous
3526 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3527 && !(old_cursor.row->next
3528 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3529 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3530 && ((old_cursor.row->previous
3531 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3532 || (old_cursor.row->next
3533 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3535 status = LyXText::NEED_MORE_REFRESH;
3538 if (old_cursor.row->previous) {
3539 refresh_row = old_cursor.row->previous;
3540 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3542 cursor = old_cursor; // that undo can restore the right cursor position
3543 LyXParagraph * endpar = old_cursor.par->next;
3544 if (endpar && endpar->GetDepth()) {
3545 while (endpar && endpar->GetDepth()) {
3546 endpar = endpar->LastPhysicalPar()->Next();
3549 SetUndo(Undo::DELETE,
3550 old_cursor.par->previous,
3555 RemoveRow(old_cursor.row);
3556 if (buffer->paragraph == old_cursor.par) {
3557 buffer->paragraph = buffer->paragraph->next;
3560 delete old_cursor.par;
3562 /* Breakagain the next par. Needed
3563 * because of the parindent that
3564 * can occur or dissappear. The
3565 * next row can change its height,
3566 * if there is another layout before */
3567 if (refresh_row->next) {
3568 BreakAgain(refresh_row->next);
3569 UpdateCounters(refresh_row);
3571 SetHeightOfRow(refresh_row);
3573 refresh_row = old_cursor.row->next;
3574 refresh_y = old_cursor.y - old_cursor.row->baseline;
3577 cursor = old_cursor; // that undo can restore the right cursor position
3578 LyXParagraph *endpar = old_cursor.par->next;
3579 if (endpar && endpar->GetDepth()) {
3580 while (endpar && endpar->GetDepth()) {
3581 endpar = endpar->LastPhysicalPar()->Next();
3584 SetUndo(Undo::DELETE,
3585 old_cursor.par->previous,
3590 RemoveRow(old_cursor.row);
3592 if (buffer->paragraph == old_cursor.par) {
3593 buffer->paragraph = buffer->paragraph->next;
3595 delete old_cursor.par;
3597 /* Breakagain the next par. Needed
3598 because of the parindent that can
3599 occur or dissappear.
3600 The next row can change its height,
3601 if there is another layout before
3604 BreakAgain(refresh_row);
3605 UpdateCounters(refresh_row->previous);
3611 SetCursorIntern(cursor.par, cursor.pos);
3613 SetCursor(cursor.par, cursor.pos);
3615 /* if (cursor.y > old_cursor.y)
3616 cursor.y -= old_cursor.row->height; */
3618 if (sel_cursor.par == old_cursor.par
3619 && sel_cursor.pos == sel_cursor.pos) {
3620 // correct selection
3621 sel_cursor = cursor;
3626 if (old_cursor.par->ClearParagraph()) {
3627 RedoParagraphs(old_cursor, old_cursor.par->Next());
3630 SetCursorIntern(cursor.par, cursor.pos);
3632 SetCursor(cursor.par, cursor.pos);
3634 sel_cursor = cursor;
3642 LyXParagraph * LyXText::GetParFromID(int id)
3644 LyXParagraph * result = FirstParagraph();
3645 while (result && result->id() != id)
3646 result = result->next;
3652 bool LyXText::TextUndo()
3654 // returns false if no undo possible
3655 Undo * undo = buffer->undostack.pop();
3660 .push(CreateUndo(undo->kind,
3661 GetParFromID(undo->number_of_before_par),
3662 GetParFromID(undo->number_of_behind_par)));
3664 return TextHandleUndo(undo);
3668 bool LyXText::TextRedo()
3670 // returns false if no redo possible
3671 Undo * undo = buffer->redostack.pop();
3676 .push(CreateUndo(undo->kind,
3677 GetParFromID(undo->number_of_before_par),
3678 GetParFromID(undo->number_of_behind_par)));
3680 return TextHandleUndo(undo);
3684 bool LyXText::TextHandleUndo(Undo * undo)
3686 // returns false if no undo possible
3687 bool result = false;
3689 LyXParagraph * before =
3690 GetParFromID(undo->number_of_before_par);
3691 LyXParagraph * behind =
3692 GetParFromID(undo->number_of_behind_par);
3693 LyXParagraph * tmppar;
3694 LyXParagraph * tmppar2;
3695 LyXParagraph * endpar;
3696 LyXParagraph * tmppar5;
3698 // if there's no before take the beginning
3699 // of the document for redoing
3701 SetCursorIntern(FirstParagraph(), 0);
3703 // replace the paragraphs with the undo informations
3705 LyXParagraph * tmppar3 = undo->par;
3706 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3707 LyXParagraph * tmppar4 = tmppar3;
3709 while (tmppar4->next)
3710 tmppar4 = tmppar4->next;
3711 } // get last undo par
3713 // now remove the old text if there is any
3714 if (before != behind || (!behind && !before)){
3716 tmppar5 = before->next;
3718 tmppar5 = buffer->paragraph;
3720 while (tmppar5 && tmppar5 != behind){
3722 tmppar5 = tmppar5->next;
3723 // a memory optimization for edit: Only layout information
3724 // is stored in the undo. So restore the text informations.
3725 if (undo->kind == Undo::EDIT) {
3726 tmppar2->setContentsFromPar(tmppar);
3727 tmppar->clearContents();
3728 //tmppar2->text = tmppar->text;
3729 //tmppar->text.clear();
3730 tmppar2 = tmppar2->next;
3732 if ( currentrow && currentrow->par == tmppar )
3733 currentrow = currentrow -> previous;
3734 // Commenting out this might remove the error
3735 // reported by Purify, but it might also
3736 // introduce a memory leak. We need to
3742 // put the new stuff in the list if there is one
3745 before->next = tmppar3;
3747 buffer->paragraph = tmppar3;
3748 tmppar3->previous = before;
3752 buffer->paragraph = behind;
3755 tmppar4->next = behind;
3757 behind->previous = tmppar4;
3761 // Set the cursor for redoing
3763 SetCursorIntern(before->FirstSelfrowPar(), 0);
3764 // check wether before points to a closed float and open it if necessary
3765 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3766 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3768 while (tmppar4->previous &&
3769 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3770 tmppar4 = tmppar4->previous;
3771 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3772 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3773 tmppar4 = tmppar4->next;
3778 // open a cosed footnote at the end if necessary
3779 if (behind && behind->previous &&
3780 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3781 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3782 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3783 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3784 behind = behind->next;
3788 // calculate the endpar for redoing the paragraphs.
3790 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3791 endpar = behind->LastPhysicalPar()->Next();
3793 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3798 tmppar = GetParFromID(undo->number_of_cursor_par);
3799 RedoParagraphs(cursor, endpar);
3801 SetCursorIntern(tmppar, undo->cursor_pos);
3802 UpdateCounters(cursor.row);
3812 void LyXText::FinishUndo()
3814 // makes sure the next operation will be stored
3815 undo_finished = True;
3819 void LyXText::FreezeUndo()
3821 // this is dangerous and for internal use only
3826 void LyXText::UnFreezeUndo()
3828 // this is dangerous and for internal use only
3829 undo_frozen = false;
3833 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3834 LyXParagraph const * behind) const
3837 buffer->undostack.push(CreateUndo(kind, before, behind));
3838 buffer->redostack.clear();
3842 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3843 LyXParagraph const * behind)
3845 buffer->redostack.push(CreateUndo(kind, before, behind));
3849 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3850 LyXParagraph const * behind) const
3852 int before_number = -1;
3853 int behind_number = -1;
3855 before_number = before->id();
3857 behind_number = behind->id();
3858 // Undo::EDIT and Undo::FINISH are
3859 // always finished. (no overlapping there)
3860 // overlapping only with insert and delete inside one paragraph:
3861 // Nobody wants all removed character
3862 // appear one by one when undoing.
3863 // EDIT is special since only layout information, not the
3864 // contents of a paragaph are stored.
3865 if (!undo_finished && kind != Undo::EDIT &&
3866 kind != Undo::FINISH){
3867 // check wether storing is needed
3868 if (!buffer->undostack.empty() &&
3869 buffer->undostack.top()->kind == kind &&
3870 buffer->undostack.top()->number_of_before_par == before_number &&
3871 buffer->undostack.top()->number_of_behind_par == behind_number ){
3876 // create a new Undo
3877 LyXParagraph * undopar;
3878 LyXParagraph * tmppar;
3879 LyXParagraph * tmppar2;
3881 LyXParagraph * start = 0;
3882 LyXParagraph * end = 0;
3885 start = before->next;
3887 start = FirstParagraph();
3889 end = behind->previous;
3891 end = FirstParagraph();
3897 && start != end->next
3898 && (before != behind || (!before && !behind))) {
3900 tmppar2 = tmppar->Clone();
3901 tmppar2->id(tmppar->id());
3903 // a memory optimization: Just store the layout information
3905 if (kind == Undo::EDIT){
3906 //tmppar2->text.clear();
3907 tmppar2->clearContents();
3912 while (tmppar != end && tmppar->next) {
3913 tmppar = tmppar->next;
3914 tmppar2->next = tmppar->Clone();
3915 tmppar2->next->id(tmppar->id());
3916 // a memory optimization: Just store the layout
3917 // information when only edit
3918 if (kind == Undo::EDIT){
3919 //tmppar2->next->text.clear();
3920 tmppar2->clearContents();
3922 tmppar2->next->previous = tmppar2;
3923 tmppar2 = tmppar2->next;
3927 undopar = 0; // nothing to replace (undo of delete maybe)
3929 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3930 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3932 Undo * undo = new Undo(kind,
3933 before_number, behind_number,
3934 cursor_par, cursor_pos,
3937 undo_finished = false;
3942 void LyXText::SetCursorParUndo()
3944 SetUndo(Undo::FINISH,
3945 cursor.par->ParFromPos(cursor.pos)->previous,
3946 cursor.par->ParFromPos(cursor.pos)->next);
3950 void LyXText::RemoveTableRow(LyXCursor * cur) const
3956 // move to the previous row
3957 int cell_act = NumberOfCell(cur->par, cur->pos);
3960 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3963 !cur->par->table->IsFirstCell(cell_act)) {
3965 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3970 // now we have to pay attention if the actual table is the
3971 // main row of TableContRows and if yes to delete all of them
3976 // delete up to the next row
3977 while (cur->pos < cur->par->Last() &&
3979 || !cur->par->table->IsFirstCell(cell_act))) {
3980 while (cur->pos < cur->par->Last() &&
3981 !cur->par->IsNewline(cur->pos))
3982 cur->par->Erase(cur->pos);
3985 if (cur->pos < cur->par->Last())
3986 cur->par->Erase(cur->pos);
3988 if (cur->pos && cur->pos == cur->par->Last()) {
3990 cur->par->Erase(cur->pos); // no newline at very end!
3992 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3993 !cur->par->table->IsContRow(cell_org) &&
3994 cur->par->table->IsContRow(cell));
3995 cur->par->table->DeleteRow(cell_org);
4000 bool LyXText::IsEmptyTableCell() const
4002 LyXParagraph::size_type pos = cursor.pos - 1;
4003 while (pos >= 0 && pos < cursor.par->Last()
4004 && !cursor.par->IsNewline(pos))
4006 return cursor.par->IsNewline(pos + 1);
4010 void LyXText::toggleAppendix(){
4011 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4012 bool start = !par->start_of_appendix;
4014 // ensure that we have only one start_of_appendix in this document
4015 LyXParagraph * tmp = FirstParagraph();
4016 for (; tmp; tmp = tmp->next)
4017 tmp->start_of_appendix = 0;
4018 par->start_of_appendix = start;
4020 // we can set the refreshing parameters now
4021 status = LyXText::NEED_MORE_REFRESH;
4023 refresh_row = 0; // not needed for full update
4025 SetCursor(cursor.par, cursor.pos);