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"
41 #define FIX_DOUBLE_SPACE 1
47 LyXText::LyXText(BufferView * bv, int pw, Buffer * p)
55 parameters = &p->params;
59 status = LyXText::UNCHANGED;
60 LyXParagraph * par = p->paragraph;
61 current_font = GetFont(par, 0);
66 InsertParagraph(par, lastrow);
70 // set cursor at the very top position
71 selection = true; /* these setting is necessary
72 because of the delete-empty-
73 paragraph mechanism in
75 SetCursor(firstrow->par, 0);
80 // no rebreak necessary
86 // Default layouttype for copy environment type
93 // Delete all rows, this does not touch the paragraphs!
94 Row * tmprow = firstrow;
96 tmprow = firstrow->next;
103 void LyXText::owner(BufferView * bv)
105 if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
109 // Gets the fully instantiated font at a given position in a paragraph
110 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
111 // The difference is that this one is used for displaying, and thus we
112 // are allowed to make cosmetic improvements. For instance make footnotes
114 // If position is -1, we get the layout font of the paragraph.
115 // If position is -2, we get the font of the manual label of the paragraph.
116 LyXFont LyXText::GetFont(LyXParagraph * par,
117 LyXParagraph::size_type pos) const
119 LyXLayout const & layout =
120 textclasslist.Style(parameters->textclass, par->GetLayout());
122 char par_depth = par->GetDepth();
123 // We specialize the 95% common case:
124 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
127 if (layout.labeltype == LABEL_MANUAL
128 && pos < BeginningOfMainBody(par)) {
130 return par->GetFontSettings(pos).
131 realize(layout.reslabelfont);
133 return par->GetFontSettings(pos).
134 realize(layout.resfont);
137 // process layoutfont for pos == -1 and labelfont for pos < -1
139 return layout.resfont;
141 return layout.reslabelfont;
145 // The uncommon case need not be optimized as much
147 LyXFont layoutfont, tmpfont;
151 if (pos < BeginningOfMainBody(par)) {
153 layoutfont = layout.labelfont;
156 layoutfont = layout.font;
158 tmpfont = par->GetFontSettings(pos);
159 tmpfont.realize(layoutfont);
162 // process layoutfont for pos == -1 and labelfont for pos < -1
164 tmpfont = layout.font;
166 tmpfont = layout.labelfont;
169 // Resolve against environment font information
170 while (par && par_depth && !tmpfont.resolved()) {
171 par = par->DepthHook(par_depth - 1);
173 tmpfont.realize(textclasslist.
174 Style(parameters->textclass,
175 par->GetLayout()).font);
176 par_depth = par->GetDepth();
180 tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
182 // Cosmetic improvement: If this is an open footnote, make the font
184 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
185 && par->footnotekind == LyXParagraph::FOOTNOTE) {
193 void LyXText::SetCharFont(LyXParagraph * par,
194 LyXParagraph::size_type pos,
198 // Let the insets convert their font
199 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
200 if (par->GetInset(pos))
201 font = par->GetInset(pos)->ConvertFont(font);
204 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
207 // Get concrete layout font to reduce against
210 if (pos < BeginningOfMainBody(par))
211 layoutfont = layout.labelfont;
213 layoutfont = layout.font;
215 // Realize against environment font information
216 if (par->GetDepth()){
217 LyXParagraph * tp = par;
218 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
219 tp = tp->DepthHook(tp->GetDepth()-1);
221 layoutfont.realize(textclasslist.
222 Style(parameters->textclass,
223 tp->GetLayout()).font);
227 layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
229 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
230 && par->footnotekind == LyXParagraph::FOOTNOTE) {
231 layoutfont.decSize();
234 // Now, reduce font against full layout font
235 font.reduce(layoutfont);
237 par->SetFont(pos, font);
241 /* inserts a new row behind the specified row, increments
242 * the touched counters */
243 void LyXText::InsertRow(Row * row, LyXParagraph * par,
244 LyXParagraph::size_type pos) const
246 Row * tmprow = new Row;
248 tmprow->previous = 0;
249 tmprow->next = firstrow;
252 tmprow->previous = row;
253 tmprow->next = row->next;
258 tmprow->next->previous = tmprow;
260 if (tmprow->previous)
261 tmprow->previous->next = tmprow;
269 ++number_of_rows; // one more row
273 // removes the row and reset the touched counters
274 void LyXText::RemoveRow(Row * row) const
276 /* this must not happen before the currentrow for clear reasons.
277 so the trick is just to set the current row onto the previous
280 GetRow(row->par, row->pos, unused_y);
281 currentrow = currentrow->previous;
283 currentrow_y -= currentrow->height;
288 row->next->previous = row->previous;
289 if (!row->previous) {
290 firstrow = row->next;
292 row->previous->next = row->next;
295 lastrow = row->previous;
297 height -= row->height; // the text becomes smaller
300 --number_of_rows; // one row less
304 // remove all following rows of the paragraph of the specified row.
305 void LyXText::RemoveParagraph(Row * row) const
307 LyXParagraph * tmppar = row->par;
311 while (row && row->par == tmppar) {
319 // insert the specified paragraph behind the specified row
320 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
322 InsertRow(row, par, 0); /* insert a new row, starting
325 SetCounter(par); // set the counters
327 // and now append the whole paragraph behind the new row
329 firstrow->height = 0;
330 AppendParagraph(firstrow);
332 row->next->height = 0;
333 AppendParagraph(row->next);
338 void LyXText::ToggleFootnote()
340 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
342 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
344 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
346 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
352 void LyXText::OpenStuff()
354 if (cursor.pos == 0 && cursor.par->bibkey){
355 cursor.par->bibkey->Edit(owner_, 0, 0, 0);
357 else if (cursor.pos < cursor.par->Last()
358 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
359 && cursor.par->GetInset(cursor.pos)->Editable()) {
360 owner_->owner()->getMiniBuffer()
361 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
362 if (cursor.par->GetInset(cursor.pos)->Editable() != Inset::HIGHLY_EDITABLE)
364 cursor.par->GetInset(cursor.pos)->Edit(owner_, 0, 0, 0);
371 void LyXText::CloseFootnote()
373 LyXParagraph * tmppar;
374 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
376 // if the cursor is not in an open footnote, or
377 // there is no open footnote in this paragraph, just return.
378 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
381 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
382 owner_->owner()->getMiniBuffer()
383 ->Set(_("Nothing to do"));
387 // ok, move the cursor right before the footnote
388 // just a little faster than using CursorRight()
390 cursor.par->ParFromPos(cursor.pos) != par;
394 // now the cursor is at the beginning of the physical par
395 SetCursor(cursor.par,
397 cursor.par->ParFromPos(cursor.pos)->size());
399 /* we are in a footnote, so let us move at the beginning */
400 /* this is just faster than using just CursorLeft() */
403 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
404 // just a little bit faster than movin the cursor
405 tmppar = tmppar->Previous();
407 SetCursor(tmppar, tmppar->Last());
410 // the cursor must be exactly before the footnote
411 par = cursor.par->ParFromPos(cursor.pos);
413 status = LyXText::NEED_MORE_REFRESH;
414 refresh_row = cursor.row;
415 refresh_y = cursor.y - cursor.row->baseline;
418 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
419 Row * row = cursor.row;
421 tmppar->CloseFootnote(cursor.pos);
423 while (tmppar != endpar) {
424 RemoveRow(row->next);
426 tmppar = row->next->par;
431 AppendParagraph(cursor.row);
433 SetCursor(cursor.par, cursor.pos);
437 if (cursor.row->next)
438 SetHeightOfRow(cursor.row->next);
442 /* used in setlayout */
443 // Asger is not sure we want to do this...
444 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
447 LyXLayout const & layout =
448 textclasslist.Style(parameters->textclass, par->GetLayout());
450 LyXFont layoutfont, tmpfont;
451 for (LyXParagraph::size_type pos = 0;
452 pos < par->Last(); ++pos) {
453 if (pos < BeginningOfMainBody(par))
454 layoutfont = layout.labelfont;
456 layoutfont = layout.font;
458 tmpfont = par->GetFontSettings(pos);
459 tmpfont.reduce(layoutfont);
460 par->SetFont(pos, tmpfont);
465 // set layout over selection and make a total rebreak of those paragraphs
466 void LyXText::SetLayout(LyXTextClass::size_type layout)
470 // if there is no selection just set the layout
471 // of the current paragraph */
473 sel_start_cursor = cursor; // dummy selection
474 sel_end_cursor = cursor;
477 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
478 LyXParagraph * undoendpar = endpar;
480 if (endpar && endpar->GetDepth()) {
481 while (endpar && endpar->GetDepth()) {
482 endpar = endpar->LastPhysicalPar()->Next();
487 endpar = endpar->Next(); // because of parindents etc.
491 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
494 tmpcursor = cursor; /* store the current cursor */
496 /* ok we have a selection. This is always between sel_start_cursor
497 * and sel_end cursor */
498 cursor = sel_start_cursor;
500 LyXLayout const & lyxlayout =
501 textclasslist.Style(parameters->textclass, layout);
503 while (cursor.par != sel_end_cursor.par) {
504 if (cursor.par->footnoteflag ==
505 sel_start_cursor.par->footnoteflag) {
506 cursor.par->SetLayout(layout);
507 MakeFontEntriesLayoutSpecific(cursor.par);
508 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
509 fppar->added_space_top = lyxlayout.fill_top ?
510 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
511 fppar->added_space_bottom = lyxlayout.fill_bottom ?
512 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
513 if (lyxlayout.margintype == MARGIN_MANUAL)
514 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
515 if (lyxlayout.labeltype != LABEL_BIBLIO
517 delete fppar->bibkey;
521 cursor.par = cursor.par->Next();
523 if (cursor.par->footnoteflag ==
524 sel_start_cursor.par->footnoteflag) {
525 cursor.par->SetLayout(layout);
526 MakeFontEntriesLayoutSpecific(cursor.par);
527 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
528 fppar->added_space_top = lyxlayout.fill_top ?
529 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
530 fppar->added_space_bottom = lyxlayout.fill_bottom ?
531 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
532 if (lyxlayout.margintype == MARGIN_MANUAL)
533 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
534 if (lyxlayout.labeltype != LABEL_BIBLIO
536 delete fppar->bibkey;
541 RedoParagraphs(sel_start_cursor, endpar);
543 // we have to reset the selection, because the
544 // geometry could have changed */
545 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
547 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
548 UpdateCounters(cursor.row);
551 SetCursor(tmpcursor.par, tmpcursor.pos, true);
555 // increment depth over selection and
556 // make a total rebreak of those paragraphs
557 void LyXText::IncDepth()
559 // If there is no selection, just use the current paragraph
561 sel_start_cursor = cursor; // dummy selection
562 sel_end_cursor = cursor;
565 // We end at the next paragraph with depth 0
566 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
567 LyXParagraph * undoendpar = endpar;
569 if (endpar && endpar->GetDepth()) {
570 while (endpar && endpar->GetDepth()) {
571 endpar = endpar->LastPhysicalPar()->Next();
576 endpar = endpar->Next(); // because of parindents etc.
581 .par->ParFromPos(sel_start_cursor.pos)->previous,
584 LyXCursor tmpcursor = cursor; // store the current cursor
586 // ok we have a selection. This is always between sel_start_cursor
587 // and sel_end cursor
588 cursor = sel_start_cursor;
590 bool anything_changed = false;
593 // NOTE: you can't change the depth of a bibliography entry
594 if (cursor.par->footnoteflag ==
595 sel_start_cursor.par->footnoteflag
596 && textclasslist.Style(parameters->textclass,
597 cursor.par->GetLayout()
598 ).labeltype != LABEL_BIBLIO) {
599 LyXParagraph * prev =
600 cursor.par->FirstPhysicalPar()->Previous();
602 && (prev->GetDepth() - cursor.par->GetDepth() > 0
603 || (prev->GetDepth() == cursor.par->GetDepth()
604 && textclasslist.Style(parameters->textclass,
605 prev->GetLayout()).isEnvironment()))) {
606 cursor.par->FirstPhysicalPar()->depth++;
607 anything_changed = true;
610 if (cursor.par == sel_end_cursor.par)
612 cursor.par = cursor.par->Next();
615 // if nothing changed set all depth to 0
616 if (!anything_changed) {
617 cursor = sel_start_cursor;
618 while (cursor.par != sel_end_cursor.par) {
619 cursor.par->FirstPhysicalPar()->depth = 0;
620 cursor.par = cursor.par->Next();
622 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
623 cursor.par->FirstPhysicalPar()->depth = 0;
626 RedoParagraphs(sel_start_cursor, endpar);
628 // we have to reset the selection, because the
629 // geometry could have changed
630 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
632 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
633 UpdateCounters(cursor.row);
636 SetCursor(tmpcursor.par, tmpcursor.pos);
640 // decrement depth over selection and
641 // make a total rebreak of those paragraphs
642 void LyXText::DecDepth()
644 // if there is no selection just set the layout
645 // of the current paragraph
647 sel_start_cursor = cursor; // dummy selection
648 sel_end_cursor = cursor;
651 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
652 LyXParagraph * undoendpar = endpar;
654 if (endpar && endpar->GetDepth()) {
655 while (endpar && endpar->GetDepth()) {
656 endpar = endpar->LastPhysicalPar()->Next();
661 endpar = endpar->Next(); // because of parindents etc.
666 .par->ParFromPos(sel_start_cursor.pos)->previous,
669 LyXCursor tmpcursor = cursor; // store the current cursor
671 // ok we have a selection. This is always between sel_start_cursor
672 // and sel_end cursor
673 cursor = sel_start_cursor;
676 if (cursor.par->footnoteflag ==
677 sel_start_cursor.par->footnoteflag) {
678 if (cursor.par->FirstPhysicalPar()->depth)
679 cursor.par->FirstPhysicalPar()->depth--;
681 if (cursor.par == sel_end_cursor.par)
683 cursor.par = cursor.par->Next();
686 RedoParagraphs(sel_start_cursor, endpar);
688 // we have to reset the selection, because the
689 // geometry could have changed
690 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
692 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
693 UpdateCounters(cursor.row);
696 SetCursor(tmpcursor.par, tmpcursor.pos);
700 // set font over selection and make a total rebreak of those paragraphs
701 void LyXText::SetFont(LyXFont const & font, bool toggleall)
703 // if there is no selection just set the current_font
705 // Determine basis font
707 if (cursor.pos < BeginningOfMainBody(cursor.par))
708 layoutfont = GetFont(cursor.par, -2);
710 layoutfont = GetFont(cursor.par, -1);
711 // Update current font
712 real_current_font.update(font, parameters->language_info, toggleall);
714 // Reduce to implicit settings
715 current_font = real_current_font;
716 current_font.reduce(layoutfont);
717 // And resolve it completely
718 real_current_font.realize(layoutfont);
722 LyXCursor tmpcursor = cursor; // store the current cursor
724 // ok we have a selection. This is always between sel_start_cursor
725 // and sel_end cursor
728 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
729 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
730 cursor = sel_start_cursor;
731 while (cursor.par != sel_end_cursor.par ||
732 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
733 && cursor.pos < sel_end_cursor.pos))
735 if (cursor.pos < cursor.par->Last()
736 && cursor.par->footnoteflag
737 == sel_start_cursor.par->footnoteflag) {
738 // an open footnote should behave
740 LyXFont newfont = GetFont(cursor.par, cursor.pos);
741 newfont.update(font, parameters->language_info, toggleall);
742 SetCharFont(cursor.par, cursor.pos, newfont);
746 cursor.par = cursor.par->Next();
750 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
752 // we have to reset the selection, because the
753 // geometry could have changed
754 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
756 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
759 SetCursor(tmpcursor.par, tmpcursor.pos);
763 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
765 Row * tmprow = cur.row;
766 long y = cur.y - tmprow->baseline;
768 SetHeightOfRow(tmprow);
769 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
770 // find the first row of the paragraph
771 if (first_phys_par != tmprow->par)
772 while (tmprow->previous
773 && tmprow->previous->par != first_phys_par) {
774 tmprow = tmprow->previous;
776 SetHeightOfRow(tmprow);
778 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
779 tmprow = tmprow->previous;
781 SetHeightOfRow(tmprow);
784 // we can set the refreshing parameters now
785 status = LyXText::NEED_MORE_REFRESH;
787 refresh_row = tmprow;
788 SetCursor(cur.par, cur.pos);
792 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
794 Row * tmprow = cur.row;
796 long y = cur.y - tmprow->baseline;
797 SetHeightOfRow(tmprow);
798 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
799 // find the first row of the paragraph
800 if (first_phys_par != tmprow->par)
801 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
802 tmprow = tmprow->previous;
805 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
806 tmprow = tmprow->previous;
810 // we can set the refreshing parameters now
811 if (status == LyXText::UNCHANGED || y < refresh_y) {
813 refresh_row = tmprow;
815 status = LyXText::NEED_MORE_REFRESH;
816 SetCursor(cur.par, cur.pos);
820 /* deletes and inserts again all paragaphs between the cursor
821 * and the specified par
822 * This function is needed after SetLayout and SetFont etc. */
823 void LyXText::RedoParagraphs(LyXCursor const & cur,
824 LyXParagraph const * endpar) const
827 LyXParagraph * tmppar, * first_phys_par;
829 Row * tmprow = cur.row;
831 long y = cur.y - tmprow->baseline;
833 if (!tmprow->previous){
834 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
836 first_phys_par = tmprow->par->FirstPhysicalPar();
837 // find the first row of the paragraph
838 if (first_phys_par != tmprow->par)
839 while (tmprow->previous &&
840 (tmprow->previous->par != first_phys_par)) {
841 tmprow = tmprow->previous;
844 while (tmprow->previous
845 && tmprow->previous->par == first_phys_par) {
846 tmprow = tmprow->previous;
851 // we can set the refreshing parameters now
852 status = LyXText::NEED_MORE_REFRESH;
854 refresh_row = tmprow->previous; /* the real refresh row will
855 be deleted, so I store
859 tmppar = tmprow->next->par;
862 while (tmppar != endpar) {
863 RemoveRow(tmprow->next);
865 tmppar = tmprow->next->par;
870 // remove the first one
871 tmprow2 = tmprow; /* this is because tmprow->previous
873 tmprow = tmprow->previous;
876 tmppar = first_phys_par;
880 InsertParagraph(tmppar, tmprow);
883 while (tmprow->next && tmprow->next->par == tmppar)
884 tmprow = tmprow->next;
885 tmppar = tmppar->Next();
887 } while (tmppar != endpar);
889 // this is because of layout changes
891 refresh_y -= refresh_row->height;
892 SetHeightOfRow(refresh_row);
894 refresh_row = firstrow;
896 SetHeightOfRow(refresh_row);
899 if (tmprow && tmprow->next)
900 SetHeightOfRow(tmprow->next);
904 int LyXText::FullRebreak()
906 if (need_break_row) {
907 BreakAgain(need_break_row);
915 /* important for the screen */
918 /* the cursor set functions have a special mechanism. When they
919 * realize, that you left an empty paragraph, they will delete it.
920 * They also delet the corresponding row */
922 // need the selection cursor:
923 void LyXText::SetSelection()
926 last_sel_cursor = sel_cursor;
927 sel_start_cursor = sel_cursor;
928 sel_end_cursor = sel_cursor;
933 // first the toggling area
934 if (cursor.y < last_sel_cursor.y ||
935 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
936 toggle_end_cursor = last_sel_cursor;
937 toggle_cursor = cursor;
940 toggle_end_cursor = cursor;
941 toggle_cursor = last_sel_cursor;
944 last_sel_cursor = cursor;
946 // and now the whole selection
948 if (sel_cursor.par == cursor.par)
949 if (sel_cursor.pos < cursor.pos) {
950 sel_end_cursor = cursor;
951 sel_start_cursor = sel_cursor;
953 sel_end_cursor = sel_cursor;
954 sel_start_cursor = cursor;
956 else if (sel_cursor.y < cursor.y ||
957 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
958 sel_end_cursor = cursor;
959 sel_start_cursor = sel_cursor;
962 sel_end_cursor = sel_cursor;
963 sel_start_cursor = cursor;
966 // a selection with no contents is not a selection
967 if (sel_start_cursor.x == sel_end_cursor.x &&
968 sel_start_cursor.y == sel_end_cursor.y)
973 void LyXText::ClearSelection() const
980 void LyXText::CursorHome() const
982 SetCursor(cursor.par, cursor.row->pos);
986 void LyXText::CursorEnd() const
988 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
989 SetCursor(cursor.par, RowLast(cursor.row) + 1);
991 if (cursor.par->Last() &&
992 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
993 || cursor.par->IsNewline(RowLast(cursor.row))))
994 SetCursor(cursor.par, RowLast(cursor.row));
996 SetCursor(cursor.par, RowLast(cursor.row) + 1);
998 if (cursor.par->table) {
999 int cell = NumberOfCell(cursor.par, cursor.pos);
1000 if (cursor.par->table->RowHasContRow(cell) &&
1001 cursor.par->table->CellHasContRow(cell)<0) {
1002 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1003 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1005 if (cursor.par->Last() &&
1006 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1007 || cursor.par->IsNewline(RowLast(cursor.row))))
1008 SetCursor(cursor.par, RowLast(cursor.row));
1010 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1017 void LyXText::CursorTop() const
1019 while (cursor.par->Previous())
1020 cursor.par = cursor.par->Previous();
1021 SetCursor(cursor.par, 0);
1025 void LyXText::CursorBottom() const
1027 while (cursor.par->Next())
1028 cursor.par = cursor.par->Next();
1029 SetCursor(cursor.par, cursor.par->Last());
1033 /* returns a pointer to the row near the specified y-coordinate
1034 * (relative to the whole text). y is set to the real beginning
1036 Row * LyXText::GetRowNearY(long & y) const
1042 tmprow = currentrow;
1043 tmpy = currentrow_y;
1050 while (tmprow->next && tmpy + tmprow->height <= y) {
1051 tmpy += tmprow->height;
1052 tmprow = tmprow->next;
1055 while (tmprow->previous && tmpy > y) {
1056 tmprow = tmprow->previous;
1057 tmpy -= tmprow->height;
1060 currentrow = tmprow;
1061 currentrow_y = tmpy;
1063 y = tmpy; // return the real y
1068 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1070 // If the mask is completely neutral, tell user
1071 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1072 // Could only happen with user style
1073 owner_->owner()->getMiniBuffer()
1074 ->Set(_("No font change defined. Use Character under"
1075 " the Layout menu to define font change."));
1079 // Try implicit word selection
1080 LyXCursor resetCursor = cursor;
1081 int implicitSelection = SelectWordWhenUnderCursor();
1084 SetFont(font, toggleall);
1086 /* Implicit selections are cleared afterwards and cursor is set to the
1087 original position. */
1088 if (implicitSelection) {
1090 cursor = resetCursor;
1091 SetCursor( cursor.par, cursor.pos );
1092 sel_cursor = cursor;
1097 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1099 if (textclasslist.Style(parameters->textclass,
1100 par->GetLayout()).labeltype != LABEL_MANUAL)
1103 return par->BeginningOfMainBody();
1107 /* if there is a selection, reset every environment you can find
1108 * in the selection, otherwise just the environment you are in */
1109 void LyXText::MeltFootnoteEnvironment()
1111 LyXParagraph * tmppar, * firsttmppar;
1115 /* is is only allowed, if the cursor is IN an open footnote.
1116 * Otherwise it is too dangerous */
1117 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1120 SetUndo(Undo::FINISH,
1121 cursor.par->PreviousBeforeFootnote()->previous,
1122 cursor.par->NextAfterFootnote()->next);
1124 /* ok, move to the beginning of the footnote. */
1125 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1126 cursor.par = cursor.par->Previous();
1128 SetCursor(cursor.par, cursor.par->Last());
1129 /* this is just faster than using CursorLeft(); */
1131 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1132 tmppar = firsttmppar;
1133 /* tmppar is now the paragraph right before the footnote */
1135 bool first_footnote_par_is_not_empty = tmppar->next->size();
1138 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1139 tmppar = tmppar->next; /* I use next instead of Next(),
1140 * because there cannot be any
1141 * footnotes in a footnote
1143 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1145 /* remember the captions and empty paragraphs */
1146 if ((textclasslist.Style(parameters->textclass,
1147 tmppar->GetLayout())
1148 .labeltype == LABEL_SENSITIVE)
1150 tmppar->SetLayout(0);
1153 // now we will paste the ex-footnote, if the layouts allow it
1154 // first restore the layout of the paragraph right behind
1157 tmppar->next->MakeSameLayout(cursor.par);
1160 if ((!tmppar->GetLayout() && !tmppar->table)
1162 && (!tmppar->Next()->Last()
1163 || tmppar->Next()->HasSameLayout(tmppar)))) {
1164 if (tmppar->Next()->Last()
1165 && tmppar->Next()->IsLineSeparator(0))
1166 tmppar->Next()->Erase(0);
1167 tmppar->PasteParagraph();
1170 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1171 * by the pasting of the beginning */
1173 /* then the beginning */
1174 /* if there is no space between the text and the footnote, so we insert
1176 * (only if the previous par and the footnotepar are not empty!) */
1177 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1178 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1179 if (firsttmppar->size()
1180 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1181 && first_footnote_par_is_not_empty) {
1182 firsttmppar->next->InsertChar(0, ' ');
1184 firsttmppar->PasteParagraph();
1187 /* now redo the paragaphs */
1188 RedoParagraphs(cursor, tmppar);
1190 SetCursor(cursor.par, cursor.pos);
1192 /* sometimes it can happen, that there is a counter change */
1193 Row * row = cursor.row;
1194 while (row->next && row->par != tmppar && row->next->par != tmppar)
1196 UpdateCounters(row);
1203 /* the DTP switches for paragraphs. LyX will store them in the
1204 * first physicla paragraph. When a paragraph is broken, the top settings
1205 * rest, the bottom settings are given to the new one. So I can make shure,
1206 * they do not duplicate themself and you cannnot make dirty things with
1209 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1210 bool pagebreak_top, bool pagebreak_bottom,
1211 VSpace const & space_top,
1212 VSpace const & space_bottom,
1214 string labelwidthstring,
1217 LyXCursor tmpcursor = cursor;
1219 sel_start_cursor = cursor;
1220 sel_end_cursor = cursor;
1223 // make sure that the depth behind the selection are restored, too
1224 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1225 LyXParagraph * undoendpar = endpar;
1227 if (endpar && endpar->GetDepth()) {
1228 while (endpar && endpar->GetDepth()) {
1229 endpar = endpar->LastPhysicalPar()->Next();
1230 undoendpar = endpar;
1234 endpar = endpar->Next(); // because of parindents etc.
1239 .par->ParFromPos(sel_start_cursor.pos)->previous,
1243 LyXParagraph * tmppar = sel_end_cursor.par;
1244 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1245 SetCursor(tmppar->FirstPhysicalPar(), 0);
1246 status = LyXText::NEED_MORE_REFRESH;
1247 refresh_row = cursor.row;
1248 refresh_y = cursor.y - cursor.row->baseline;
1249 if (cursor.par->footnoteflag ==
1250 sel_start_cursor.par->footnoteflag) {
1251 cursor.par->line_top = line_top;
1252 cursor.par->line_bottom = line_bottom;
1253 cursor.par->pagebreak_top = pagebreak_top;
1254 cursor.par->pagebreak_bottom = pagebreak_bottom;
1255 cursor.par->added_space_top = space_top;
1256 cursor.par->added_space_bottom = space_bottom;
1257 // does the layout allow the new alignment?
1258 if (align == LYX_ALIGN_LAYOUT)
1259 align = textclasslist
1260 .Style(parameters->textclass,
1261 cursor.par->GetLayout()).align;
1262 if (align & textclasslist
1263 .Style(parameters->textclass,
1264 cursor.par->GetLayout()).alignpossible) {
1265 if (align == textclasslist
1266 .Style(parameters->textclass,
1267 cursor.par->GetLayout()).align)
1268 cursor.par->align = LYX_ALIGN_LAYOUT;
1270 cursor.par->align = align;
1272 cursor.par->SetLabelWidthString(labelwidthstring);
1273 cursor.par->noindent = noindent;
1276 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1279 RedoParagraphs(sel_start_cursor, endpar);
1282 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1283 sel_cursor = cursor;
1284 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1286 SetCursor(tmpcursor.par, tmpcursor.pos);
1290 void LyXText::SetParagraphExtraOpt(int type,
1292 char const * widthp,
1293 int alignment, bool hfill,
1294 bool start_minipage)
1296 LyXCursor tmpcursor = cursor;
1297 LyXParagraph * tmppar;
1299 sel_start_cursor = cursor;
1300 sel_end_cursor = cursor;
1303 // make sure that the depth behind the selection are restored, too
1304 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1305 LyXParagraph * undoendpar = endpar;
1307 if (endpar && endpar->GetDepth()) {
1308 while (endpar && endpar->GetDepth()) {
1309 endpar = endpar->LastPhysicalPar()->Next();
1310 undoendpar = endpar;
1314 endpar = endpar->Next(); // because of parindents etc.
1319 .par->ParFromPos(sel_start_cursor.pos)->previous,
1322 tmppar = sel_end_cursor.par;
1323 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1324 SetCursor(tmppar->FirstPhysicalPar(), 0);
1325 status = LyXText::NEED_MORE_REFRESH;
1326 refresh_row = cursor.row;
1327 refresh_y = cursor.y - cursor.row->baseline;
1328 if (cursor.par->footnoteflag ==
1329 sel_start_cursor.par->footnoteflag) {
1330 if (type == LyXParagraph::PEXTRA_NONE) {
1331 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1332 cursor.par->UnsetPExtraType();
1333 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1336 cursor.par->SetPExtraType(type, width, widthp);
1337 cursor.par->pextra_hfill = hfill;
1338 cursor.par->pextra_start_minipage = start_minipage;
1339 cursor.par->pextra_alignment = alignment;
1342 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1344 RedoParagraphs(sel_start_cursor, endpar);
1346 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1347 sel_cursor = cursor;
1348 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1350 SetCursor(tmpcursor.par, tmpcursor.pos);
1354 char loweralphaCounter(int n)
1356 if (n < 1 || n > 26)
1362 char alphaCounter(int n)
1364 if (n < 1 || n > 26)
1370 char hebrewCounter(int n)
1372 static const char hebrew[22] = {
1373 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1374 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1375 '÷', 'ø', 'ù', 'ú'
1377 if (n < 1 || n > 22)
1383 static char const * romanCounter(int n)
1385 static char const * roman[20] = {
1386 "i", "ii", "iii", "iv", "v",
1387 "vi", "vii", "viii", "ix", "x",
1388 "xi", "xii", "xiii", "xiv", "xv",
1389 "xvi", "xvii", "xviii", "xix", "xx"
1391 if (n < 1 || n > 20)
1397 // set the counter of a paragraph. This includes the labels
1398 void LyXText::SetCounter(LyXParagraph * par) const
1400 // this is only relevant for the beginning of paragraph
1401 par = par->FirstPhysicalPar();
1403 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1406 LyXTextClass const & textclass =
1407 textclasslist.TextClass(parameters->textclass);
1409 /* copy the prev-counters to this one, unless this is the start of a
1410 footnote or of a bibliography or the very first paragraph */
1412 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1413 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1414 && par->footnotekind == LyXParagraph::FOOTNOTE)
1415 && !(textclasslist.Style(parameters->textclass,
1416 par->Previous()->GetLayout()
1417 ).labeltype != LABEL_BIBLIO
1418 && layout.labeltype == LABEL_BIBLIO)) {
1419 for (int i = 0; i < 10; ++i) {
1420 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1422 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1423 if (!par->appendix && par->start_of_appendix){
1424 par->appendix = true;
1425 for (int i = 0; i < 10; ++i) {
1426 par->setCounter(i, 0);
1429 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1430 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1433 for (int i = 0; i < 10; ++i) {
1434 par->setCounter(i, 0);
1436 par->appendix = par->start_of_appendix;
1441 // if this is an open marginnote and this is the first
1442 // entry in the marginnote and the enclosing
1443 // environment is an enum/item then correct for the
1444 // LaTeX behaviour (ARRae)
1445 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1446 && par->footnotekind == LyXParagraph::MARGIN
1448 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1449 && (par->PreviousBeforeFootnote()
1450 && textclasslist.Style(parameters->textclass,
1451 par->PreviousBeforeFootnote()->GetLayout()
1452 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1453 // Any itemize or enumerate environment in a marginnote
1454 // that is embedded in an itemize or enumerate
1455 // paragraph is seen by LaTeX as being at a deeper
1456 // level within that enclosing itemization/enumeration
1457 // even if there is a "standard" layout at the start of
1463 /* Maybe we have to increment the enumeration depth.
1464 * BUT, enumeration in a footnote is considered in isolation from its
1465 * surrounding paragraph so don't increment if this is the
1466 * first line of the footnote
1467 * AND, bibliographies can't have their depth changed ie. they
1468 * are always of depth 0
1471 && par->Previous()->GetDepth() < par->GetDepth()
1472 && textclasslist.Style(parameters->textclass,
1473 par->Previous()->GetLayout()
1474 ).labeltype == LABEL_COUNTER_ENUMI
1475 && par->enumdepth < 3
1476 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1477 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1478 && par->footnotekind == LyXParagraph::FOOTNOTE)
1479 && layout.labeltype != LABEL_BIBLIO) {
1483 /* Maybe we have to decrement the enumeration depth, see note above */
1485 && par->Previous()->GetDepth() > par->GetDepth()
1486 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1487 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1488 && par->footnotekind == LyXParagraph::FOOTNOTE)
1489 && layout.labeltype != LABEL_BIBLIO) {
1490 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1491 par->setCounter(6 + par->enumdepth,
1492 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1493 /* reset the counters.
1494 * A depth change is like a breaking layout
1496 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1497 par->setCounter(i, 0);
1500 if (!par->labelstring.empty()) {
1501 par->labelstring.clear();
1504 if (layout.margintype == MARGIN_MANUAL) {
1505 if (par->labelwidthstring.empty()) {
1506 par->SetLabelWidthString(layout.labelstring());
1509 par->SetLabelWidthString(string());
1512 /* is it a layout that has an automatic label ? */
1513 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1515 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1516 if (i >= 0 && i<= parameters->secnumdepth) {
1517 par->incCounter(i); // increment the counter
1519 // Is there a label? Useful for Chapter layout
1520 if (!par->appendix){
1521 if (!layout.labelstring().empty())
1522 par->labelstring = layout.labelstring();
1524 par->labelstring.clear();
1526 if (!layout.labelstring_appendix().empty())
1527 par->labelstring = layout.labelstring_appendix();
1529 par->labelstring.clear();
1533 std::ostringstream s;
1537 if (!par->appendix) {
1538 switch (2 * LABEL_FIRST_COUNTER -
1539 textclass.maxcounter() + i) {
1540 case LABEL_COUNTER_CHAPTER:
1541 s << par->getCounter(i);
1543 case LABEL_COUNTER_SECTION:
1544 s << par->getCounter(i - 1) << '.'
1545 << par->getCounter(i);
1547 case LABEL_COUNTER_SUBSECTION:
1548 s << par->getCounter(i - 2) << '.'
1549 << par->getCounter(i - 1) << '.'
1550 << par->getCounter(i);
1552 case LABEL_COUNTER_SUBSUBSECTION:
1553 s << par->getCounter(i - 3) << '.'
1554 << par->getCounter(i - 2) << '.'
1555 << par->getCounter(i - 1) << '.'
1556 << par->getCounter(i);
1559 case LABEL_COUNTER_PARAGRAPH:
1560 s << par->getCounter(i - 4) << '.'
1561 << par->getCounter(i - 3) << '.'
1562 << par->getCounter(i - 2) << '.'
1563 << par->getCounter(i - 1) << '.'
1564 << par->getCounter(i);
1566 case LABEL_COUNTER_SUBPARAGRAPH:
1567 s << par->getCounter(i - 5) << '.'
1568 << par->getCounter(i - 4) << '.'
1569 << par->getCounter(i - 3) << '.'
1570 << par->getCounter(i - 2) << '.'
1571 << par->getCounter(i - 1) << '.'
1572 << par->getCounter(i);
1576 s << par->getCounter(i) << '.';
1579 } else { // appendix
1580 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1581 case LABEL_COUNTER_CHAPTER:
1582 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1583 s << alphaCounter(par->getCounter(i));
1585 s << hebrewCounter(par->getCounter(i));
1587 case LABEL_COUNTER_SECTION:
1588 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1589 s << alphaCounter(par->getCounter(i - 1));
1591 s << hebrewCounter(par->getCounter(i - 1));
1594 << par->getCounter(i);
1597 case LABEL_COUNTER_SUBSECTION:
1598 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1599 s << alphaCounter(par->getCounter(i - 2));
1601 s << hebrewCounter(par->getCounter(i - 2));
1604 << par->getCounter(i-1) << '.'
1605 << par->getCounter(i);
1608 case LABEL_COUNTER_SUBSUBSECTION:
1609 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1610 s << alphaCounter(par->getCounter(i-3));
1612 s << hebrewCounter(par->getCounter(i-3));
1615 << par->getCounter(i-2) << '.'
1616 << par->getCounter(i-1) << '.'
1617 << par->getCounter(i);
1620 case LABEL_COUNTER_PARAGRAPH:
1621 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1622 s << alphaCounter(par->getCounter(i-4));
1624 s << hebrewCounter(par->getCounter(i-4));
1627 << par->getCounter(i-3) << '.'
1628 << par->getCounter(i-2) << '.'
1629 << par->getCounter(i-1) << '.'
1630 << par->getCounter(i);
1633 case LABEL_COUNTER_SUBPARAGRAPH:
1634 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1635 s << alphaCounter(par->getCounter(i-5));
1637 s << hebrewCounter(par->getCounter(i-5));
1640 << par->getCounter(i-4) << '.'
1641 << par->getCounter(i-3) << '.'
1642 << par->getCounter(i-2) << '.'
1643 << par->getCounter(i-1) << '.'
1644 << par->getCounter(i);
1648 // Can this ever be reached? And in the
1649 // case it is, how can this be correct?
1651 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1657 par->labelstring += s.str().c_str();
1658 // We really want to remove the c_str as soon as
1662 char * tmps = s.str();
1663 par->labelstring += tmps;
1667 for (i++; i < 10; ++i) {
1668 // reset the following counters
1669 par->setCounter(i, 0);
1671 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1672 for (i++; i < 10; ++i) {
1673 // reset the following counters
1674 par->setCounter(i, 0);
1676 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1677 par->incCounter(i + par->enumdepth);
1678 int number = par->getCounter(i + par->enumdepth);
1681 std::ostringstream s;
1685 switch (par->enumdepth) {
1687 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1689 << loweralphaCounter(number)
1693 << hebrewCounter(number)
1697 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1698 s << romanCounter(number) << '.';
1700 s << '.' << romanCounter(number);
1703 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1704 s << alphaCounter(number)
1708 << alphaCounter(number);
1711 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1718 par->labelstring = s.str().c_str();
1719 // we really want to get rid of that c_str()
1722 char * tmps = s.str();
1723 par->labelstring = tmps;
1727 for (i += par->enumdepth + 1; i < 10; ++i)
1728 par->setCounter(i, 0); /* reset the following counters */
1731 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1732 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1734 int number = par->getCounter(i);
1736 par->bibkey = new InsetBibKey();
1737 par->bibkey->setCounter(number);
1738 par->labelstring = layout.labelstring();
1740 // In biblio should't be following counters but...
1742 string s = layout.labelstring();
1744 // the caption hack:
1746 if (layout.labeltype == LABEL_SENSITIVE) {
1747 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1748 && (par->footnotekind == LyXParagraph::FIG
1749 || par->footnotekind == LyXParagraph::WIDE_FIG))
1750 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1754 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1755 && (par->footnotekind == LyXParagraph::TAB
1756 || par->footnotekind == LyXParagraph::WIDE_TAB))
1757 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1761 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1762 && par->footnotekind == LyXParagraph::ALGORITHM)
1763 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1766 s = ":Ãúéøåâìà ";
1768 /* par->SetLayout(0);
1769 s = layout->labelstring; */
1770 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1773 s = " :úåòîùî øñç";
1777 par->labelstring = s;
1779 /* reset the enumeration counter. They are always resetted
1780 * when there is any other layout between */
1781 for (int i = 6 + par->enumdepth; i < 10; ++i)
1782 par->setCounter(i, 0);
1787 /* Updates all counters BEHIND the row. Changed paragraphs
1788 * with a dynamic left margin will be rebroken. */
1789 void LyXText::UpdateCounters(Row * row) const
1798 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1799 par = row->par->LastPhysicalPar()->Next();
1801 par = row->par->next;
1806 while (row->par != par)
1811 /* now check for the headline layouts. remember that they
1812 * have a dynamic left margin */
1814 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1815 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1818 /* Rebreak the paragraph */
1819 RemoveParagraph(row);
1820 AppendParagraph(row);
1822 /* think about the damned open footnotes! */
1823 while (par->Next() &&
1824 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1825 || par->Next()->IsDummy())){
1827 if (par->IsDummy()) {
1828 while (row->par != par)
1830 RemoveParagraph(row);
1831 AppendParagraph(row);
1836 par = par->LastPhysicalPar()->Next();
1842 /* insets an inset. */
1843 void LyXText::InsertInset(Inset *inset)
1845 SetUndo(Undo::INSERT,
1846 cursor.par->ParFromPos(cursor.pos)->previous,
1847 cursor.par->ParFromPos(cursor.pos)->next);
1848 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1849 cursor.par->InsertInset(cursor.pos, inset);
1850 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1851 * The character will not be inserted a
1856 // this is for the simple cut and paste mechanism
1857 static LyXParagraph * simple_cut_buffer = 0;
1858 static char simple_cut_buffer_textclass = 0;
1860 void DeleteSimpleCutBuffer()
1862 if (!simple_cut_buffer)
1864 LyXParagraph * tmppar;
1866 while (simple_cut_buffer) {
1867 tmppar = simple_cut_buffer;
1868 simple_cut_buffer = simple_cut_buffer->next;
1871 simple_cut_buffer = 0;
1875 void LyXText::copyEnvironmentType()
1877 copylayouttype = cursor.par->GetLayout();
1881 void LyXText::pasteEnvironmentType()
1883 SetLayout(copylayouttype);
1887 void LyXText::CutSelection(bool doclear)
1889 // This doesn't make sense, if there is no selection
1893 // OK, we have a selection. This is always between sel_start_cursor
1894 // and sel_end cursor
1895 LyXParagraph * tmppar;
1897 // Check whether there are half footnotes in the selection
1898 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1899 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1900 tmppar = sel_start_cursor.par;
1901 while (tmppar != sel_end_cursor.par){
1902 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1903 WriteAlert(_("Impossible operation"),
1904 _("Don't know what to do with half floats."),
1908 tmppar = tmppar->Next();
1912 /* table stuff -- begin */
1913 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1914 if ( sel_start_cursor.par != sel_end_cursor.par) {
1915 WriteAlert(_("Impossible operation"),
1916 _("Don't know what to do with half tables."),
1920 sel_start_cursor.par->table->Reinit();
1922 /* table stuff -- end */
1924 // make sure that the depth behind the selection are restored, too
1925 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1926 LyXParagraph * undoendpar = endpar;
1928 if (endpar && endpar->GetDepth()) {
1929 while (endpar && endpar->GetDepth()) {
1930 endpar = endpar->LastPhysicalPar()->Next();
1931 undoendpar = endpar;
1933 } else if (endpar) {
1934 endpar = endpar->Next(); // because of parindents etc.
1937 SetUndo(Undo::DELETE,
1939 .par->ParFromPos(sel_start_cursor.pos)->previous,
1942 // clear the simple_cut_buffer
1943 DeleteSimpleCutBuffer();
1945 // set the textclass
1946 simple_cut_buffer_textclass = parameters->textclass;
1948 #ifdef WITH_WARNINGS
1949 #warning Asger: Make cut more intelligent here.
1952 White paper for "intelligent" cutting:
1954 Example: "This is our text."
1955 Using " our " as selection, cutting will give "This istext.".
1956 Using "our" as selection, cutting will give "This is text.".
1957 Using " our" as selection, cutting will give "This is text.".
1958 Using "our " as selection, cutting will give "This is text.".
1960 All those four selections will (however) paste identically:
1961 Pasting with the cursor right after the "is" will give the
1962 original text with all four selections.
1964 The rationale is to be intelligent such that words are copied,
1965 cut and pasted in a functional manner.
1967 This is not implemented yet. (Asger)
1969 The changes below sees to do a lot of what you want. However
1970 I have not verified that all cases work as they should:
1972 - cut in multiple row
1974 - cut across footnotes and paragraph
1975 My simplistic tests show that the idea are basically sound but
1976 there are some items to fix up...we only need to find them
1979 As do redo Asger's example above (with | beeing the cursor in the
1980 result after cutting.):
1982 Example: "This is our text."
1983 Using " our " as selection, cutting will give "This is|text.".
1984 Using "our" as selection, cutting will give "This is | text.".
1985 Using " our" as selection, cutting will give "This is| text.".
1986 Using "our " as selection, cutting will give "This is |text.".
1991 #ifndef FIX_DOUBLE_SPACE
1992 bool space_wrapped =
1993 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1994 if (sel_end_cursor.pos > 0
1995 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1996 // please break before a space at the end
1997 sel_end_cursor.pos--;
1998 space_wrapped = true;
2000 // cut behind a space if there is one
2001 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2002 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2003 && (sel_start_cursor.par != sel_end_cursor.par
2004 || sel_start_cursor.pos < sel_end_cursor.pos))
2005 sel_start_cursor.pos++;
2007 // there are two cases: cut only within one paragraph or
2008 // more than one paragraph
2010 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2011 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2012 // only within one paragraph
2013 simple_cut_buffer = new LyXParagraph;
2014 LyXParagraph::size_type i =
2015 sel_start_cursor.pos;
2016 for (; i < sel_end_cursor.pos; ++i) {
2017 /* table stuff -- begin */
2018 if (sel_start_cursor.par->table
2019 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2020 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2021 sel_start_cursor.pos++;
2023 /* table stuff -- end */
2024 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2025 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2027 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2029 #ifndef FIX_DOUBLE_SPACE
2030 // check for double spaces
2031 if (sel_start_cursor.pos &&
2032 sel_start_cursor.par->Last() > sel_start_cursor.pos
2033 && sel_start_cursor.par
2034 ->IsLineSeparator(sel_start_cursor.pos - 1)
2035 && sel_start_cursor.par
2036 ->IsLineSeparator(sel_start_cursor.pos)) {
2037 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2040 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
2043 endpar = sel_end_cursor.par->Next();
2045 // cut more than one paragraph
2048 ->BreakParagraphConservative(sel_end_cursor.pos);
2049 #ifndef FIX_DOUBLE_SPACE
2050 // insert a space at the end if there was one
2053 ->InsertChar(sel_end_cursor.par->Last(), ' ');
2055 sel_end_cursor.par = sel_end_cursor.par->Next();
2056 sel_end_cursor.pos = 0;
2058 cursor = sel_end_cursor;
2060 #ifndef FIX_DOUBLE_SPACE
2061 // please break behind a space, if there is one.
2062 // The space should be copied too
2063 if (sel_start_cursor.par
2064 ->IsLineSeparator(sel_start_cursor.pos))
2065 sel_start_cursor.pos++;
2067 sel_start_cursor.par
2068 ->BreakParagraphConservative(sel_start_cursor.pos);
2069 #ifndef FIX_DOUBLE_SPACE
2070 if (!sel_start_cursor.pos
2071 || sel_start_cursor.par
2072 ->IsLineSeparator(sel_start_cursor.pos - 1)
2073 || sel_start_cursor.par
2074 ->IsNewline(sel_start_cursor.pos - 1)) {
2075 sel_start_cursor.par->Next()->InsertChar(0, ' ');
2078 // store the endparagraph for redoing later
2079 endpar = sel_end_cursor.par->Next(); /* needed because
2084 // store the selection
2085 simple_cut_buffer = sel_start_cursor.par
2086 ->ParFromPos(sel_start_cursor.pos)->next;
2087 simple_cut_buffer->previous = 0;
2088 sel_end_cursor.par->previous->next = 0;
2090 // cut the selection
2091 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2092 = sel_end_cursor.par;
2094 sel_end_cursor.par->previous
2095 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2097 // care about footnotes
2098 if (simple_cut_buffer->footnoteflag) {
2099 LyXParagraph * tmppar = simple_cut_buffer;
2101 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2102 tmppar = tmppar->next;
2106 // the cut selection should begin with standard layout
2107 simple_cut_buffer->Clear();
2109 // paste the paragraphs again, if possible
2111 sel_start_cursor.par->Next()->ClearParagraph();
2112 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2114 !sel_start_cursor.par->Next()->Last())
2115 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2117 #ifndef FIX_DOUBLE_SPACE
2118 // maybe a forgotten blank
2119 if (sel_start_cursor.pos
2120 && sel_start_cursor.par
2121 ->IsLineSeparator(sel_start_cursor.pos)
2122 && sel_start_cursor.par
2123 ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2124 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2129 // sometimes necessary
2131 sel_start_cursor.par->ClearParagraph();
2133 RedoParagraphs(sel_start_cursor, endpar);
2136 cursor = sel_start_cursor;
2137 SetCursor(cursor.par, cursor.pos);
2138 sel_cursor = cursor;
2139 UpdateCounters(cursor.row);
2143 void LyXText::CopySelection()
2145 // this doesnt make sense, if there is no selection
2149 // ok we have a selection. This is always between sel_start_cursor
2150 // and sel_end cursor
2151 LyXParagraph * tmppar;
2153 /* check wether there are half footnotes in the selection */
2154 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2155 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2156 tmppar = sel_start_cursor.par;
2157 while (tmppar != sel_end_cursor.par) {
2158 if (tmppar->footnoteflag !=
2159 sel_end_cursor.par->footnoteflag) {
2160 WriteAlert(_("Impossible operation"),
2161 _("Don't know what to do"
2162 " with half floats."),
2166 tmppar = tmppar->Next();
2170 /* table stuff -- begin */
2171 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2172 if ( sel_start_cursor.par != sel_end_cursor.par){
2173 WriteAlert(_("Impossible operation"),
2174 _("Don't know what to do with half tables."),
2179 /* table stuff -- end */
2181 // delete the simple_cut_buffer
2182 DeleteSimpleCutBuffer();
2184 // set the textclass
2185 simple_cut_buffer_textclass = parameters->textclass;
2187 #ifdef FIX_DOUBLE_SPACE
2188 // copy behind a space if there is one
2189 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2190 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2191 && (sel_start_cursor.par != sel_end_cursor.par
2192 || sel_start_cursor.pos < sel_end_cursor.pos))
2193 sel_start_cursor.pos++;
2195 // there are two cases: copy only within one paragraph
2196 // or more than one paragraph
2197 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2198 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2199 // only within one paragraph
2200 simple_cut_buffer = new LyXParagraph;
2201 LyXParagraph::size_type i = 0;
2202 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2203 sel_start_cursor.par->CopyIntoMinibuffer(i);
2204 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2207 // copy more than one paragraph
2208 // clone the paragraphs within the selection
2210 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2211 simple_cut_buffer = tmppar->Clone();
2212 LyXParagraph *tmppar2 = simple_cut_buffer;
2214 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2216 tmppar = tmppar->next;
2217 tmppar2->next = tmppar->Clone();
2218 tmppar2->next->previous = tmppar2;
2219 tmppar2 = tmppar2->next;
2223 // care about footnotes
2224 if (simple_cut_buffer->footnoteflag) {
2225 tmppar = simple_cut_buffer;
2227 tmppar->footnoteflag =
2228 LyXParagraph::NO_FOOTNOTE;
2229 tmppar = tmppar->next;
2233 // the simple_cut_buffer paragraph is too big
2234 LyXParagraph::size_type tmpi2 =
2235 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2236 for (; tmpi2; --tmpi2)
2237 simple_cut_buffer->Erase(0);
2239 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2241 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2242 while (tmppar2->size() > tmpi2) {
2243 tmppar2->Erase(tmppar2->size() - 1);
2249 void LyXText::PasteSelection()
2251 // this does not make sense, if there is nothing to paste
2252 if (!simple_cut_buffer)
2255 LyXParagraph * tmppar;
2256 LyXParagraph * endpar;
2258 LyXCursor tmpcursor;
2260 // be carefull with footnotes in footnotes
2261 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2263 // check whether the cut_buffer includes a footnote
2264 tmppar = simple_cut_buffer;
2266 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2267 tmppar = tmppar->next;
2270 WriteAlert(_("Impossible operation"),
2271 _("Can't paste float into float!"),
2277 /* table stuff -- begin */
2278 if (cursor.par->table) {
2279 if (simple_cut_buffer->next) {
2280 WriteAlert(_("Impossible operation"),
2281 _("Table cell cannot include more than one paragraph!"),
2286 /* table stuff -- end */
2288 SetUndo(Undo::INSERT,
2289 cursor.par->ParFromPos(cursor.pos)->previous,
2290 cursor.par->ParFromPos(cursor.pos)->next);
2294 // There are two cases: cutbuffer only one paragraph or many
2295 if (!simple_cut_buffer->next) {
2296 // only within a paragraph
2298 #ifndef FIX_DOUBLE_SPACE
2299 // please break behind a space, if there is one
2300 while (tmpcursor.par->Last() > tmpcursor.pos
2301 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2304 tmppar = simple_cut_buffer->Clone();
2305 /* table stuff -- begin */
2306 bool table_too_small = false;
2307 if (tmpcursor.par->table) {
2308 while (simple_cut_buffer->size()
2309 && !table_too_small) {
2310 if (simple_cut_buffer->IsNewline(0)){
2311 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2313 simple_cut_buffer->Erase(0);
2314 if (tmpcursor.pos < tmpcursor.par->Last())
2317 table_too_small = true;
2319 #ifdef FIX_DOUBLE_SPACE
2320 // This is an attempt to fix the
2321 // "never insert a space at the
2322 // beginning of a paragraph" problem.
2323 if (tmpcursor.pos == 0
2324 && simple_cut_buffer->IsLineSeparator(0)) {
2325 simple_cut_buffer->Erase(0);
2327 simple_cut_buffer->CutIntoMinibuffer(0);
2328 simple_cut_buffer->Erase(0);
2329 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2333 simple_cut_buffer->CutIntoMinibuffer(0);
2334 simple_cut_buffer->Erase(0);
2335 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2341 /* table stuff -- end */
2342 // Some provisions should be done here for checking
2343 // if we are inserting at the beginning of a
2344 // paragraph. If there are a space at the beginning
2345 // of the text to insert and we are inserting at
2346 // the beginning of the paragraph the space should
2348 while (simple_cut_buffer->size()) {
2349 #ifdef FIX_DOUBLE_SPACE
2350 // This is an attempt to fix the
2351 // "never insert a space at the
2352 // beginning of a paragraph" problem.
2353 if (tmpcursor.pos == 0
2354 && simple_cut_buffer->IsLineSeparator(0)) {
2355 simple_cut_buffer->Erase(0);
2357 simple_cut_buffer->CutIntoMinibuffer(0);
2358 simple_cut_buffer->Erase(0);
2359 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2363 simple_cut_buffer->CutIntoMinibuffer(0);
2364 simple_cut_buffer->Erase(0);
2365 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2370 delete simple_cut_buffer;
2371 simple_cut_buffer = tmppar;
2372 endpar = tmpcursor.par->Next();
2376 // make a copy of the simple cut_buffer
2377 tmppar = simple_cut_buffer;
2378 LyXParagraph * simple_cut_clone = tmppar->Clone();
2379 LyXParagraph * tmppar2 = simple_cut_clone;
2380 if (cursor.par->footnoteflag){
2381 tmppar->footnoteflag = cursor.par->footnoteflag;
2382 tmppar->footnotekind = cursor.par->footnotekind;
2384 while (tmppar->next) {
2385 tmppar = tmppar->next;
2386 tmppar2->next = tmppar->Clone();
2387 tmppar2->next->previous = tmppar2;
2388 tmppar2 = tmppar2->next;
2389 if (cursor.par->footnoteflag){
2390 tmppar->footnoteflag = cursor.par->footnoteflag;
2391 tmppar->footnotekind = cursor.par->footnotekind;
2395 // make sure there is no class difference
2396 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2397 parameters->textclass,
2400 // make the simple_cut_buffer exactly the same layout than
2401 // the cursor paragraph
2402 simple_cut_buffer->MakeSameLayout(cursor.par);
2404 // find the end of the buffer
2405 LyXParagraph * lastbuffer = simple_cut_buffer;
2406 while (lastbuffer->Next())
2407 lastbuffer = lastbuffer->Next();
2409 #ifndef FIX_DOUBLE_SPACE
2410 // Please break behind a space, if there is one. The space
2411 // should be copied too.
2412 if (cursor.par->Last() > cursor.pos
2413 && cursor.par->IsLineSeparator(cursor.pos))
2416 bool paste_the_end = false;
2418 // open the paragraph for inserting the simple_cut_buffer
2420 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2421 cursor.par->BreakParagraphConservative(cursor.pos);
2422 paste_the_end = true;
2425 #ifndef FIX_DOUBLE_SPACE
2426 // be careful with double spaces
2427 if ((!cursor.par->Last()
2428 || cursor.par->IsLineSeparator(cursor.pos - 1)
2429 || cursor.par->IsNewline(cursor.pos - 1))
2430 && simple_cut_buffer->text.size()
2431 && simple_cut_buffer->IsLineSeparator(0))
2432 simple_cut_buffer->Erase(0);
2434 // set the end for redoing later
2435 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2438 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2439 cursor.par->ParFromPos(cursor.pos)->next;
2440 cursor.par->ParFromPos(cursor.pos)->next->previous =
2441 lastbuffer->ParFromPos(lastbuffer->Last());
2443 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2444 simple_cut_buffer->previous =
2445 cursor.par->ParFromPos(cursor.pos);
2447 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2448 lastbuffer = cursor.par;
2450 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2452 // store the new cursor position
2453 tmpcursor.par = lastbuffer;
2454 tmpcursor.pos = lastbuffer->Last();
2456 // maybe some pasting
2457 if (lastbuffer->Next() && paste_the_end) {
2458 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2459 #ifndef FIX_DOUBLE_SPACE
2460 // be careful with double spaces
2461 if ((!lastbuffer->Last()
2462 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2463 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2464 && lastbuffer->Next()->Last()
2465 && lastbuffer->Next()->IsLineSeparator(0))
2466 lastbuffer->Next()->Erase(0);
2468 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2470 } else if (!lastbuffer->Next()->Last()) {
2471 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2472 #ifndef FIX_DOUBLE_SPACE
2473 // be careful witth double spaces
2474 if ((!lastbuffer->Last()
2475 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2476 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2477 && lastbuffer->Next()->Last()
2478 && lastbuffer->Next()->IsLineSeparator(0))
2479 lastbuffer->Next()->Erase(0);
2481 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2483 } else if (!lastbuffer->Last()) {
2484 lastbuffer->MakeSameLayout(lastbuffer->next);
2485 #ifndef FIX_DOUBLE_SPACE
2486 // be careful witth double spaces
2487 if ((!lastbuffer->Last()
2488 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2489 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2490 && lastbuffer->Next()->Last()
2491 && lastbuffer->Next()->IsLineSeparator(0))
2492 lastbuffer->Next()->Erase(0);
2494 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2497 lastbuffer->Next()->ClearParagraph();
2500 // restore the simple cut buffer
2501 simple_cut_buffer = simple_cut_clone;
2504 RedoParagraphs(cursor, endpar);
2506 SetCursor(cursor.par, cursor.pos);
2509 sel_cursor = cursor;
2510 SetCursor(tmpcursor.par, tmpcursor.pos);
2512 UpdateCounters(cursor.row);
2516 // returns a pointer to the very first LyXParagraph
2517 LyXParagraph * LyXText::FirstParagraph() const
2519 return params->paragraph;
2523 // returns true if the specified string is at the specified position
2524 bool LyXText::IsStringInText(LyXParagraph * par,
2525 LyXParagraph::size_type pos,
2526 char const * str) const
2530 while (pos + i < par->Last() && str[i] &&
2531 str[i] == par->GetChar(pos + i)) {
2541 // sets the selection over the number of characters of string, no check!!
2542 void LyXText::SetSelectionOverString(char const * string)
2544 sel_cursor = cursor;
2545 for (int i = 0; string[i]; ++i)
2551 // simple replacing. The font of the first selected character is used
2552 void LyXText::ReplaceSelectionWithString(char const * str)
2557 if (!selection) { // create a dummy selection
2558 sel_end_cursor = cursor;
2559 sel_start_cursor = cursor;
2562 // Get font setting before we cut
2563 LyXParagraph::size_type pos = sel_end_cursor.pos;
2564 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2566 // Insert the new string
2567 for (int i = 0; str[i]; ++i) {
2568 sel_end_cursor.par->InsertChar(pos, str[i]);
2569 sel_end_cursor.par->SetFont(pos, font);
2573 // Cut the selection
2580 // if the string can be found: return true and set the cursor to
2582 bool LyXText::SearchForward(char const * str) const
2584 LyXParagraph * par = cursor.par;
2585 LyXParagraph::size_type pos = cursor.pos;
2586 while (par && !IsStringInText(par, pos, str)) {
2587 if (pos < par->Last() - 1)
2595 SetCursor(par, pos);
2603 bool LyXText::SearchBackward(char const * string) const
2605 LyXParagraph * par = cursor.par;
2606 int pos = cursor.pos;
2612 // We skip empty paragraphs (Asger)
2614 par = par->Previous();
2616 pos = par->Last() - 1;
2617 } while (par && pos < 0);
2619 } while (par && !IsStringInText(par, pos, string));
2622 SetCursor(par, pos);
2629 // needed to insert the selection
2630 void LyXText::InsertStringA(string const & str)
2632 LyXParagraph * par = cursor.par;
2633 LyXParagraph::size_type pos = cursor.pos;
2634 LyXParagraph::size_type a = 0;
2636 LyXParagraph * endpar = cursor.par->Next();
2641 textclasslist.Style(parameters->textclass,
2642 cursor.par->GetLayout()).isEnvironment();
2643 // only to be sure, should not be neccessary
2646 // insert the string, don't insert doublespace
2647 string::size_type i = 0;
2648 while (i < str.length()) {
2649 if (str[i] != '\n') {
2651 && i + 1 < str.length() && str[i + 1] != ' '
2652 && pos && par->GetChar(pos - 1)!= ' ') {
2653 par->InsertChar(pos,' ');
2654 par->SetFont(pos, current_font);
2656 } else if (par->table) {
2657 if (str[i] == '\t') {
2658 while((pos < par->size()) &&
2659 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2661 if (pos < par->size())
2663 else // no more fields to fill skip the rest
2665 } else if ((str[i] != 13) &&
2666 ((str[i] & 127) >= ' ')) {
2667 par->InsertChar(pos, str[i]);
2668 par->SetFont(pos, current_font);
2671 } else if (str[i] == ' ') {
2673 InsetSpecialChar * new_inset =
2674 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2675 par->InsertChar(pos, LyXParagraph::META_INSET);
2676 par->SetFont(pos, current_font);
2677 par->InsertInset(pos, new_inset);
2679 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2680 par->SetFont(pos, current_font);
2683 } else if (str[i] == '\t') {
2684 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2686 InsetSpecialChar * new_inset =
2687 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2688 par->InsertChar(pos, LyXParagraph::META_INSET);
2689 par->SetFont(pos, current_font);
2690 par->InsertInset(pos, new_inset);
2692 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2693 par->SetFont(a, current_font);
2697 } else if (str[i] != 13 &&
2698 // Ignore unprintables
2699 (str[i] & 127) >= ' ') {
2700 par->InsertChar(pos, str[i]);
2701 par->SetFont(pos, current_font);
2706 if (i + 1 >= str.length()) {
2710 while((pos < par->size()) &&
2711 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2714 cell = NumberOfCell(par, pos);
2715 while((pos < par->size()) &&
2716 !(par->table->IsFirstCell(cell))) {
2718 while((pos < par->size()) &&
2719 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2722 cell = NumberOfCell(par, pos);
2724 if (pos >= par->size())
2725 // no more fields to fill skip the rest
2728 if (!par->size()) { // par is empty
2730 InsetSpecialChar * new_inset =
2731 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2732 par->InsertChar(pos, LyXParagraph::META_INSET);
2733 par->SetFont(pos, current_font);
2734 par->InsertInset(pos, new_inset);
2736 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2737 par->SetFont(pos, current_font);
2741 par->BreakParagraph(pos, flag);
2749 RedoParagraphs(cursor, endpar);
2750 SetCursor(cursor.par, cursor.pos);
2751 sel_cursor = cursor;
2752 SetCursor(par, pos);
2757 /* turns double-CR to single CR, others where converted into one blank and 13s
2758 * that are ignored .Double spaces are also converted into one. Spaces at
2759 * the beginning of a paragraph are forbidden. tabs are converted into one
2760 * space. then InsertStringA is called */
2761 void LyXText::InsertStringB(string const & s)
2764 LyXParagraph * par = cursor.par;
2765 string::size_type i = 1;
2766 while (i < str.length()) {
2767 if (str[i] == '\t' && !par->table)
2769 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2771 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2772 if (str[i + 1] != '\n') {
2773 if (str[i - 1] != ' ')
2778 while (i + 1 < str.length()
2779 && (str[i + 1] == ' '
2780 || str[i + 1] == '\t'
2781 || str[i + 1] == '\n'
2782 || str[i + 1] == 13)) {
2793 bool LyXText::GotoNextError() const
2795 LyXCursor res = cursor;
2797 if (res.pos < res.par->Last() - 1) {
2801 res.par = res.par->Next();
2806 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2807 && res.par->GetInset(res.pos)->AutoDelete()));
2810 SetCursor(res.par, res.pos);
2817 bool LyXText::GotoNextNote() const
2819 LyXCursor res = cursor;
2821 if (res.pos < res.par->Last() - 1) {
2824 res.par = res.par->Next();
2829 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2830 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2833 SetCursor(res.par, res.pos);
2840 int LyXText::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type class1,
2841 LyXTextClassList::size_type class2,
2845 if (!par || class1 == class2)
2847 par = par->FirstPhysicalPar();
2849 string name = textclasslist.NameOfLayout(class1, par->layout);
2851 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2852 textclasslist.NumberOfLayout(class2, name);
2855 } else { // layout not found
2856 // use default layout "Standard" (0)
2861 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2863 string s = "Layout had to be changed from\n"
2864 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2865 + "\nbecause of class conversion from\n"
2866 + textclasslist.NameOfClass(class1) + " to "
2867 + textclasslist.NameOfClass(class2);
2868 InsetError * new_inset = new InsetError(s);
2869 par->InsertChar(0, LyXParagraph::META_INSET);
2870 par->InsertInset(0, new_inset);
2879 void LyXText::CheckParagraph(LyXParagraph * par,
2880 LyXParagraph::size_type pos)
2883 LyXCursor tmpcursor;
2885 /* table stuff -- begin*/
2888 CheckParagraphInTable(par, pos);
2891 /* table stuff -- end*/
2894 LyXParagraph::size_type z;
2895 Row * row = GetRow(par, pos, y);
2897 // is there a break one row above
2898 if (row->previous && row->previous->par == row->par) {
2899 z = NextBreakPoint(row->previous, paperwidth);
2900 if ( z >= row->pos) {
2901 // set the dimensions of the row above
2902 y -= row->previous->height;
2904 refresh_row = row->previous;
2905 status = LyXText::NEED_MORE_REFRESH;
2907 BreakAgain(row->previous);
2909 // set the cursor again. Otherwise
2910 // dangling pointers are possible
2911 SetCursor(cursor.par, cursor.pos);
2912 sel_cursor = cursor;
2917 int tmpheight = row->height;
2918 LyXParagraph::size_type tmplast = RowLast(row);
2923 if (row->height == tmpheight && RowLast(row) == tmplast)
2924 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2926 status = LyXText::NEED_MORE_REFRESH;
2928 // check the special right address boxes
2929 if (textclasslist.Style(parameters->textclass,
2930 par->GetLayout()).margintype
2931 == MARGIN_RIGHT_ADDRESS_BOX) {
2932 tmpcursor.par = par;
2933 tmpcursor.row = row;
2936 tmpcursor.x_fix = 0;
2937 tmpcursor.pos = pos;
2938 RedoDrawingOfParagraph(tmpcursor);
2943 // set the cursor again. Otherwise dangling pointers are possible
2944 // also set the selection
2948 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2949 sel_cursor = cursor;
2950 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2951 sel_start_cursor = cursor;
2952 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2953 sel_end_cursor = cursor;
2954 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2955 last_sel_cursor = cursor;
2958 SetCursorIntern(cursor.par, cursor.pos);
2962 // returns 0 if inset wasn't found
2963 int LyXText::UpdateInset(Inset * inset)
2965 // first check the current paragraph
2966 int pos = cursor.par->GetPositionOfInset(inset);
2968 CheckParagraph(cursor.par, pos);
2972 // check every paragraph
2974 LyXParagraph * par = FirstParagraph();
2976 // make sure the paragraph is open
2977 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2978 pos = par->GetPositionOfInset(inset);
2980 CheckParagraph(par, pos);
2991 void LyXText::SetCursor(LyXParagraph * par,
2992 LyXParagraph::size_type pos, bool setfont) const
2994 LyXCursor old_cursor = cursor;
2995 SetCursorIntern(par, pos, setfont);
2996 DeleteEmptyParagraphMechanism(old_cursor);
3000 void LyXText::SetCursorIntern(LyXParagraph * par,
3001 LyXParagraph::size_type pos, bool setfont) const
3003 // correct the cursor position if impossible
3004 if (pos > par->Last()){
3005 LyXParagraph * tmppar = par->ParFromPos(pos);
3006 pos = par->PositionInParFromPos(pos);
3009 if (par->IsDummy() && par->previous &&
3010 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3011 while (par->previous &&
3012 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3013 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3014 par = par->previous ;
3015 if (par->IsDummy() &&
3016 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3017 pos += par->size() + 1;
3019 if (par->previous) {
3020 par = par->previous;
3022 pos += par->size() + 1;
3030 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3031 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3032 && !cursor.par->IsSeparator(cursor.pos))
3033 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3035 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3036 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3038 current_font = cursor.par->GetFontSettings(cursor.pos);
3039 real_current_font = GetFont(cursor.par, cursor.pos);
3042 /* get the cursor y position in text */
3044 Row * row = GetRow(par, pos, y);
3045 /* y is now the beginning of the cursor row */
3047 /* y is now the cursor baseline */
3050 /* now get the cursors x position */
3052 float fill_separator, fill_hfill, fill_label_hfill;
3053 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3054 LyXParagraph::size_type cursor_vpos;
3055 LyXParagraph::size_type last = RowLast(row);
3056 if (row->pos > last)
3058 else if (pos > last)
3059 cursor_vpos = (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
3060 ? log2vis(last)+1 : log2vis(last);
3062 LyXDirection letter_direction =
3063 row->par->getLetterDirection(pos);
3064 LyXDirection font_direction =
3065 (real_current_font.isVisibleRightToLeft())
3066 ? LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
3067 if (letter_direction == font_direction
3069 || (row->par->table && row->par->IsNewline(pos-1)))
3070 cursor_vpos = (letter_direction == LYX_DIR_LEFT_TO_RIGHT)
3071 ? log2vis(pos) : log2vis(pos) + 1;
3073 cursor_vpos = (font_direction == LYX_DIR_LEFT_TO_RIGHT)
3074 ? log2vis(pos-1) + 1 : log2vis(pos - 1);
3077 /* table stuff -- begin*/
3078 if (row->par->table) {
3079 int cell = NumberOfCell(row->par, row->pos);
3081 x += row->par->table->GetBeginningOfTextInCell(cell);
3082 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3083 pos = vis2log(vpos);
3084 if (row->par->IsNewline(pos)) {
3085 x = x_old + row->par->table->WidthOfColumn(cell);
3088 x += row->par->table->GetBeginningOfTextInCell(cell);
3090 x += SingleWidth(row->par, pos);
3094 /* table stuff -- end*/
3095 LyXParagraph::size_type main_body =
3096 BeginningOfMainBody(row->par);
3097 if (main_body > 0 &&
3098 (main_body-1 > last ||
3099 !row->par->IsLineSeparator(main_body-1)))
3102 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3103 pos = vis2log(vpos);
3104 if (main_body > 0 && pos == main_body-1) {
3105 x += fill_label_hfill +
3106 lyxfont::width(textclasslist
3107 .Style(parameters->textclass,
3108 row->par->GetLayout())
3110 GetFont(row->par, -2));
3111 if (row->par->IsLineSeparator(main_body-1))
3112 x -= SingleWidth(row->par, main_body-1);
3114 if (HfillExpansion(row, pos)) {
3115 x += SingleWidth(row->par, pos);
3116 if (pos >= main_body)
3119 x += fill_label_hfill;
3121 else if (row->par->IsSeparator(pos)) {
3124 row->next->par != row->par ||
3125 row->par->getParDirection() ==
3126 row->par->getLetterDirection(last)) {
3127 x += SingleWidth(row->par, pos);
3128 if (pos >= main_body)
3129 x += fill_separator;
3132 x += SingleWidth(row->par, pos);
3138 cursor.x_fix = cursor.x;
3143 void LyXText::SetCursorFromCoordinates(int x, long y) const
3145 LyXCursor old_cursor = cursor;
3147 /* get the row first */
3149 Row * row = GetRowNearY(y);
3151 cursor.par = row->par;
3153 int column = GetColumnNearX(row, x);
3154 cursor.pos = row->pos + column;
3156 cursor.y = y + row->baseline;
3161 (cursor.pos == cursor.par->Last()
3162 || cursor.par->IsSeparator(cursor.pos)
3163 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3164 && !cursor.par->IsSeparator(cursor.pos))
3165 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3167 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3168 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3170 current_font = cursor.par->GetFontSettings(cursor.pos);
3171 real_current_font = GetFont(cursor.par, cursor.pos);
3173 DeleteEmptyParagraphMechanism(old_cursor);
3176 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3178 /* get the row first */
3180 Row * row = GetRowNearY(y);
3181 int column = GetColumnNearX(row, x);
3184 cur.pos = row->pos + column;
3186 cur.y = y + row->baseline;
3191 void LyXText::CursorLeft() const
3194 if (cursor.par->table) {
3195 int cell = NumberOfCell(cursor.par, cursor.pos);
3196 if (cursor.par->table->IsContRow(cell) &&
3197 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3204 void LyXText::CursorLeftIntern() const
3206 if (cursor.pos > 0) {
3207 SetCursor(cursor.par, cursor.pos - 1);
3209 else if (cursor.par->Previous()) { // steps into the above paragraph.
3210 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3215 void LyXText::CursorRight() const
3217 CursorRightIntern();
3218 if (cursor.par->table) {
3219 int cell = NumberOfCell(cursor.par, cursor.pos);
3220 if (cursor.par->table->IsContRow(cell) &&
3221 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3228 void LyXText::CursorRightIntern() const
3230 if (cursor.pos < cursor.par->Last()) {
3231 SetCursor(cursor.par, cursor.pos + 1);
3233 else if (cursor.par->Next()) {
3234 SetCursor(cursor.par->Next(), 0);
3239 void LyXText::CursorUp() const
3241 SetCursorFromCoordinates(cursor.x_fix,
3242 cursor.y - cursor.row->baseline - 1);
3243 if (cursor.par->table) {
3244 int cell = NumberOfCell(cursor.par, cursor.pos);
3245 if (cursor.par->table->IsContRow(cell) &&
3246 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3253 void LyXText::CursorDown() const
3255 if (cursor.par->table &&
3256 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3259 SetCursorFromCoordinates(cursor.x_fix,
3260 cursor.y - cursor.row->baseline
3261 + cursor.row->height + 1);
3262 if (cursor.par->table) {
3263 int cell = NumberOfCell(cursor.par, cursor.pos);
3264 int cell_above = cursor.par->table->GetCellAbove(cell);
3265 while(cursor.par->table &&
3266 cursor.par->table->IsContRow(cell) &&
3267 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3268 SetCursorFromCoordinates(cursor.x_fix,
3269 cursor.y - cursor.row->baseline
3270 + cursor.row->height + 1);
3271 if (cursor.par->table) {
3272 cell = NumberOfCell(cursor.par, cursor.pos);
3273 cell_above = cursor.par->table->GetCellAbove(cell);
3280 void LyXText::CursorUpParagraph() const
3282 if (cursor.pos > 0) {
3283 SetCursor(cursor.par, 0);
3285 else if (cursor.par->Previous()) {
3286 SetCursor(cursor.par->Previous(), 0);
3291 void LyXText::CursorDownParagraph() const
3293 if (cursor.par->Next()) {
3294 SetCursor(cursor.par->Next(), 0);
3296 SetCursor(cursor.par, cursor.par->Last());
3302 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3304 // Would be wrong to delete anything if we have a selection.
3305 if (selection) return;
3307 // We allow all kinds of "mumbo-jumbo" when freespacing.
3308 if (textclasslist.Style(parameters->textclass,
3309 old_cursor.par->GetLayout()).free_spacing)
3312 bool deleted = false;
3314 #ifdef FIX_DOUBLE_SPACE
3315 /* Ok I'll put some comments here about what is missing.
3316 I have fixed BackSpace (and thus Delete) to not delete
3317 double-spaces automagically. I have also changed Cut,
3318 Copy and Paste to hopefully do some sensible things.
3319 There are still some small problems that can lead to
3320 double spaces stored in the document file or space at
3321 the beginning of paragraphs. This happens if you have
3322 the cursor betwenn to spaces and then save. Or if you
3323 cut and paste and the selection have a space at the
3324 beginning and then save right after the paste. I am
3325 sure none of these are very hard to fix, but I will
3326 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3327 that I can get some feedback. (Lgb)
3330 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3331 // delete the LineSeparator.
3334 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3335 // delete the LineSeparator.
3338 // If the pos around the old_cursor were spaces, delete one of them.
3339 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3341 if (old_cursor.pos > 0
3342 && old_cursor.pos < old_cursor.par->Last()
3343 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3344 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3345 old_cursor.par->Erase(old_cursor.pos - 1);
3346 status = LyXText::NEED_MORE_REFRESH;
3348 if (old_cursor.par == cursor.par &&
3349 cursor.pos > old_cursor.pos) {
3350 //SetCursor(cursor.par, cursor.pos - 1);
3353 // SetCursor(cursor.par, cursor.pos);
3359 // Do not delete empty paragraphs with keepempty set.
3360 if ((textclasslist.Style(parameters->textclass,
3361 old_cursor.par->GetLayout())).keepempty)
3364 LyXCursor tmpcursor;
3366 if (old_cursor.par != cursor.par) {
3367 if ( (old_cursor.par->Last() == 0
3368 || (old_cursor.par->Last() == 1
3369 && old_cursor.par->IsLineSeparator(0)))
3370 && old_cursor.par->FirstPhysicalPar()
3371 == old_cursor.par->LastPhysicalPar()) {
3372 // ok, we will delete anything
3374 // make sure that you do not delete any environments
3375 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3376 !(old_cursor.row->previous
3377 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3378 && !(old_cursor.row->next
3379 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3380 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3381 && ((old_cursor.row->previous
3382 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3383 || (old_cursor.row->next
3384 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3386 status = LyXText::NEED_MORE_REFRESH;
3389 if (old_cursor.row->previous) {
3390 refresh_row = old_cursor.row->previous;
3391 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3393 cursor = old_cursor; // that undo can restore the right cursor position
3394 LyXParagraph * endpar = old_cursor.par->next;
3395 if (endpar && endpar->GetDepth()) {
3396 while (endpar && endpar->GetDepth()) {
3397 endpar = endpar->LastPhysicalPar()->Next();
3400 SetUndo(Undo::DELETE,
3401 old_cursor.par->previous,
3406 RemoveRow(old_cursor.row);
3407 if (params->paragraph == old_cursor.par) {
3408 params->paragraph = params->paragraph->next;
3411 delete old_cursor.par;
3413 /* Breakagain the next par. Needed
3414 * because of the parindent that
3415 * can occur or dissappear. The
3416 * next row can change its height,
3417 * if there is another layout before */
3418 if (refresh_row->next) {
3419 BreakAgain(refresh_row->next);
3420 UpdateCounters(refresh_row);
3422 SetHeightOfRow(refresh_row);
3424 refresh_row = old_cursor.row->next;
3425 refresh_y = old_cursor.y - old_cursor.row->baseline;
3428 cursor = old_cursor; // that undo can restore the right cursor position
3429 LyXParagraph *endpar = old_cursor.par->next;
3430 if (endpar && endpar->GetDepth()) {
3431 while (endpar && endpar->GetDepth()) {
3432 endpar = endpar->LastPhysicalPar()->Next();
3435 SetUndo(Undo::DELETE,
3436 old_cursor.par->previous,
3441 RemoveRow(old_cursor.row);
3443 if (params->paragraph == old_cursor.par) {
3444 params->paragraph = params->paragraph->next;
3446 delete old_cursor.par;
3448 /* Breakagain the next par. Needed
3449 because of the parindent that can
3450 occur or dissappear.
3451 The next row can change its height,
3452 if there is another layout before
3455 BreakAgain(refresh_row);
3456 UpdateCounters(refresh_row->previous);
3461 SetCursor(cursor.par, cursor.pos);
3463 /* if (cursor.y > old_cursor.y)
3464 cursor.y -= old_cursor.row->height; */
3466 if (sel_cursor.par == old_cursor.par
3467 && sel_cursor.pos == sel_cursor.pos) {
3468 // correct selection
3469 sel_cursor = cursor;
3474 if (old_cursor.par->ClearParagraph()) {
3475 RedoParagraphs(old_cursor, old_cursor.par->Next());
3477 SetCursor(cursor.par, cursor.pos);
3478 sel_cursor = cursor;
3486 LyXParagraph * LyXText::GetParFromID(int id)
3488 LyXParagraph * result = FirstParagraph();
3489 while (result && result->id() != id)
3490 result = result->next;
3496 bool LyXText::TextUndo()
3498 // returns false if no undo possible
3499 Undo * undo = params->undostack.pop();
3504 .push(CreateUndo(undo->kind,
3505 GetParFromID(undo->number_of_before_par),
3506 GetParFromID(undo->number_of_behind_par)));
3508 return TextHandleUndo(undo);
3512 bool LyXText::TextRedo()
3514 // returns false if no redo possible
3515 Undo * undo = params->redostack.pop();
3520 .push(CreateUndo(undo->kind,
3521 GetParFromID(undo->number_of_before_par),
3522 GetParFromID(undo->number_of_behind_par)));
3524 return TextHandleUndo(undo);
3528 bool LyXText::TextHandleUndo(Undo * undo)
3530 // returns false if no undo possible
3531 bool result = false;
3533 LyXParagraph * before =
3534 GetParFromID(undo->number_of_before_par);
3535 LyXParagraph * behind =
3536 GetParFromID(undo->number_of_behind_par);
3537 LyXParagraph * tmppar;
3538 LyXParagraph * tmppar2;
3539 LyXParagraph * endpar;
3540 LyXParagraph * tmppar5;
3542 // if there's no before take the beginning
3543 // of the document for redoing
3545 SetCursorIntern(FirstParagraph(), 0);
3547 // replace the paragraphs with the undo informations
3549 LyXParagraph * tmppar3 = undo->par;
3550 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3551 LyXParagraph * tmppar4 = tmppar3;
3553 while (tmppar4->next)
3554 tmppar4 = tmppar4->next;
3555 } // get last undo par
3557 // now remove the old text if there is any
3558 if (before != behind || (!behind && !before)){
3560 tmppar5 = before->next;
3562 tmppar5 = params->paragraph;
3564 while (tmppar5 && tmppar5 != behind){
3566 tmppar5 = tmppar5->next;
3567 // a memory optimization for edit: Only layout information
3568 // is stored in the undo. So restore the text informations.
3569 if (undo->kind == Undo::EDIT) {
3570 tmppar2->setContentsFromPar(tmppar);
3571 tmppar->clearContents();
3572 //tmppar2->text = tmppar->text;
3573 //tmppar->text.clear();
3574 tmppar2 = tmppar2->next;
3576 if ( currentrow && currentrow->par == tmppar )
3577 currentrow = currentrow -> previous;
3578 // Commenting out this might remove the error
3579 // reported by Purify, but it might also
3580 // introduce a memory leak. We need to
3586 // put the new stuff in the list if there is one
3589 before->next = tmppar3;
3591 params->paragraph = tmppar3;
3592 tmppar3->previous = before;
3596 params->paragraph = behind;
3599 tmppar4->next = behind;
3601 behind->previous = tmppar4;
3605 // Set the cursor for redoing
3607 SetCursorIntern(before->FirstSelfrowPar(), 0);
3608 // check wether before points to a closed float and open it if necessary
3609 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3610 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3612 while (tmppar4->previous &&
3613 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3614 tmppar4 = tmppar4->previous;
3615 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3616 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3617 tmppar4 = tmppar4->next;
3622 // open a cosed footnote at the end if necessary
3623 if (behind && behind->previous &&
3624 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3625 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3626 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3627 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3628 behind = behind->next;
3632 // calculate the endpar for redoing the paragraphs.
3634 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3635 endpar = behind->LastPhysicalPar()->Next();
3637 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3642 tmppar = GetParFromID(undo->number_of_cursor_par);
3643 RedoParagraphs(cursor, endpar);
3645 SetCursorIntern(tmppar, undo->cursor_pos);
3646 UpdateCounters(cursor.row);
3656 void LyXText::FinishUndo()
3658 // makes sure the next operation will be stored
3659 undo_finished = True;
3663 void LyXText::FreezeUndo()
3665 // this is dangerous and for internal use only
3670 void LyXText::UnFreezeUndo()
3672 // this is dangerous and for internal use only
3673 undo_frozen = false;
3677 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3678 LyXParagraph const * behind) const
3681 params->undostack.push(CreateUndo(kind, before, behind));
3682 params->redostack.clear();
3686 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3687 LyXParagraph const * behind)
3689 params->redostack.push(CreateUndo(kind, before, behind));
3693 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3694 LyXParagraph const * behind) const
3696 int before_number = -1;
3697 int behind_number = -1;
3699 before_number = before->id();
3701 behind_number = behind->id();
3702 // Undo::EDIT and Undo::FINISH are
3703 // always finished. (no overlapping there)
3704 // overlapping only with insert and delete inside one paragraph:
3705 // Nobody wants all removed character
3706 // appear one by one when undoing.
3707 // EDIT is special since only layout information, not the
3708 // contents of a paragaph are stored.
3709 if (!undo_finished && kind != Undo::EDIT &&
3710 kind != Undo::FINISH){
3711 // check wether storing is needed
3712 if (!params->undostack.empty() &&
3713 params->undostack.top()->kind == kind &&
3714 params->undostack.top()->number_of_before_par == before_number &&
3715 params->undostack.top()->number_of_behind_par == behind_number ){
3720 // create a new Undo
3721 LyXParagraph * undopar;
3722 LyXParagraph * tmppar;
3723 LyXParagraph * tmppar2;
3725 LyXParagraph * start = 0;
3726 LyXParagraph * end = 0;
3729 start = before->next;
3731 start = FirstParagraph();
3733 end = behind->previous;
3735 end = FirstParagraph();
3741 && start != end->next
3742 && (before != behind || (!before && !behind))) {
3744 tmppar2 = tmppar->Clone();
3745 tmppar2->id(tmppar->id());
3747 // a memory optimization: Just store the layout information
3749 if (kind == Undo::EDIT){
3750 //tmppar2->text.clear();
3751 tmppar2->clearContents();
3756 while (tmppar != end && tmppar->next) {
3757 tmppar = tmppar->next;
3758 tmppar2->next = tmppar->Clone();
3759 tmppar2->next->id(tmppar->id());
3760 // a memory optimization: Just store the layout
3761 // information when only edit
3762 if (kind == Undo::EDIT){
3763 //tmppar2->next->text.clear();
3764 tmppar2->clearContents();
3766 tmppar2->next->previous = tmppar2;
3767 tmppar2 = tmppar2->next;
3771 undopar = 0; // nothing to replace (undo of delete maybe)
3773 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3774 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3776 Undo * undo = new Undo(kind,
3777 before_number, behind_number,
3778 cursor_par, cursor_pos,
3781 undo_finished = false;
3786 void LyXText::SetCursorParUndo()
3788 SetUndo(Undo::FINISH,
3789 cursor.par->ParFromPos(cursor.pos)->previous,
3790 cursor.par->ParFromPos(cursor.pos)->next);
3794 void LyXText::RemoveTableRow(LyXCursor * cur) const
3800 // move to the previous row
3801 int cell_act = NumberOfCell(cur->par, cur->pos);
3804 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3807 !cur->par->table->IsFirstCell(cell_act)) {
3809 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3814 // now we have to pay attention if the actual table is the
3815 // main row of TableContRows and if yes to delete all of them
3820 // delete up to the next row
3821 while (cur->pos < cur->par->Last() &&
3823 || !cur->par->table->IsFirstCell(cell_act))) {
3824 while (cur->pos < cur->par->Last() &&
3825 !cur->par->IsNewline(cur->pos))
3826 cur->par->Erase(cur->pos);
3829 if (cur->pos < cur->par->Last())
3830 cur->par->Erase(cur->pos);
3832 if (cur->pos && cur->pos == cur->par->Last()) {
3834 cur->par->Erase(cur->pos); // no newline at very end!
3836 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3837 !cur->par->table->IsContRow(cell_org) &&
3838 cur->par->table->IsContRow(cell));
3839 cur->par->table->DeleteRow(cell_org);
3844 bool LyXText::IsEmptyTableCell() const
3846 LyXParagraph::size_type pos = cursor.pos - 1;
3847 while (pos >= 0 && pos < cursor.par->Last()
3848 && !cursor.par->IsNewline(pos))
3850 return cursor.par->IsNewline(pos + 1);
3854 void LyXText::toggleAppendix(){
3855 LyXParagraph * par = cursor.par->FirstPhysicalPar();
3856 bool start = !par->start_of_appendix;
3858 // ensure that we have only one start_of_appendix in this document
3859 LyXParagraph * tmp = FirstParagraph();
3860 for (; tmp; tmp = tmp->next)
3861 tmp->start_of_appendix = 0;
3862 par->start_of_appendix = start;
3864 // we can set the refreshing parameters now
3865 status = LyXText::NEED_MORE_REFRESH;
3867 refresh_row = 0; // not needed for full update
3869 SetCursor(cursor.par, cursor.pos);