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);
3159 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3160 LyXParagraph::size_type pos) const
3162 // correct the cursor position if impossible
3163 if (pos > par->Last()){
3164 LyXParagraph * tmppar = par->ParFromPos(pos);
3165 pos = par->PositionInParFromPos(pos);
3168 if (par->IsDummy() && par->previous &&
3169 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3170 while (par->previous &&
3171 ((par->previous->IsDummy() &&
3172 (par->previous->previous->footnoteflag ==
3173 LyXParagraph::CLOSED_FOOTNOTE)) ||
3174 (par->previous->footnoteflag ==
3175 LyXParagraph::CLOSED_FOOTNOTE))) {
3176 par = par->previous ;
3177 if (par->IsDummy() &&
3178 (par->previous->footnoteflag ==
3179 LyXParagraph::CLOSED_FOOTNOTE))
3180 pos += par->size() + 1;
3182 if (par->previous) {
3183 par = par->previous;
3185 pos += par->size() + 1;
3191 /* get the cursor y position in text */
3193 Row * row = GetRow(par, pos, y);
3194 /* y is now the beginning of the cursor row */
3196 /* y is now the cursor baseline */
3199 /* now get the cursors x position */
3201 float fill_separator, fill_hfill, fill_label_hfill;
3202 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3203 LyXParagraph::size_type cursor_vpos;
3204 LyXParagraph::size_type last = RowLastPrintable(row);
3206 if (pos > last + 1) // This shouldn't happen.
3209 if (last < row->pos)
3211 else if ((pos > last) ||
3212 ((pos - 1 >= row->pos) &&
3213 (row->par->IsSeparator(pos) ||
3214 (row->par->table && row->par->IsNewline(pos)))))
3215 /// Place cursor after char at (logical) position pos-1
3216 cursor_vpos = !(bidi_level(pos-1) % 2)
3217 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3219 /// Place cursor before char at (logical) position pos
3220 cursor_vpos = !(bidi_level(pos) % 2)
3221 ? log2vis(pos) : log2vis(pos) + 1;
3223 /* table stuff -- begin*/
3224 if (row->par->table) {
3225 int cell = NumberOfCell(row->par, row->pos);
3227 x += row->par->table->GetBeginningOfTextInCell(cell);
3228 for (LyXParagraph::size_type vpos = row->pos;
3229 vpos < cursor_vpos; ++vpos) {
3230 pos = vis2log(vpos);
3231 if (row->par->IsNewline(pos)) {
3232 x = x_old + row->par->table->WidthOfColumn(cell);
3235 x += row->par->table->GetBeginningOfTextInCell(cell);
3237 x += SingleWidth(row->par, pos);
3241 /* table stuff -- end*/
3242 LyXParagraph::size_type main_body =
3243 BeginningOfMainBody(row->par);
3244 if ((main_body > 0) &&
3245 ((main_body-1 > last) ||
3246 !row->par->IsLineSeparator(main_body-1)))
3249 for (LyXParagraph::size_type vpos = row->pos;
3250 vpos < cursor_vpos; ++vpos) {
3251 pos = vis2log(vpos);
3252 if (main_body > 0 && pos == main_body-1) {
3253 x += fill_label_hfill +
3254 lyxfont::width(textclasslist.Style(
3255 buffer->params.textclass,
3256 row->par->GetLayout())
3258 GetFont(row->par, -2));
3259 if (row->par->IsLineSeparator(main_body-1))
3260 x -= SingleWidth(row->par,main_body-1);
3262 if (HfillExpansion(row, pos)) {
3263 x += SingleWidth(row->par, pos);
3264 if (pos >= main_body)
3267 x += fill_label_hfill;
3268 } else if (row->par->IsSeparator(pos)) {
3269 x += SingleWidth(row->par, pos);
3270 if (pos >= main_body)
3271 x += fill_separator;
3273 x += SingleWidth(row->par, pos);
3283 void LyXText::SetCursorIntern(LyXParagraph * par,
3284 LyXParagraph::size_type pos, bool setfont) const
3286 SetCursor(cursor, par, pos);
3287 #warning Remove this when verified working (Jug 20000413)
3289 // correct the cursor position if impossible
3290 if (pos > par->Last()){
3291 LyXParagraph * tmppar = par->ParFromPos(pos);
3292 pos = par->PositionInParFromPos(pos);
3295 if (par->IsDummy() && par->previous &&
3296 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3297 while (par->previous &&
3298 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3299 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3300 par = par->previous ;
3301 if (par->IsDummy() &&
3302 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3303 pos += par->size() + 1;
3305 if (par->previous) {
3306 par = par->previous;
3308 pos += par->size() + 1;
3314 /* get the cursor y position in text */
3316 Row * row = GetRow(par, pos, y);
3317 /* y is now the beginning of the cursor row */
3319 /* y is now the cursor baseline */
3322 /* now get the cursors x position */
3324 float fill_separator, fill_hfill, fill_label_hfill;
3325 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3326 LyXParagraph::size_type cursor_vpos;
3327 LyXParagraph::size_type last = RowLastPrintable(row);
3329 if (pos > last + 1) // This shouldn't happen.
3332 if (last < row->pos)
3334 else if (pos > last ||
3335 (pos - 1 >= row->pos &&
3336 (row->par->IsSeparator(pos) ||
3337 (row->par->table && row->par->IsNewline(pos))
3339 /// Place cursor after char at (logical) position pos-1
3340 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3341 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3343 /// Place cursor before char at (logical) position pos
3344 cursor_vpos = (bidi_level(pos) % 2 == 0)
3345 ? log2vis(pos) : log2vis(pos) + 1;
3347 /* table stuff -- begin*/
3348 if (row->par->table) {
3349 int cell = NumberOfCell(row->par, row->pos);
3351 x += row->par->table->GetBeginningOfTextInCell(cell);
3352 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3353 pos = vis2log(vpos);
3354 if (row->par->IsNewline(pos)) {
3355 x = x_old + row->par->table->WidthOfColumn(cell);
3358 x += row->par->table->GetBeginningOfTextInCell(cell);
3360 x += SingleWidth(row->par, pos);
3364 /* table stuff -- end*/
3365 LyXParagraph::size_type main_body =
3366 BeginningOfMainBody(row->par);
3367 if (main_body > 0 &&
3368 (main_body-1 > last ||
3369 !row->par->IsLineSeparator(main_body-1)))
3372 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3373 pos = vis2log(vpos);
3374 if (main_body > 0 && pos == main_body-1) {
3375 x += fill_label_hfill +
3376 lyxfont::width(textclasslist
3377 .Style(buffer->params.textclass,
3378 row->par->GetLayout())
3380 GetFont(row->par, -2));
3381 if (row->par->IsLineSeparator(main_body-1))
3382 x -= SingleWidth(row->par, main_body-1);
3384 if (HfillExpansion(row, pos)) {
3385 x += SingleWidth(row->par, pos);
3386 if (pos >= main_body)
3389 x += fill_label_hfill;
3391 else if (row->par->IsSeparator(pos)) {
3392 x += SingleWidth(row->par, pos);
3393 if (pos >= main_body)
3394 x += fill_separator;
3396 x += SingleWidth(row->par, pos);
3402 cursor.x_fix = cursor.x;
3407 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3408 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3410 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3411 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3413 current_font = cursor.par->GetFontSettings(cursor.pos);
3414 real_current_font = GetFont(cursor.par, cursor.pos);
3420 void LyXText::SetCursorFromCoordinates(int x, long y) const
3422 LyXCursor old_cursor = cursor;
3424 /* get the row first */
3426 Row * row = GetRowNearY(y);
3428 cursor.par = row->par;
3430 int column = GetColumnNearX(row, x);
3431 cursor.pos = row->pos + column;
3433 cursor.y = y + row->baseline;
3438 (cursor.pos == cursor.par->Last()
3439 || cursor.par->IsSeparator(cursor.pos)
3440 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3441 && !cursor.par->IsSeparator(cursor.pos))
3442 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3444 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3445 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3447 current_font = cursor.par->GetFontSettings(cursor.pos);
3448 real_current_font = GetFont(cursor.par, cursor.pos);
3450 DeleteEmptyParagraphMechanism(old_cursor);
3453 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3455 /* get the row first */
3457 Row * row = GetRowNearY(y);
3458 int column = GetColumnNearX(row, x);
3461 cur.pos = row->pos + column;
3463 cur.y = y + row->baseline;
3468 void LyXText::CursorLeft() const
3471 if (cursor.par->table) {
3472 int cell = NumberOfCell(cursor.par, cursor.pos);
3473 if (cursor.par->table->IsContRow(cell) &&
3474 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3481 void LyXText::CursorLeftIntern() const
3483 if (cursor.pos > 0) {
3484 SetCursor(cursor.par, cursor.pos - 1);
3486 else if (cursor.par->Previous()) { // steps into the above paragraph.
3487 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3492 void LyXText::CursorRight() const
3494 CursorRightIntern();
3495 if (cursor.par->table) {
3496 int cell = NumberOfCell(cursor.par, cursor.pos);
3497 if (cursor.par->table->IsContRow(cell) &&
3498 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3505 void LyXText::CursorRightIntern() const
3507 if (cursor.pos < cursor.par->Last()) {
3508 SetCursor(cursor.par, cursor.pos + 1);
3510 else if (cursor.par->Next()) {
3511 SetCursor(cursor.par->Next(), 0);
3516 void LyXText::CursorUp() const
3518 SetCursorFromCoordinates(cursor.x_fix,
3519 cursor.y - cursor.row->baseline - 1);
3520 if (cursor.par->table) {
3521 int cell = NumberOfCell(cursor.par, cursor.pos);
3522 if (cursor.par->table->IsContRow(cell) &&
3523 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3530 void LyXText::CursorDown() const
3532 if (cursor.par->table &&
3533 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3536 SetCursorFromCoordinates(cursor.x_fix,
3537 cursor.y - cursor.row->baseline
3538 + cursor.row->height + 1);
3539 if (cursor.par->table) {
3540 int cell = NumberOfCell(cursor.par, cursor.pos);
3541 int cell_above = cursor.par->table->GetCellAbove(cell);
3542 while(cursor.par->table &&
3543 cursor.par->table->IsContRow(cell) &&
3544 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3545 SetCursorFromCoordinates(cursor.x_fix,
3546 cursor.y - cursor.row->baseline
3547 + cursor.row->height + 1);
3548 if (cursor.par->table) {
3549 cell = NumberOfCell(cursor.par, cursor.pos);
3550 cell_above = cursor.par->table->GetCellAbove(cell);
3557 void LyXText::CursorUpParagraph() const
3559 if (cursor.pos > 0) {
3560 SetCursor(cursor.par, 0);
3562 else if (cursor.par->Previous()) {
3563 SetCursor(cursor.par->Previous(), 0);
3568 void LyXText::CursorDownParagraph() const
3570 if (cursor.par->Next()) {
3571 SetCursor(cursor.par->Next(), 0);
3573 SetCursor(cursor.par, cursor.par->Last());
3579 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3581 // Would be wrong to delete anything if we have a selection.
3582 if (selection) return;
3584 // We allow all kinds of "mumbo-jumbo" when freespacing.
3585 if (textclasslist.Style(buffer->params.textclass,
3586 old_cursor.par->GetLayout()).free_spacing)
3589 bool deleted = false;
3591 #ifdef FIX_DOUBLE_SPACE
3592 /* Ok I'll put some comments here about what is missing.
3593 I have fixed BackSpace (and thus Delete) to not delete
3594 double-spaces automagically. I have also changed Cut,
3595 Copy and Paste to hopefully do some sensible things.
3596 There are still some small problems that can lead to
3597 double spaces stored in the document file or space at
3598 the beginning of paragraphs. This happens if you have
3599 the cursor betwenn to spaces and then save. Or if you
3600 cut and paste and the selection have a space at the
3601 beginning and then save right after the paste. I am
3602 sure none of these are very hard to fix, but I will
3603 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3604 that I can get some feedback. (Lgb)
3607 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3608 // delete the LineSeparator.
3611 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3612 // delete the LineSeparator.
3615 // If the pos around the old_cursor were spaces, delete one of them.
3616 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3618 if (old_cursor.pos > 0
3619 && old_cursor.pos < old_cursor.par->Last()
3620 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3621 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3622 old_cursor.par->Erase(old_cursor.pos - 1);
3623 RedoParagraphs(old_cursor, old_cursor.par->Next());
3625 if (old_cursor.par == cursor.par &&
3626 cursor.pos > old_cursor.pos) {
3627 SetCursorIntern(cursor.par, cursor.pos - 1);
3629 SetCursorIntern(cursor.par, cursor.pos);
3635 // Do not delete empty paragraphs with keepempty set.
3636 if ((textclasslist.Style(buffer->params.textclass,
3637 old_cursor.par->GetLayout())).keepempty)
3640 LyXCursor tmpcursor;
3642 if (old_cursor.par != cursor.par) {
3643 if ( (old_cursor.par->Last() == 0
3644 || (old_cursor.par->Last() == 1
3645 && old_cursor.par->IsLineSeparator(0)))
3646 && old_cursor.par->FirstPhysicalPar()
3647 == old_cursor.par->LastPhysicalPar()) {
3648 // ok, we will delete anything
3650 // make sure that you do not delete any environments
3651 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3652 !(old_cursor.row->previous
3653 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3654 && !(old_cursor.row->next
3655 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3656 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3657 && ((old_cursor.row->previous
3658 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3659 || (old_cursor.row->next
3660 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3662 status = LyXText::NEED_MORE_REFRESH;
3665 if (old_cursor.row->previous) {
3666 refresh_row = old_cursor.row->previous;
3667 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3669 cursor = old_cursor; // that undo can restore the right cursor position
3670 LyXParagraph * endpar = old_cursor.par->next;
3671 if (endpar && endpar->GetDepth()) {
3672 while (endpar && endpar->GetDepth()) {
3673 endpar = endpar->LastPhysicalPar()->Next();
3676 SetUndo(Undo::DELETE,
3677 old_cursor.par->previous,
3682 RemoveRow(old_cursor.row);
3683 if (buffer->paragraph == old_cursor.par) {
3684 buffer->paragraph = buffer->paragraph->next;
3687 delete old_cursor.par;
3689 /* Breakagain the next par. Needed
3690 * because of the parindent that
3691 * can occur or dissappear. The
3692 * next row can change its height,
3693 * if there is another layout before */
3694 if (refresh_row->next) {
3695 BreakAgain(refresh_row->next);
3696 UpdateCounters(refresh_row);
3698 SetHeightOfRow(refresh_row);
3700 refresh_row = old_cursor.row->next;
3701 refresh_y = old_cursor.y - old_cursor.row->baseline;
3704 cursor = old_cursor; // that undo can restore the right cursor position
3705 LyXParagraph *endpar = old_cursor.par->next;
3706 if (endpar && endpar->GetDepth()) {
3707 while (endpar && endpar->GetDepth()) {
3708 endpar = endpar->LastPhysicalPar()->Next();
3711 SetUndo(Undo::DELETE,
3712 old_cursor.par->previous,
3717 RemoveRow(old_cursor.row);
3719 if (buffer->paragraph == old_cursor.par) {
3720 buffer->paragraph = buffer->paragraph->next;
3722 delete old_cursor.par;
3724 /* Breakagain the next par. Needed
3725 because of the parindent that can
3726 occur or dissappear.
3727 The next row can change its height,
3728 if there is another layout before
3731 BreakAgain(refresh_row);
3732 UpdateCounters(refresh_row->previous);
3738 SetCursorIntern(cursor.par, cursor.pos);
3740 SetCursor(cursor.par, cursor.pos);
3742 /* if (cursor.y > old_cursor.y)
3743 cursor.y -= old_cursor.row->height; */
3745 if (sel_cursor.par == old_cursor.par
3746 && sel_cursor.pos == sel_cursor.pos) {
3747 // correct selection
3748 sel_cursor = cursor;
3753 if (old_cursor.par->ClearParagraph()) {
3754 RedoParagraphs(old_cursor, old_cursor.par->Next());
3757 SetCursorIntern(cursor.par, cursor.pos);
3759 SetCursor(cursor.par, cursor.pos);
3761 sel_cursor = cursor;
3769 LyXParagraph * LyXText::GetParFromID(int id)
3771 LyXParagraph * result = FirstParagraph();
3772 while (result && result->id() != id)
3773 result = result->next;
3779 bool LyXText::TextUndo()
3781 // returns false if no undo possible
3782 Undo * undo = buffer->undostack.pop();
3787 .push(CreateUndo(undo->kind,
3788 GetParFromID(undo->number_of_before_par),
3789 GetParFromID(undo->number_of_behind_par)));
3791 return TextHandleUndo(undo);
3795 bool LyXText::TextRedo()
3797 // returns false if no redo possible
3798 Undo * undo = buffer->redostack.pop();
3803 .push(CreateUndo(undo->kind,
3804 GetParFromID(undo->number_of_before_par),
3805 GetParFromID(undo->number_of_behind_par)));
3807 return TextHandleUndo(undo);
3811 bool LyXText::TextHandleUndo(Undo * undo)
3813 // returns false if no undo possible
3814 bool result = false;
3816 LyXParagraph * before =
3817 GetParFromID(undo->number_of_before_par);
3818 LyXParagraph * behind =
3819 GetParFromID(undo->number_of_behind_par);
3820 LyXParagraph * tmppar;
3821 LyXParagraph * tmppar2;
3822 LyXParagraph * endpar;
3823 LyXParagraph * tmppar5;
3825 // if there's no before take the beginning
3826 // of the document for redoing
3828 SetCursorIntern(FirstParagraph(), 0);
3830 // replace the paragraphs with the undo informations
3832 LyXParagraph * tmppar3 = undo->par;
3833 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3834 LyXParagraph * tmppar4 = tmppar3;
3836 while (tmppar4->next)
3837 tmppar4 = tmppar4->next;
3838 } // get last undo par
3840 // now remove the old text if there is any
3841 if (before != behind || (!behind && !before)){
3843 tmppar5 = before->next;
3845 tmppar5 = buffer->paragraph;
3847 while (tmppar5 && tmppar5 != behind){
3849 tmppar5 = tmppar5->next;
3850 // a memory optimization for edit: Only layout information
3851 // is stored in the undo. So restore the text informations.
3852 if (undo->kind == Undo::EDIT) {
3853 tmppar2->setContentsFromPar(tmppar);
3854 tmppar->clearContents();
3855 //tmppar2->text = tmppar->text;
3856 //tmppar->text.clear();
3857 tmppar2 = tmppar2->next;
3859 if ( currentrow && currentrow->par == tmppar )
3860 currentrow = currentrow -> previous;
3861 // Commenting out this might remove the error
3862 // reported by Purify, but it might also
3863 // introduce a memory leak. We need to
3869 // put the new stuff in the list if there is one
3872 before->next = tmppar3;
3874 buffer->paragraph = tmppar3;
3875 tmppar3->previous = before;
3879 buffer->paragraph = behind;
3882 tmppar4->next = behind;
3884 behind->previous = tmppar4;
3888 // Set the cursor for redoing
3890 SetCursorIntern(before->FirstSelfrowPar(), 0);
3891 // check wether before points to a closed float and open it if necessary
3892 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3893 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3895 while (tmppar4->previous &&
3896 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3897 tmppar4 = tmppar4->previous;
3898 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3899 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3900 tmppar4 = tmppar4->next;
3905 // open a cosed footnote at the end if necessary
3906 if (behind && behind->previous &&
3907 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3908 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3909 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3910 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3911 behind = behind->next;
3915 // calculate the endpar for redoing the paragraphs.
3917 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3918 endpar = behind->LastPhysicalPar()->Next();
3920 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3925 tmppar = GetParFromID(undo->number_of_cursor_par);
3926 RedoParagraphs(cursor, endpar);
3928 SetCursorIntern(tmppar, undo->cursor_pos);
3929 UpdateCounters(cursor.row);
3939 void LyXText::FinishUndo()
3941 // makes sure the next operation will be stored
3942 undo_finished = True;
3946 void LyXText::FreezeUndo()
3948 // this is dangerous and for internal use only
3953 void LyXText::UnFreezeUndo()
3955 // this is dangerous and for internal use only
3956 undo_frozen = false;
3960 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3961 LyXParagraph const * behind) const
3964 buffer->undostack.push(CreateUndo(kind, before, behind));
3965 buffer->redostack.clear();
3969 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3970 LyXParagraph const * behind)
3972 buffer->redostack.push(CreateUndo(kind, before, behind));
3976 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3977 LyXParagraph const * behind) const
3979 int before_number = -1;
3980 int behind_number = -1;
3982 before_number = before->id();
3984 behind_number = behind->id();
3985 // Undo::EDIT and Undo::FINISH are
3986 // always finished. (no overlapping there)
3987 // overlapping only with insert and delete inside one paragraph:
3988 // Nobody wants all removed character
3989 // appear one by one when undoing.
3990 // EDIT is special since only layout information, not the
3991 // contents of a paragaph are stored.
3992 if (!undo_finished && kind != Undo::EDIT &&
3993 kind != Undo::FINISH){
3994 // check wether storing is needed
3995 if (!buffer->undostack.empty() &&
3996 buffer->undostack.top()->kind == kind &&
3997 buffer->undostack.top()->number_of_before_par == before_number &&
3998 buffer->undostack.top()->number_of_behind_par == behind_number ){
4003 // create a new Undo
4004 LyXParagraph * undopar;
4005 LyXParagraph * tmppar;
4006 LyXParagraph * tmppar2;
4008 LyXParagraph * start = 0;
4009 LyXParagraph * end = 0;
4012 start = before->next;
4014 start = FirstParagraph();
4016 end = behind->previous;
4018 end = FirstParagraph();
4024 && start != end->next
4025 && (before != behind || (!before && !behind))) {
4027 tmppar2 = tmppar->Clone();
4028 tmppar2->id(tmppar->id());
4030 // a memory optimization: Just store the layout information
4032 if (kind == Undo::EDIT){
4033 //tmppar2->text.clear();
4034 tmppar2->clearContents();
4039 while (tmppar != end && tmppar->next) {
4040 tmppar = tmppar->next;
4041 tmppar2->next = tmppar->Clone();
4042 tmppar2->next->id(tmppar->id());
4043 // a memory optimization: Just store the layout
4044 // information when only edit
4045 if (kind == Undo::EDIT){
4046 //tmppar2->next->text.clear();
4047 tmppar2->clearContents();
4049 tmppar2->next->previous = tmppar2;
4050 tmppar2 = tmppar2->next;
4054 undopar = 0; // nothing to replace (undo of delete maybe)
4056 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
4057 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
4059 Undo * undo = new Undo(kind,
4060 before_number, behind_number,
4061 cursor_par, cursor_pos,
4064 undo_finished = false;
4069 void LyXText::SetCursorParUndo()
4071 SetUndo(Undo::FINISH,
4072 cursor.par->ParFromPos(cursor.pos)->previous,
4073 cursor.par->ParFromPos(cursor.pos)->next);
4077 void LyXText::RemoveTableRow(LyXCursor * cur) const
4083 // move to the previous row
4084 int cell_act = NumberOfCell(cur->par, cur->pos);
4087 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4090 !cur->par->table->IsFirstCell(cell_act)) {
4092 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4097 // now we have to pay attention if the actual table is the
4098 // main row of TableContRows and if yes to delete all of them
4103 // delete up to the next row
4104 while (cur->pos < cur->par->Last() &&
4106 || !cur->par->table->IsFirstCell(cell_act))) {
4107 while (cur->pos < cur->par->Last() &&
4108 !cur->par->IsNewline(cur->pos))
4109 cur->par->Erase(cur->pos);
4112 if (cur->pos < cur->par->Last())
4113 cur->par->Erase(cur->pos);
4115 if (cur->pos && cur->pos == cur->par->Last()) {
4117 cur->par->Erase(cur->pos); // no newline at very end!
4119 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4120 !cur->par->table->IsContRow(cell_org) &&
4121 cur->par->table->IsContRow(cell));
4122 cur->par->table->DeleteRow(cell_org);
4127 bool LyXText::IsEmptyTableCell() const
4129 LyXParagraph::size_type pos = cursor.pos - 1;
4130 while (pos >= 0 && pos < cursor.par->Last()
4131 && !cursor.par->IsNewline(pos))
4133 return cursor.par->IsNewline(pos + 1);
4137 void LyXText::toggleAppendix(){
4138 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4139 bool start = !par->start_of_appendix;
4141 // ensure that we have only one start_of_appendix in this document
4142 LyXParagraph * tmp = FirstParagraph();
4143 for (; tmp; tmp = tmp->next)
4144 tmp->start_of_appendix = 0;
4145 par->start_of_appendix = start;
4147 // we can set the refreshing parameters now
4148 status = LyXText::NEED_MORE_REFRESH;
4150 refresh_row = 0; // not needed for full update
4152 SetCursor(cursor.par, cursor.pos);