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 * ====================================================== */
14 #pragma implementation "lyxparagraph.h"
21 #include "lyxparagraph.h"
22 #include "support/textutils.h"
25 #include "tex-strings.h"
26 #include "bufferparams.h"
27 #include "support/FileInfo.h"
28 #include "support/LAssert.h"
30 #include "LaTeXFeatures.h"
31 #include "insets/insetinclude.h"
32 #include "insets/insetbib.h"
33 #include "support/filetools.h"
34 #include "lyx_gui_misc.h"
38 extern void addNewlineAndDepth(string & file, int const depth); // Jug 990923
39 int tex_code_break_column = 72; // needs non-zero initialization. set later.
40 // this is a bad idea, but how can LyXParagraph find its buffer to get
41 // parameters? (JMarc)
42 extern BufferView * current_view;
47 extern string bibitemWidthest(Painter &);
49 // this is a minibuffer
50 static char minibuffer_char;
51 static LyXFont minibuffer_font;
52 static Inset * minibuffer_inset;
55 // Initialization of the counter for the paragraph id's,
56 // declared in lyxparagraph.h
57 unsigned int LyXParagraph::paragraph_id = 0;
60 LyXParagraph::LyXParagraph()
62 text.reserve(500); // is this number too big?
64 for (int i = 0; i < 10; ++i) setCounter(i , 0);
70 footnoteflag = LyXParagraph::NO_FOOTNOTE;
71 footnotekind = LyXParagraph::FOOTNOTE; // should not be needed
73 align = LYX_ALIGN_BLOCK;
75 /* table stuff -- begin*/
77 /* table stuff -- end*/
79 bibkey = 0; // ale970302
84 // This konstruktor inserts the new paragraph in a list.
85 LyXParagraph::LyXParagraph(LyXParagraph * par)
88 par->text.resize(par->text.size());
90 for (int i = 0; i < 10; ++i) setCounter(i, 0);
94 // double linked list begin
97 next->previous = this;
99 previous->next = this;
101 footnoteflag = LyXParagraph::NO_FOOTNOTE;
102 footnotekind = LyXParagraph::FOOTNOTE;
104 /* table stuff -- begin*/
106 /* table stuff -- end*/
107 id_ = paragraph_id++;
109 bibkey = 0; // ale970302
115 void LyXParagraph::writeFile(ostream & os, BufferParams const & params,
116 char footflag, char dth) const
118 LyXFont font1, font2;
123 if (footnoteflag != LyXParagraph::NO_FOOTNOTE
125 || previous->footnoteflag == LyXParagraph::NO_FOOTNOTE){
127 // The beginning or the end of a footnote environment?
128 if (footflag != footnoteflag) {
129 footflag = footnoteflag;
131 os << "\n\\begin_float "
132 << string_footnotekinds[footnotekind]
135 os << "\n\\end_float ";
139 // The beginning or end of a deeper (i.e. nested) area?
142 while (depth > dth) {
143 os << "\n\\begin_deeper ";
147 while (depth < dth) {
148 os << "\n\\end_deeper ";
154 // First write the layout
156 << textclasslist.NameOfLayout(params.textclass, layout)
159 // Maybe some vertical spaces.
160 if (added_space_top.kind() != VSpace::NONE)
161 os << "\\added_space_top "
162 << added_space_top.asLyXCommand() << " ";
163 if (added_space_bottom.kind() != VSpace::NONE)
164 os << "\\added_space_bottom "
165 << added_space_bottom.asLyXCommand() << " ";
167 // The labelwidth string used in lists.
168 if (!labelwidthstring.empty())
169 os << "\\labelwidthstring "
170 << labelwidthstring << '\n';
172 // Lines above or below?
176 os << "\\line_bottom ";
178 // Pagebreaks above or below?
180 os << "\\pagebreak_top ";
181 if (pagebreak_bottom)
182 os << "\\pagebreak_bottom ";
184 // Start of appendix?
185 if (start_of_appendix)
186 os << "\\start_of_appendix ";
193 if (align != LYX_ALIGN_LAYOUT) {
195 case LYX_ALIGN_LEFT: h = 1; break;
196 case LYX_ALIGN_RIGHT: h = 2; break;
197 case LYX_ALIGN_CENTER: h = 3; break;
198 default: h = 0; break;
200 os << "\\align " << string_align[h] << " ";
202 if (pextra_type != PEXTRA_NONE) {
203 os << "\\pextra_type " << pextra_type;
204 if (pextra_type == PEXTRA_MINIPAGE) {
205 os << " \\pextra_alignment "
208 os << " \\pextra_hfill "
210 if (pextra_start_minipage)
211 os << " \\pextra_start_minipage "
212 << pextra_start_minipage;
214 if (!pextra_width.empty()) {
215 os << " \\pextra_width "
216 << VSpace(pextra_width).asLyXCommand();
217 } else if (!pextra_widthp.empty()) {
218 os << " \\pextra_widthp "
224 // Dummy layout. This means that a footnote ended.
225 os << "\n\\end_float ";
226 footflag = LyXParagraph::NO_FOOTNOTE;
229 // It might be a table.
231 os << "\\LyXTable\n";
239 font1 = LyXFont(LyXFont::ALL_INHERIT);
242 for (size_type i = 0; i < size(); ++i) {
248 // Write font changes
249 font2 = GetFontSettings(i);
250 if (font2 != font1) {
251 font2.lyxWriteChanges(font1, os);
260 Inset const * inset = GetInset(i);
262 if (inset->DirectWrite()) {
263 // international char, let it write
264 // code directly so it's shorter in
268 os << "\n\\begin_inset ";
270 os << "\n\\end_inset \n\n";
276 os << "\n\\newline \n";
280 os << "\n\\hfill \n";
283 case META_PROTECTED_SEPARATOR:
284 os << "\n\\protected_separator \n";
288 os << "\n\\backslash \n";
292 if (i + 1 < size() && GetChar(i + 1) == ' ') {
299 if ((column > 70 && c == ' ')
304 // this check is to amend a bug. LyX sometimes
305 // inserts '\0' this could cause problems.
309 lyxerr << "ERROR (LyXParagraph::writeFile):"
310 " NULL char in structure." << endl;
316 // now write the next paragraph
318 next->writeFile(os, params, footflag, dth);
322 void LyXParagraph::validate(LaTeXFeatures & features) const
324 // this will be useful later
325 LyXLayout const & layout =
326 textclasslist.Style(current_view->buffer()->params.textclass,
330 if (line_top || line_bottom)
331 features.lyxline = true;
334 features.layout[GetLayout()] = true;
337 for (FontList::const_iterator cit = fontlist.begin();
338 cit != fontlist.end(); ++cit) {
339 if ((*cit).font.noun() == LyXFont::ON) {
340 lyxerr[Debug::LATEX] << "font.noun: "
341 << (*cit).font.noun()
343 features.noun = true;
344 lyxerr[Debug::LATEX] << "Noun enabled. Font: "
345 << (*cit).font.stateText()
348 switch ((*cit).font.color()) {
350 case LColor::inherit:
354 features.color = true;
355 lyxerr[Debug::LATEX] << "Color enabled. Font: "
356 << (*cit).font.stateText()
362 for (InsetList::const_iterator cit = insetlist.begin();
363 cit != insetlist.end(); ++cit) {
365 (*cit).inset->Validate(features);
368 if (table && table->IsLongTable())
369 features.longtable = true;
370 if (pextra_type == PEXTRA_INDENT)
371 features.LyXParagraphIndent = true;
372 if (pextra_type == PEXTRA_FLOATFLT)
373 features.floatflt = true;
374 if (layout.needprotect
375 && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
376 features.NeedLyXFootnoteCode = true;
377 if ((current_view->buffer()->params.paragraph_separation == BufferParams::PARSEP_INDENT) &&
378 (pextra_type == LyXParagraph::PEXTRA_MINIPAGE))
379 features.NeedLyXMinipageIndent = true;
380 if (table && table->NeedRotating())
381 features.rotating = true;
382 if (footnoteflag != NO_FOOTNOTE && footnotekind == ALGORITHM)
383 features.algorithm = true;
387 // First few functions needed for cut and paste and paragraph breaking.
388 void LyXParagraph::CopyIntoMinibuffer(LyXParagraph::size_type pos) const
390 minibuffer_char = GetChar(pos);
391 minibuffer_font = GetFontSettings(pos);
392 minibuffer_inset = 0;
393 if (minibuffer_char == LyXParagraph::META_INSET) {
395 minibuffer_inset = GetInset(pos)->Clone();
397 minibuffer_inset = 0;
398 minibuffer_char = ' ';
399 // This reflects what GetInset() does (ARRae)
405 void LyXParagraph::CutIntoMinibuffer(LyXParagraph::size_type pos)
407 minibuffer_char = GetChar(pos);
408 minibuffer_font = GetFontSettings(pos);
409 minibuffer_inset = 0;
410 if (minibuffer_char == LyXParagraph::META_INSET) {
412 minibuffer_inset = GetInset(pos);
413 // This is a little hack since I want exactly
414 // the inset, not just a clone. Otherwise
415 // the inset would be deleted when calling Erase(pos)
417 for (InsetList::iterator it = insetlist.begin();
418 it != insetlist.end(); ++it) {
419 if ((*it).pos == pos) {
426 minibuffer_inset = 0;
427 minibuffer_char = ' ';
428 // This reflects what GetInset() does (ARRae)
433 // Erase(pos); now the caller is responsible for that.
437 void LyXParagraph::InsertFromMinibuffer(LyXParagraph::size_type pos)
439 InsertChar(pos, minibuffer_char);
440 SetFont(pos, minibuffer_font);
441 if (minibuffer_char == LyXParagraph::META_INSET)
442 InsertInset(pos, minibuffer_inset);
449 void LyXParagraph::Clear()
454 pagebreak_top = false;
455 pagebreak_bottom = false;
457 added_space_top = VSpace(VSpace::NONE);
458 added_space_bottom = VSpace(VSpace::NONE);
460 align = LYX_ALIGN_LAYOUT;
464 pextra_type = PEXTRA_NONE;
465 pextra_width.clear();
466 pextra_widthp.clear();
467 pextra_alignment = MINIPAGE_ALIGN_TOP;
468 pextra_hfill = false;
469 pextra_start_minipage = false;
472 labelwidthstring.clear();
476 start_of_appendix = false;
480 // the destructor removes the new paragraph from the list
481 LyXParagraph::~LyXParagraph()
484 previous->next = next;
486 next->previous = previous;
488 for (InsetList::iterator it = insetlist.begin();
489 it != insetlist.end(); ++it) {
493 /* table stuff -- begin*/
495 /* table stuff -- end*/
502 void LyXParagraph::Erase(LyXParagraph::size_type pos)
504 // > because last is the next unused position, and you can
505 // use it if you want
507 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
508 NextAfterFootnote()->Erase(pos - text.size() - 1);
510 lyxerr.debug() << "ERROR (LyXParagraph::Erase): "
511 "position does not exist." << endl;
514 if (pos < size()) { // last is free for insertation, but should be empty
515 // if it is an inset, delete the inset entry
516 if (text[pos] == LyXParagraph::META_INSET) {
518 for (InsetList::iterator it = insetlist.begin();
519 it != insetlist.end(); ++it) {
520 if ((*it).pos == pos) {
527 text.erase(text.begin() + pos);
528 // Erase entries in the tables.
529 for (FontList::iterator it = fontlist.begin();
530 it != fontlist.end(); ++it) {
531 if (pos >= (*it).pos && pos <= (*it).pos_end) {
532 if ((*it).pos == (*it).pos_end) {
533 // If it is a multi-character font
534 // entry, we just make it smaller
535 // (see update below), otherwise we
542 // Update all other entries.
543 for (FontList::iterator it = fontlist.begin();
544 it != fontlist.end(); ++it) {
547 if ((*it).pos_end >= pos)
551 // Update the inset table.
552 for (InsetList::iterator it = insetlist.begin();
553 it != insetlist.end(); ++it) {
558 lyxerr << "ERROR (LyXParagraph::Erase): "
559 "can't erase non-existant char." << endl;
564 void LyXParagraph::InsertChar(LyXParagraph::size_type pos, char c)
566 // > because last is the next unused position, and you can
567 // use it if you want
570 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
571 NextAfterFootnote()->InsertChar(pos - text.size() - 1,
574 lyxerr.debug() << "ERROR (LyXParagraph::InsertChar): "
575 "position does not exist." << endl;
578 text.insert(text.begin() + pos, c);
579 // Update the font table.
580 for (FontList::iterator it = fontlist.begin();
581 it != fontlist.end(); ++it) {
582 if ((*it).pos >= pos)
584 if ((*it).pos_end >= pos)
588 // Update the inset table.
589 for (InsetList::iterator it = insetlist.begin();
590 it != insetlist.end(); ++it) {
591 if ((*it).pos >= pos)
597 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
600 // > because last is the next unused position, and you can
601 // use it if you want
604 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
606 ->InsertInset(pos - text.size() - 1, inset);
608 lyxerr << "ERROR (LyXParagraph::InsertInset): "
609 "position does not exist: " << pos << endl;
612 if (text[pos] != LyXParagraph::META_INSET) {
613 lyxerr << "ERROR (LyXParagraph::InsertInset): "
614 "there is no LyXParagraph::META_INSET" << endl;
619 // Add a new entry in the inset table.
620 InsetList::iterator it =
621 insetlist.insert(insetlist.begin(), InsetTable());
628 Inset * LyXParagraph::GetInset(LyXParagraph::size_type pos)
632 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
633 return NextAfterFootnote()
634 ->GetInset(pos - text.size() - 1);
636 lyxerr << "ERROR (LyXParagraph::GetInset): "
637 "position does not exist: "
643 for (InsetList::iterator it = insetlist.begin();
644 it != insetlist.end(); ++it) {
645 if ((*it).pos == pos) {
649 lyxerr << "ERROR (LyXParagraph::GetInset): "
650 "Inset does not exist: " << pos << endl;
651 text[pos] = ' '; // WHY!!! does this set the pos to ' '????
652 // Did this commenting out introduce a bug? So far I have not
653 // see any, please enlighten me. (Lgb)
654 // My guess is that since the inset does not exist, we might
655 // as well replace it with a space to prevent craches. (Asger)
660 Inset const * LyXParagraph::GetInset(LyXParagraph::size_type pos) const
664 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
665 return NextAfterFootnote()
666 ->GetInset(pos - text.size() - 1);
668 lyxerr << "ERROR (LyXParagraph::GetInset): "
669 "position does not exist: "
675 for (InsetList::const_iterator cit = insetlist.begin();
676 cit != insetlist.end(); ++cit) {
677 if ((*cit).pos == pos) {
681 lyxerr << "ERROR (LyXParagraph::GetInset): "
682 "Inset does not exist: " << pos << endl;
683 //text[pos] = ' '; // WHY!!! does this set the pos to ' '????
684 // Did this commenting out introduce a bug? So far I have not
685 // see any, please enlighten me. (Lgb)
686 // My guess is that since the inset does not exist, we might
687 // as well replace it with a space to prevent craches. (Asger)
692 // Gets uninstantiated font setting at position.
693 // Optimized after profiling. (Asger)
694 LyXFont LyXParagraph::GetFontSettings(LyXParagraph::size_type pos) const
697 for (FontList::const_iterator cit = fontlist.begin();
698 cit != fontlist.end(); ++cit) {
699 if (pos >= (*cit).pos && pos <= (*cit).pos_end)
703 // > because last is the next unused position, and you can
704 // use it if you want
705 else if (pos > size()) {
707 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
708 return NextAfterFootnote()
709 ->GetFontSettings(pos - text.size() - 1);
711 // Why is it an error to ask for the font of a
712 // position that does not exist? Would it be
713 // enough for this to be enabled on debug?
714 // We want strict error checking, but it's ok to only
715 // have it when debugging. (Asger)
716 lyxerr << "ERROR (LyXParagraph::GetFontSettings): "
717 "position does not exist. "
718 << pos << " (" << static_cast<int>(pos)
722 return GetFontSettings(pos - 1);
724 return LyXFont(LyXFont::ALL_INHERIT);
728 // Gets the fully instantiated font at a given position in a paragraph
729 // This is basically the same function as LyXText::GetFont() in text2.C.
730 // The difference is that this one is used for generating the LaTeX file,
731 // and thus cosmetic "improvements" are disallowed: This has to deliver
732 // the true picture of the buffer. (Asger)
733 // If position is -1, we get the layout font of the paragraph.
734 // If position is -2, we get the font of the manual label of the paragraph.
735 LyXFont LyXParagraph::getFont(LyXParagraph::size_type pos) const
738 LyXLayout const & layout =
739 textclasslist.Style(current_view->buffer()->params.textclass,
741 LyXParagraph::size_type main_body = 0;
742 if (layout.labeltype == LABEL_MANUAL)
743 main_body = BeginningOfMainBody();
748 layoutfont = layout.labelfont;
750 layoutfont = layout.font;
751 tmpfont = GetFontSettings(pos);
752 tmpfont.realize(layoutfont);
754 // process layoutfont for pos == -1 and labelfont for pos < -1
756 tmpfont = layout.font;
758 tmpfont = layout.labelfont;
759 if (getParDirection() == LYX_DIR_RIGHT_TO_LEFT)
760 tmpfont.setDirection(LyXFont::RTL_DIR);
763 // check for environment font information
764 char par_depth = GetDepth();
765 LyXParagraph const * par = this;
766 while (par && par_depth && !tmpfont.resolved()) {
767 par = par->DepthHook(par_depth - 1);
769 tmpfont.realize(textclasslist.
770 Style(current_view->buffer()->params.textclass,
771 par->GetLayout()).font);
772 par_depth = par->GetDepth();
776 tmpfont.realize(textclasslist
777 .TextClass(current_view->buffer()->params.textclass)
783 /// Returns the height of the highest font in range
785 LyXParagraph::HighestFontInRange(LyXParagraph::size_type startpos,
786 LyXParagraph::size_type endpos) const
788 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
789 for (FontList::const_iterator cit = fontlist.begin();
790 cit != fontlist.end(); ++cit) {
791 if (startpos <= (*cit).pos_end && endpos >= (*cit).pos) {
792 LyXFont::FONT_SIZE size = (*cit).font.size();
793 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
801 char LyXParagraph::GetChar(LyXParagraph::size_type pos)
808 // > because last is the next unused position, and you can
809 // use it if you want
810 else if (pos > size()) {
811 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
812 return NextAfterFootnote()
813 ->GetChar(pos - text.size() - 1);
815 lyxerr << "ERROR (LyXParagraph::GetChar): "
816 "position does not exist."
817 << pos << " (" << static_cast<int>(pos)
819 // Assert(false); // This triggers sometimes...
824 // We should have a footnote environment.
825 if (!next || next->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
826 // Notice that LyX does request the
827 // last char from time to time. (Asger)
828 //lyxerr << "ERROR (LyXParagraph::GetChar): "
829 // "expected footnote." << endl;
832 switch (next->footnotekind) {
833 case LyXParagraph::FOOTNOTE:
834 return LyXParagraph::META_FOOTNOTE;
835 case LyXParagraph::MARGIN:
836 return LyXParagraph::META_MARGIN;
837 case LyXParagraph::FIG:
838 case LyXParagraph::WIDE_FIG:
839 return LyXParagraph::META_FIG;
840 case LyXParagraph::TAB:
841 case LyXParagraph::WIDE_TAB:
842 return LyXParagraph::META_TAB;
843 case LyXParagraph::ALGORITHM:
844 return LyXParagraph::META_ALGORITHM;
846 return '\0'; // to shut up gcc
851 char LyXParagraph::GetChar(LyXParagraph::size_type pos) const
858 // > because last is the next unused position, and you can
859 // use it if you want
860 else if (pos > size()) {
861 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
862 return NextAfterFootnote()
863 ->GetChar(pos - text.size() - 1);
865 lyxerr << "ERROR (LyXParagraph::GetChar const): "
866 "position does not exist."
867 << pos << " (" << static_cast<int>(pos)
873 // We should have a footnote environment.
874 if (!next || next->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
875 // Notice that LyX does request the
876 // last char from time to time. (Asger)
877 //lyxerr << "ERROR (LyXParagraph::GetChar): "
878 // "expected footnote." << endl;
881 switch (next->footnotekind) {
882 case LyXParagraph::FOOTNOTE:
883 return LyXParagraph::META_FOOTNOTE;
884 case LyXParagraph::MARGIN:
885 return LyXParagraph::META_MARGIN;
886 case LyXParagraph::FIG:
887 case LyXParagraph::WIDE_FIG:
888 return LyXParagraph::META_FIG;
889 case LyXParagraph::TAB:
890 case LyXParagraph::WIDE_TAB:
891 return LyXParagraph::META_TAB;
892 case LyXParagraph::ALGORITHM:
893 return LyXParagraph::META_ALGORITHM;
895 return '\0'; // to shut up gcc
900 // return an string of the current word, and the end of the word in lastpos.
901 string LyXParagraph::GetWord(LyXParagraph::size_type & lastpos) const
905 // the current word is defined as starting at the first character
906 // from the immediate left of lastpospos which meets the definition
907 // of IsLetter(), continuing to the last character to the right
908 // of this meeting IsLetter.
914 // move back until we have a letter
916 //there's no real reason to have firstpos & lastpos as
917 //separate variables as this is written, but maybe someon
918 // will want to return firstpos in the future.
920 //since someone might have typed a punctuation first
921 int firstpos = lastpos;
923 while ((firstpos >= 0) && !IsLetter(firstpos))
926 // now find the beginning by looking for a nonletter
928 while ((firstpos>= 0) && IsLetter(firstpos))
931 // the above is now pointing to the preceeding non-letter
935 // so copy characters into theword until we get a nonletter
936 // note that this can easily exceed lastpos, wich means
937 // that if used in the middle of a word, the whole word
940 while (IsLetter(lastpos)) theword += GetChar(lastpos++);
947 LyXParagraph::size_type LyXParagraph::Last() const
949 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
950 return text.size() + NextAfterFootnote()->Last() + 1;
951 // the 1 is the symbol
958 LyXParagraph * LyXParagraph::ParFromPos(LyXParagraph::size_type pos)
960 // > because last is the next unused position, and you can
961 // use it if you want
964 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
965 return NextAfterFootnote()
966 ->ParFromPos(pos - text.size() - 1);
968 lyxerr << "ERROR (LyXParagraph::ParFromPos): "
969 "position does not exist." << endl;
976 int LyXParagraph::PositionInParFromPos(LyXParagraph::size_type pos) const
978 // > because last is the next unused position, and you can
979 // use it if you want
982 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
983 return NextAfterFootnote()
984 ->PositionInParFromPos(pos - text.size() - 1);
987 "ERROR (LyXParagraph::PositionInParFromPos): "
988 "position does not exist." << endl;
996 void LyXParagraph::SetFont(LyXParagraph::size_type pos,
997 LyXFont const & font)
999 // > because last is the next unused position, and you can
1000 // use it if you want
1003 next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1004 NextAfterFootnote()->SetFont(pos - text.size() - 1,
1007 lyxerr << "ERROR (LyXParagraph::SetFont): "
1008 "position does not exist." << endl;
1012 LyXFont patternfont(LyXFont::ALL_INHERIT);
1014 // First, reduce font against layout/label font
1015 // Update: The SetCharFont() routine in text2.C already
1016 // reduces font, so we don't need to do that here. (Asger)
1017 // No need to simplify this because it will disappear
1018 // in a new kernel. (Asger)
1019 // Next search font table
1020 FontList::iterator tmp = fontlist.begin();
1021 for (; tmp != fontlist.end(); ++tmp) {
1022 if (pos >= (*tmp).pos && pos <= (*tmp).pos_end) {
1026 if (tmp == fontlist.end()) { // !found
1027 // if we did not find a font entry, but if the font at hand
1028 // is the same as default, we just forget it
1029 if (font == patternfont) return;
1031 // ok, we did not find a font entry. But maybe there is exactly
1032 // the needed font ientry one position left
1033 FontList::iterator tmp2 = fontlist.begin();
1034 for (; tmp2 != fontlist.end(); ++tmp2) {
1035 if (pos - 1 >= (*tmp2).pos
1036 && pos - 1 <= (*tmp2).pos_end)
1039 if (tmp2 != fontlist.end()) {
1040 // ok there is one, maybe it is exactly
1042 if ((*tmp2).font == font) {
1043 // put the position under the font
1048 // Add a new entry in the
1049 // fontlist for the position
1053 ft.font = font; // or patternfont
1054 // It seems that using font instead of patternfont here
1055 // fixes all the problems. This also surfaces a "bug" in
1057 fontlist.insert(fontlist.begin(), ft);
1058 } else if ((*tmp).pos != (*tmp).pos_end) { // we found a font entry. maybe we have to split it and create a new one.
1060 // more than one character
1061 if (pos == (*tmp).pos) {
1062 // maybe we should enlarge the left fonttable
1063 FontList::iterator tmp2 = fontlist.begin();
1064 for (; tmp2 != fontlist.end(); ++tmp2) {
1065 if (pos - 1 >= (*tmp2).pos
1066 && pos - 1 <= (*tmp2).pos_end)
1069 // Is there is one, and is it exactly
1071 if (tmp2 != fontlist.end() &&
1072 (*tmp2).font == font) {
1073 // Put the position under the font
1079 // Add a new entry in the
1080 // fontlist for the position
1083 ft.pos_end = (*tmp).pos_end;
1084 ft.font = (*tmp).font;
1085 (*tmp).pos_end = pos;
1087 fontlist.insert(fontlist.begin(), ft);
1088 } else if (pos == (*tmp).pos_end) {
1089 // Add a new entry in the
1090 // fontlist for the position
1092 ft.pos = (*tmp).pos;
1093 ft.pos_end = (*tmp).pos_end - 1;
1094 ft.font = (*tmp).font;
1095 (*tmp).pos = (*tmp).pos_end;
1097 fontlist.insert(fontlist.begin(), ft);
1099 // Add a new entry in the
1100 // fontlist for the position
1102 ft.pos = (*tmp).pos;
1103 ft.pos_end = pos - 1;
1104 ft.font = (*tmp).font;
1108 ft2.pos_end = (*tmp).pos_end;
1109 ft2.font = (*tmp).font;
1112 (*tmp).pos_end = pos;
1115 fontlist.insert(fontlist.begin(), ft);
1116 fontlist.insert(fontlist.begin(), ft2);
1124 // This function is able to hide closed footnotes.
1125 LyXParagraph * LyXParagraph::Next()
1127 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1128 LyXParagraph * tmp = next;
1130 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1132 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1133 return tmp->Next(); /* there can be more than one
1134 footnote in a logical
1137 return next; // This should never happen!
1143 LyXParagraph * LyXParagraph::NextAfterFootnote()
1145 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1146 LyXParagraph * tmp = next;
1147 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1149 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1150 return tmp; /* there can be more than one footnote
1151 in a logical paragraph */
1153 return next; // This should never happen!
1159 LyXParagraph const * LyXParagraph::NextAfterFootnote() const
1161 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1162 LyXParagraph * tmp = next;
1163 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1165 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1166 return tmp; /* there can be more than one footnote
1167 in a logical paragraph */
1169 return next; // This should never happen!
1175 LyXParagraph * LyXParagraph::PreviousBeforeFootnote()
1178 if (previous && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1180 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1181 tmp = tmp->previous;
1182 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1183 return tmp; /* there can be more than one footnote
1184 in a logical paragraph */
1186 return previous; // This should never happen!
1192 LyXParagraph * LyXParagraph::LastPhysicalPar()
1194 if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1197 LyXParagraph * tmp = this;
1199 && tmp->next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1200 tmp = tmp->NextAfterFootnote();
1207 LyXParagraph * LyXParagraph::FirstPhysicalPar()
1211 LyXParagraph * tmppar = this;
1215 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1216 tmppar = tmppar->previous;
1225 LyXParagraph const * LyXParagraph::FirstPhysicalPar() const
1229 LyXParagraph const * tmppar = this;
1233 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1234 tmppar = tmppar->previous;
1243 // This function is able to hide closed footnotes.
1244 LyXParagraph * LyXParagraph::Previous()
1246 LyXParagraph * tmp = previous;
1251 && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1252 tmp = tmp->previous;
1254 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1255 tmp = tmp->previous;
1256 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1257 return tmp->next->Previous();
1266 // This function is able to hide closed footnotes.
1267 LyXParagraph const * LyXParagraph::Previous() const
1269 LyXParagraph * tmp = previous;
1274 && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1275 tmp = tmp->previous;
1277 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1278 tmp = tmp->previous;
1279 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1280 return tmp->next->Previous();
1289 void LyXParagraph::BreakParagraph(LyXParagraph::size_type pos,
1292 size_type i, pos_end, pos_first;
1293 // create a new paragraph
1294 LyXParagraph * par = ParFromPos(pos);
1295 LyXParagraph * firstpar = FirstPhysicalPar();
1297 LyXParagraph * tmp = new LyXParagraph(par);
1299 tmp->footnoteflag = footnoteflag;
1300 tmp->footnotekind = footnotekind;
1302 // this is an idea for a more userfriendly layout handling, I will
1303 // see what the users say
1305 // layout stays the same with latex-environments
1307 tmp->SetOnlyLayout(firstpar->layout);
1308 tmp->SetLabelWidthString(firstpar->labelwidthstring);
1311 if (Last() > pos || !Last() || flag == 2) {
1312 tmp->SetOnlyLayout(firstpar->layout);
1313 tmp->align = firstpar->align;
1314 tmp->SetLabelWidthString(firstpar->labelwidthstring);
1316 tmp->line_bottom = firstpar->line_bottom;
1317 firstpar->line_bottom = false;
1318 tmp->pagebreak_bottom = firstpar->pagebreak_bottom;
1319 firstpar->pagebreak_bottom = false;
1320 tmp->added_space_bottom = firstpar->added_space_bottom;
1321 firstpar->added_space_bottom = VSpace(VSpace::NONE);
1323 tmp->depth = firstpar->depth;
1324 tmp->noindent = firstpar->noindent;
1326 // copy everything behind the break-position
1327 // to the new paragraph
1329 while (ParFromPos(pos_first) != par)
1332 pos_end = pos_first + par->text.size() - 1;
1333 // The constructor has already reserved 500 elements
1334 //if (pos_end > pos)
1335 // tmp->text.reserve(pos_end - pos);
1337 for (i = pos; i <= pos_end; ++i) {
1338 par->CutIntoMinibuffer(i - pos_first);
1339 tmp->InsertFromMinibuffer(i - pos);
1341 tmp->text.resize(tmp->text.size());
1342 for (i = pos_end; i >= pos; --i)
1343 par->Erase(i - pos_first);
1345 par->text.resize(par->text.size());
1348 // just an idea of me
1350 tmp->line_top = firstpar->line_top;
1351 tmp->pagebreak_top = firstpar->pagebreak_top;
1352 tmp->added_space_top = firstpar->added_space_top;
1353 tmp->bibkey = firstpar->bibkey;
1355 // layout stays the same with latex-environments
1357 firstpar->SetOnlyLayout(tmp->layout);
1358 firstpar->SetLabelWidthString(tmp->labelwidthstring);
1359 firstpar->depth = tmp->depth;
1365 void LyXParagraph::MakeSameLayout(LyXParagraph const * par)
1367 par = par->FirstPhysicalPar();
1368 footnoteflag = par->footnoteflag;
1369 footnotekind = par->footnotekind;
1371 layout = par->layout;
1372 align = par-> align;
1373 SetLabelWidthString(par->labelwidthstring);
1375 line_bottom = par->line_bottom;
1376 pagebreak_bottom = par->pagebreak_bottom;
1377 added_space_bottom = par->added_space_bottom;
1379 line_top = par->line_top;
1380 pagebreak_top = par->pagebreak_top;
1381 added_space_top = par->added_space_top;
1383 pextra_type = par->pextra_type;
1384 pextra_width = par->pextra_width;
1385 pextra_widthp = par->pextra_widthp;
1386 pextra_alignment = par->pextra_alignment;
1387 pextra_hfill = par->pextra_hfill;
1388 pextra_start_minipage = par->pextra_start_minipage;
1390 noindent = par->noindent;
1395 LyXParagraph * LyXParagraph::FirstSelfrowPar()
1397 LyXParagraph * tmppar = this;
1400 && tmppar->previous->footnoteflag ==
1401 LyXParagraph::CLOSED_FOOTNOTE)
1402 || tmppar->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))
1403 tmppar = tmppar->previous;
1406 return this; // This should never happen!
1412 LyXParagraph * LyXParagraph::Clone() const
1414 // create a new paragraph
1415 LyXParagraph * result = new LyXParagraph;
1417 result->MakeSameLayout(this);
1419 // this is because of the dummy layout of the paragraphs that
1421 result->layout = layout;
1423 /* table stuff -- begin*/
1425 result->table = table->Clone();
1428 /* table stuff -- end*/
1431 result->bibkey = (bibkey) ? new InsetBibKey(bibkey): 0;
1434 // copy everything behind the break-position to the new paragraph
1436 for (size_type i = 0; i < size(); ++i) {
1437 CopyIntoMinibuffer(i);
1438 result->InsertFromMinibuffer(i);
1440 result->text.resize(result->text.size());
1445 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1447 par = par->FirstPhysicalPar();
1450 par->footnoteflag == footnoteflag &&
1451 par->footnotekind == footnotekind &&
1453 par->layout == layout &&
1455 par->align == align &&
1457 par->line_bottom == line_bottom &&
1458 par->pagebreak_bottom == pagebreak_bottom &&
1459 par->added_space_bottom == added_space_bottom &&
1461 par->line_top == line_top &&
1462 par->pagebreak_top == pagebreak_top &&
1463 par->added_space_top == added_space_top &&
1465 par->pextra_type == pextra_type &&
1466 par->pextra_width == pextra_width &&
1467 par->pextra_widthp == pextra_widthp &&
1468 par->pextra_alignment == pextra_alignment &&
1469 par->pextra_hfill == pextra_hfill &&
1470 par->pextra_start_minipage == pextra_start_minipage &&
1472 par->table == table && // what means: NO TABLE AT ALL
1474 par->noindent == noindent &&
1475 par->depth == depth);
1479 void LyXParagraph::BreakParagraphConservative(LyXParagraph::size_type pos)
1481 // create a new paragraph
1482 LyXParagraph * par = ParFromPos(pos);
1484 LyXParagraph * tmp = new LyXParagraph(par);
1486 tmp->MakeSameLayout(par);
1488 // When can pos < Last()?
1489 // I guess pos == Last() is possible.
1491 // copy everything behind the break-position to the new
1493 size_type pos_first = 0;
1494 while (ParFromPos(pos_first) != par)
1496 size_type pos_end = pos_first + par->text.size() - 1;
1497 // make sure there is enough memory for the now larger
1498 // paragraph. This is not neccessary, because
1499 // InsertFromMinibuffer will enlarge the memory (it uses
1500 // InsertChar of course). But doing it by hand
1501 // is MUCH faster! (only one time, not thousend times!!)
1502 // Not needed since the constructor aleady have
1503 // reserved 500 elements in text.
1504 //if (pos_end > pos)
1505 // tmp->text.reserve(pos_end - pos);
1507 for (size_type i = pos; i <= pos_end; ++i) {
1508 par->CutIntoMinibuffer(i - pos_first);
1509 tmp->InsertFromMinibuffer(i - pos);
1511 tmp->text.resize(tmp->text.size());
1512 for (size_type i = pos_end; i >= pos; --i)
1513 par->Erase(i - pos_first);
1515 par->text.resize(par->text.size());
1520 // Be carefull, this does not make any check at all.
1521 void LyXParagraph::PasteParagraph()
1523 // copy the next paragraph to this one
1524 LyXParagraph * the_next = Next();
1526 LyXParagraph * firstpar = FirstPhysicalPar();
1528 // first the DTP-stuff
1529 firstpar->line_bottom = the_next->line_bottom;
1530 firstpar->added_space_bottom = the_next->added_space_bottom;
1531 firstpar->pagebreak_bottom = the_next->pagebreak_bottom;
1533 size_type pos_end = the_next->text.size() - 1;
1534 size_type pos_insert = Last();
1536 // ok, now copy the paragraph
1537 for (size_type i = 0; i <= pos_end; ++i) {
1538 the_next->CutIntoMinibuffer(i);
1539 InsertFromMinibuffer(pos_insert + i);
1542 // delete the next paragraph
1547 void LyXParagraph::OpenFootnote(LyXParagraph::size_type pos)
1549 LyXParagraph * par = ParFromPos(pos);
1551 while (par && par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1552 par->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
1558 void LyXParagraph::CloseFootnote(LyXParagraph::size_type pos)
1560 LyXParagraph * par = ParFromPos(pos);
1562 while (par && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1563 par->footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
1569 LyXTextClass::LayoutList::size_type LyXParagraph::GetLayout() const
1571 return FirstPhysicalPar()->layout;
1575 char LyXParagraph::GetDepth() const
1577 return FirstPhysicalPar()->depth;
1581 char LyXParagraph::GetAlign() const
1583 return FirstPhysicalPar()->align;
1587 string LyXParagraph::GetLabestring() const
1589 return FirstPhysicalPar()->labelstring;
1593 int LyXParagraph::GetFirstCounter(int i) const
1595 return FirstPhysicalPar()->counter_[i];
1599 // the next two functions are for the manual labels
1600 string LyXParagraph::GetLabelWidthString() const
1602 if (!FirstPhysicalPar()->labelwidthstring.empty())
1603 return FirstPhysicalPar()->labelwidthstring;
1605 return _("Senseless with this layout!");
1609 void LyXParagraph::SetLabelWidthString(string const & s)
1611 LyXParagraph * par = FirstPhysicalPar();
1613 par->labelwidthstring = s;
1617 void LyXParagraph::SetOnlyLayout(LyXTextClass::LayoutList::size_type new_layout)
1619 LyXParagraph * par = FirstPhysicalPar();
1620 LyXParagraph * ppar = 0;
1621 LyXParagraph * npar = 0;
1623 par->layout = new_layout;
1624 /* table stuff -- begin*/
1627 /* table stuff -- end*/
1628 if (par->pextra_type == PEXTRA_NONE) {
1629 if (par->Previous()) {
1630 ppar = par->Previous()->FirstPhysicalPar();
1633 && (ppar->depth > par->depth))
1634 ppar = ppar->Previous()->FirstPhysicalPar();
1637 npar = par->Next()->NextAfterFootnote();
1640 && (npar->depth > par->depth))
1641 npar = npar->Next()->NextAfterFootnote();
1643 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
1645 p1 = ppar->pextra_width,
1646 p2 = ppar->pextra_widthp;
1647 ppar->SetPExtraType(ppar->pextra_type,
1648 p1.c_str(), p2.c_str());
1650 if ((par->pextra_type == PEXTRA_NONE) &&
1651 npar && (npar->pextra_type != PEXTRA_NONE)) {
1653 p1 = npar->pextra_width,
1654 p2 = npar->pextra_widthp;
1655 npar->SetPExtraType(npar->pextra_type,
1656 p1.c_str(), p2.c_str());
1662 void LyXParagraph::SetLayout(LyXTextClass::LayoutList::size_type new_layout)
1665 * par = FirstPhysicalPar(),
1669 par->layout = new_layout;
1670 par->labelwidthstring.clear();
1671 par->align = LYX_ALIGN_LAYOUT;
1672 par->added_space_top = VSpace(VSpace::NONE);
1673 par->added_space_bottom = VSpace(VSpace::NONE);
1674 /* table stuff -- begin*/
1677 /* table stuff -- end*/
1678 if (par->pextra_type == PEXTRA_NONE) {
1679 if (par->Previous()) {
1680 ppar = par->Previous()->FirstPhysicalPar();
1683 && (ppar->depth > par->depth))
1684 ppar = ppar->Previous()->FirstPhysicalPar();
1687 npar = par->Next()->NextAfterFootnote();
1690 && (npar->depth > par->depth))
1691 npar = npar->Next()->NextAfterFootnote();
1693 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
1695 p1 = ppar->pextra_width,
1696 p2 = ppar->pextra_widthp;
1697 ppar->SetPExtraType(ppar->pextra_type,
1698 p1.c_str(), p2.c_str());
1700 if ((par->pextra_type == PEXTRA_NONE) &&
1701 npar && (npar->pextra_type != PEXTRA_NONE)) {
1703 p1 = npar->pextra_width,
1704 p2 = npar->pextra_widthp;
1705 npar->SetPExtraType(npar->pextra_type,
1706 p1.c_str(), p2.c_str());
1712 // if the layout of a paragraph contains a manual label, the beginning of the
1713 // main body is the beginning of the second word. This is what the par-
1714 // function returns. If the layout does not contain a label, the main
1715 // body always starts with position 0. This differentiation is necessary,
1716 // because there cannot be a newline or a blank <= the beginning of the
1717 // main body in TeX.
1719 int LyXParagraph::BeginningOfMainBody() const
1721 if (FirstPhysicalPar() != this)
1724 // Unroll the first two cycles of the loop
1725 // and remember the previous character to
1726 // remove unnecessary GetChar() calls
1729 && GetChar(i) != LyXParagraph::META_NEWLINE) {
1731 char previous_char, temp;
1733 && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1734 // Yes, this ^ is supposed to be "= " not "=="
1737 && previous_char != ' '
1738 && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1740 previous_char = temp;
1745 if (i == 0 && i == size() &&
1746 !(footnoteflag == LyXParagraph::NO_FOOTNOTE
1747 && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1748 ++i; /* the cursor should not jump
1749 * to the main body if there
1755 LyXParagraph * LyXParagraph::DepthHook(int deth)
1757 LyXParagraph * newpar = this;
1762 newpar = newpar->FirstPhysicalPar()->Previous();
1763 } while (newpar && newpar->GetDepth() > deth
1764 && newpar->footnoteflag == footnoteflag);
1767 if (Previous() || GetDepth())
1768 lyxerr << "ERROR (LyXParagraph::DepthHook): "
1772 return newpar->FirstPhysicalPar();
1776 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
1778 LyXParagraph const * newpar = this;
1783 newpar = newpar->FirstPhysicalPar()->Previous();
1784 } while (newpar && newpar->GetDepth() > deth
1785 && newpar->footnoteflag == footnoteflag);
1788 if (Previous() || GetDepth())
1789 lyxerr << "ERROR (LyXParagraph::DepthHook): "
1793 return newpar->FirstPhysicalPar();
1797 int LyXParagraph::AutoDeleteInsets()
1799 vector<size_type> tmpvec;
1801 for (InsetList::iterator it = insetlist.begin();
1802 it != insetlist.end(); ++it) {
1803 if ((*it).inset && (*it).inset->AutoDelete()) {
1804 tmpvec.push_back((*it).pos);
1808 for (vector<size_type>::const_iterator cit = tmpvec.begin();
1809 cit != tmpvec.end(); ++cit) {
1816 Inset * LyXParagraph::ReturnNextInsetPointer(LyXParagraph::size_type & pos)
1818 InsetList::iterator it2 = insetlist.end();
1819 for (InsetList::iterator it = insetlist.begin();
1820 it != insetlist.end(); ++it) {
1821 if ((*it).pos >= pos) {
1822 if (it2 == insetlist.end() || (*it).pos < (*it2).pos)
1826 if (it2 != insetlist.end()) {
1828 return (*it2).inset;
1834 // returns -1 if inset not found
1835 int LyXParagraph::GetPositionOfInset(Inset * inset) const
1838 for (InsetList::const_iterator cit = insetlist.begin();
1839 cit != insetlist.end(); ++cit) {
1840 if ((*cit).inset == inset) {
1844 // Think about footnotes.
1845 if (footnoteflag == LyXParagraph::NO_FOOTNOTE
1846 && next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1848 NextAfterFootnote()->GetPositionOfInset(inset);
1850 return text.size() + 1 + further;
1856 void LyXParagraph::readSimpleWholeFile(istream & is)
1862 InsertChar(text.size(), c);
1867 LyXParagraph * LyXParagraph::TeXOnePar(string & file, TexRow & texrow,
1868 string & foot, TexRow & foot_texrow,
1871 lyxerr[Debug::LATEX] << "TeXOnePar... " << this << endl;
1872 LyXParagraph * par = next;
1873 LyXLayout const & style =
1874 textclasslist.Style(current_view->buffer()->params.textclass,
1877 bool further_blank_line = false;
1879 lyxerr << "ERROR (LyXParagraph::TeXOnePar) is dummy." << endl;
1881 if (start_of_appendix) {
1882 file += "\\appendix\n";
1886 if (tex_code_break_column && style.isCommand()){
1891 if (pagebreak_top) {
1892 file += "\\newpage";
1893 further_blank_line = true;
1895 if (added_space_top.kind() != VSpace::NONE) {
1896 file += added_space_top.asLatexCommand(current_view->buffer()->params);
1897 further_blank_line = true;
1901 file += "\\lyxline{\\" + getFont(0).latexSize() + '}';
1902 file += "\\vspace{-1\\parskip}";
1903 further_blank_line = true;
1906 if (further_blank_line){
1911 LyXDirection direction = getParDirection();
1912 LyXDirection global_direction =
1913 current_view->buffer()->params.getDocumentDirection();
1914 if (direction != global_direction) {
1915 if (direction == LYX_DIR_LEFT_TO_RIGHT)
1916 file += "\\unsethebrew\n";
1918 file += "\\sethebrew\n";
1923 switch (style.latextype) {
1926 file += style.latexname();
1927 file += style.latexparam();
1929 case LATEX_ITEM_ENVIRONMENT:
1931 bibkey->Latex(file, false);
1935 case LATEX_LIST_ENVIRONMENT:
1942 bool need_par = SimpleTeXOnePar(file, texrow);
1944 // Spit out footnotes
1945 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1946 && par->footnoteflag != footnoteflag) {
1947 par = par->TeXFootnote(file, texrow,
1948 foot, foot_texrow, foot_count,
1950 par->SimpleTeXOnePar(file, texrow);
1954 // Make sure that \\par is done with the font of the last
1955 // character if this has another size as the default.
1956 // This is necessary because LaTeX (and LyX on the screen)
1957 // calculates the space between the baselines according
1958 // to this font. (Matthias)
1959 LyXFont font = getFont(Last()-1);
1961 if (style.resfont.size() != font.size()) {
1963 file += font.latexSize();
1967 } else if (textclasslist.Style(current_view->buffer()->params.textclass,
1968 GetLayout()).isCommand()){
1969 if (style.resfont.size() != font.size()) {
1971 file += font.latexSize();
1975 } else if (style.resfont.size() != font.size()){
1976 file += "{\\" + font.latexSize() + " \\par}";
1979 if (direction != global_direction)
1980 if (direction == LYX_DIR_LEFT_TO_RIGHT)
1981 file += "\\sethebrew";
1983 file += "\\unsethebrew";
1985 switch (style.latextype) {
1986 case LATEX_ITEM_ENVIRONMENT:
1987 case LATEX_LIST_ENVIRONMENT:
1988 if (par && (depth < par->depth)) {
1993 case LATEX_ENVIRONMENT:
1994 // if its the last paragraph of the current environment
1995 // skip it otherwise fall through
1997 && (par->layout != layout
1998 || par->depth != depth
1999 || par->pextra_type != pextra_type))
2002 if (!(footnoteflag != LyXParagraph::NO_FOOTNOTE
2003 && footnotekind != LyXParagraph::FOOTNOTE
2004 && footnotekind != LyXParagraph::MARGIN
2008 // don't insert this if we would be adding it
2009 // before or after a table in a float. This
2010 // little trick is needed in order to allow
2011 // use of tables in \subfigures or \subtables.
2017 further_blank_line = false;
2019 file += "\\lyxline{\\" + getFont(Last()-1).latexSize() + '}';
2020 further_blank_line = true;
2023 if (added_space_bottom.kind() != VSpace::NONE) {
2024 file += added_space_bottom.asLatexCommand(current_view->buffer()->params);
2025 further_blank_line = true;
2028 if (pagebreak_bottom) {
2029 file += "\\newpage";
2030 further_blank_line = true;
2033 if (further_blank_line){
2038 if (!(footnoteflag != LyXParagraph::NO_FOOTNOTE && par &&
2039 par->footnoteflag == LyXParagraph::NO_FOOTNOTE)) {
2044 lyxerr[Debug::LATEX] << "TeXOnePar...done " << par << endl;
2049 // This one spits out the text of the paragraph
2050 bool LyXParagraph::SimpleTeXOnePar(string & file, TexRow & texrow)
2052 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
2055 return SimpleTeXOneTablePar(file, texrow);
2058 size_type main_body;
2060 bool return_value = false;
2062 LyXLayout const & style = textclasslist.Style(current_view->buffer()->params.textclass, GetLayout());
2063 LyXFont basefont, last_font;
2065 // Maybe we have to create a optional argument.
2066 if (style.labeltype != LABEL_MANUAL)
2069 main_body = BeginningOfMainBody();
2071 if (main_body > 0) {
2073 basefont = getFont(-2); // Get label font
2075 basefont = getFont(-1); // Get layout font
2083 if (style.isCommand()) {
2086 } else if (align != LYX_ALIGN_LAYOUT) {
2089 return_value = true;
2093 // Which font is currently active?
2094 LyXFont running_font = basefont;
2095 // Do we have an open font change?
2096 bool open_font = false;
2098 texrow.start(this, 0);
2100 for (size_type i = 0; i < size(); ++i) {
2102 // First char in paragraph or after label?
2103 if (i == main_body && !IsDummy()) {
2104 if (main_body > 0) {
2106 column += running_font.latexWriteEndChanges(file, basefont, basefont);
2109 basefont = getFont(-1); // Now use the layout font
2110 running_font = basefont;
2114 if (style.isCommand()) {
2117 } else if (align != LYX_ALIGN_LAYOUT) {
2120 return_value = true;
2124 file += "\\noindent ";
2128 case LYX_ALIGN_NONE:
2129 case LYX_ALIGN_BLOCK:
2130 case LYX_ALIGN_LAYOUT:
2131 case LYX_ALIGN_SPECIAL: break;
2132 case LYX_ALIGN_LEFT:
2133 file += "\\raggedright ";
2136 case LYX_ALIGN_RIGHT:
2137 file += "\\raggedleft ";
2140 case LYX_ALIGN_CENTER:
2141 file += "\\centering ";
2149 // Fully instantiated font
2150 LyXFont font = getFont(i);
2151 last_font = running_font;
2153 // Spaces at end of font change are simulated to be
2154 // outside font change, i.e. we write "\textXX{text} "
2155 // rather than "\textXX{text }". (Asger)
2156 if (open_font && c == ' ' && i <= size() - 2
2157 && !getFont(i+1).equalExceptLatex(running_font)
2158 && !getFont(i+1).equalExceptLatex(font)) {
2159 font = getFont(i + 1);
2161 // We end font definition before blanks
2162 if (!font.equalExceptLatex(running_font) && open_font) {
2163 column += running_font.latexWriteEndChanges(file,
2165 (i == main_body-1) ? basefont : font);
2166 running_font = basefont;
2170 // Blanks are printed before start of fontswitch
2172 // Do not print the separation of the optional argument
2173 if (i != main_body - 1) {
2174 SimpleTeXBlanks(file, texrow, i,
2175 column, font, style);
2179 // Do we need to change font?
2180 if (!font.equalExceptLatex(running_font)
2181 && i != main_body-1) {
2182 column += font.latexWriteStartChanges(file, basefont, last_font);
2183 running_font = font;
2187 if (c == LyXParagraph::META_NEWLINE) {
2188 // newlines are handled differently here than
2189 // the default in SimpleTeXSpecialChars().
2190 if (!style.newline_allowed
2191 || font.latex() == LyXFont::ON) {
2195 column += running_font.latexWriteEndChanges(file, basefont, basefont);
2198 basefont = getFont(-1);
2199 running_font = basefont;
2200 if (font.family() ==
2201 LyXFont::TYPEWRITER_FAMILY) {
2207 texrow.start(this, i + 1);
2210 SimpleTeXSpecialChars(file, texrow,
2211 font, running_font, basefont,
2212 open_font, style, i, column, c);
2216 // If we have an open font definition, we have to close it
2218 running_font.latexWriteEndChanges(file, basefont, basefont);
2221 // Needed if there is an optional argument but no contents.
2222 if (main_body > 0 && main_body == size()) {
2224 return_value = false;
2227 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
2228 return return_value;
2232 // This one spits out the text of a table paragraph
2233 bool LyXParagraph::SimpleTeXOneTablePar(string & file, TexRow & texrow)
2235 lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar... " << this << endl;
2237 bool return_value = false;
2239 LyXLayout const & style =
2240 textclasslist.Style(current_view->buffer()->params.textclass,
2244 if (!IsDummy()) { // it is dummy if it is in a float!!!
2245 if (style.isCommand()) {
2248 } else if (align != LYX_ALIGN_LAYOUT) {
2251 return_value = true;
2254 file += "\\noindent ";
2258 case LYX_ALIGN_NONE:
2259 case LYX_ALIGN_BLOCK:
2260 case LYX_ALIGN_LAYOUT:
2261 case LYX_ALIGN_SPECIAL: break;
2262 case LYX_ALIGN_LEFT:
2263 file += "\\raggedright ";
2266 case LYX_ALIGN_RIGHT:
2267 file += "\\raggedleft ";
2270 case LYX_ALIGN_CENTER:
2271 file += "\\centering ";
2277 LyXFont basefont = getFont(-1); // Get layout font
2278 // Which font is currently active?
2279 LyXFont running_font = basefont;
2281 // Do we have an open font change?
2282 bool open_font = false;
2283 int current_cell_number = -1;
2284 int tmp = table->TexEndOfCell(file, current_cell_number);
2285 for (; tmp > 0 ; --tmp)
2288 texrow.start(this, 0);
2290 for (size_type i = 0; i < size(); ++i) {
2291 char c = GetChar(i);
2292 if (table->IsContRow(current_cell_number + 1)) {
2293 if (c == LyXParagraph::META_NEWLINE)
2294 ++current_cell_number;
2299 // Fully instantiated font
2300 LyXFont font = getFont(i);
2301 last_font = running_font;
2303 // Spaces at end of font change are simulated to be
2304 // outside font change.
2305 // i.e. we write "\textXX{text} " rather than
2306 // "\textXX{text }". (Asger)
2307 if (open_font && c == ' ' && i <= size() - 2
2308 && getFont(i+1) != running_font && getFont(i+1) != font) {
2309 font = getFont(i+1);
2312 // We end font definition before blanks
2313 if (font != running_font && open_font) {
2314 column += running_font.latexWriteEndChanges(file,
2316 running_font = basefont;
2319 // Blanks are printed before start of fontswitch
2321 SimpleTeXBlanks(file, texrow, i, column, font, style);
2323 // Do we need to change font?
2324 if (font != running_font) {
2325 column += font.latexWriteStartChanges(file, basefont, last_font);
2326 running_font = font;
2329 // Do we need to turn on LaTeX mode?
2330 if (font.latex() != running_font.latex()) {
2331 if (font.latex() == LyXFont::ON
2332 && style.needprotect) {
2333 file += "\\protect ";
2337 if (c == LyXParagraph::META_NEWLINE) {
2338 // special case for inside a table
2339 // different from default case in
2340 // SimpleTeXSpecialChars()
2342 column += running_font
2343 .latexWriteEndChanges(file, basefont, basefont);
2346 basefont = getFont(-1);
2347 running_font = basefont;
2348 ++current_cell_number;
2349 if (table->CellHasContRow(current_cell_number) >= 0) {
2350 TeXContTableRows(file, i + 1,
2351 current_cell_number,
2354 // if this cell follow only ContRows till end don't
2355 // put the EndOfCell because it is put after the
2357 if (table->ShouldBeVeryLastCell(current_cell_number)) {
2358 --current_cell_number;
2361 int tmp = table->TexEndOfCell(file,
2362 current_cell_number);
2365 } else if (tmp < 0) {
2371 texrow.start(this, i + 1);
2373 SimpleTeXSpecialChars(file, texrow,
2374 font, running_font, basefont,
2375 open_font, style, i, column, c);
2379 // If we have an open font definition, we have to close it
2381 running_font.latexWriteEndChanges(file, basefont, basefont);
2383 ++current_cell_number;
2384 tmp = table->TexEndOfCell(file, current_cell_number);
2385 for (; tmp > 0; --tmp)
2387 lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar...done " << this << endl;
2388 return return_value;
2392 // This one spits out the text off ContRows in tables
2393 bool LyXParagraph::TeXContTableRows(string & file,
2394 LyXParagraph::size_type i,
2395 int current_cell_number,
2396 int & column, TexRow & texrow)
2398 lyxerr[Debug::LATEX] << "TeXContTableRows... " << this << endl;
2404 bool return_value = false;
2405 LyXLayout const & style =
2406 textclasslist.Style(current_view->buffer()->params.textclass,
2408 LyXFont basefont = getFont(-1); // Get layout font
2410 // Which font is currently active?
2411 LyXFont running_font = basefont;
2412 // Do we have an open font change?
2413 bool open_font = false;
2415 size_type lastpos = i;
2416 int cell = table->CellHasContRow(current_cell_number);
2417 ++current_cell_number;
2419 // first find the right position
2421 for (; (i < size()) && (current_cell_number<cell); ++i) {
2423 if (c == LyXParagraph::META_NEWLINE)
2424 ++current_cell_number;
2428 if (table->Linebreaks(table->FirstVirtualCell(cell))) {
2432 } else if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
2437 && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
2441 // Fully instantiated font
2442 LyXFont font = getFont(i);
2443 last_font = running_font;
2445 // Spaces at end of font change are simulated to
2446 // be outside font change. i.e. we write
2447 // "\textXX{text} " rather than "\textXX{text }".
2449 if (open_font && c == ' ' && i <= size() - 2
2450 && getFont(i + 1) != running_font
2451 && getFont(i + 1) != font) {
2452 font = getFont(i + 1);
2455 // We end font definition before blanks
2456 if (font != running_font && open_font) {
2457 column += running_font.latexWriteEndChanges(file, basefont, font);
2458 running_font = basefont;
2461 // Blanks are printed before start of fontswitch
2463 SimpleTeXBlanks(file, texrow, i,
2464 column, font, style);
2466 // Do we need to change font?
2467 if (font != running_font) {
2469 font.latexWriteStartChanges(file,
2470 basefont, last_font);
2471 running_font = font;
2474 // Do we need to turn on LaTeX mode?
2475 if (font.latex() != running_font.latex()) {
2476 if (font.latex() == LyXFont::ON
2477 && style.needprotect)
2479 file += "\\protect ";
2483 SimpleTeXSpecialChars(file, texrow, font,
2484 running_font, basefont,
2485 open_font, style, i, column, c);
2487 // If we have an open font definition, we have to close it
2489 running_font.latexWriteEndChanges(file, basefont, basefont);
2492 basefont = getFont(-1);
2493 running_font = basefont;
2494 cell = table->CellHasContRow(current_cell_number);
2496 lyxerr[Debug::LATEX] << "TeXContTableRows...done " << this << endl;
2497 return return_value;
2501 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
2503 bool retval = false;
2505 case LyXParagraph::META_HFILL:
2506 sgml_string.clear();
2508 case LyXParagraph::META_PROTECTED_SEPARATOR:
2511 case LyXParagraph::META_NEWLINE:
2515 sgml_string = "&";
2518 sgml_string = "<";
2521 sgml_string = ">";
2524 sgml_string = "$";
2527 sgml_string = "#";
2530 sgml_string = "%";
2533 sgml_string = "[";
2536 sgml_string = "]";
2539 sgml_string = "{";
2542 sgml_string = "}";
2545 sgml_string = "˜";
2548 sgml_string = """;
2551 sgml_string = "\";
2557 case '\0': // Ignore :-)
2558 sgml_string.clear();
2568 void LyXParagraph::SimpleDocBookOneTablePar(string & file, string & extra,
2569 int & desc_on, int depth)
2572 lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar... " << this << endl;
2574 LyXFont font1, font2;
2577 size_type main_body;
2578 string emph = "emphasis";
2579 bool emph_flag = false;
2581 LyXLayout const & style =
2582 textclasslist.Style(current_view->buffer()->params.textclass,
2585 if (style.labeltype != LABEL_MANUAL)
2588 main_body = BeginningOfMainBody();
2590 // Gets paragraph main font.
2592 font1 = style.labelfont;
2596 int char_line_count = depth;
2597 addNewlineAndDepth(file, depth);
2598 if (footnoteflag == LyXParagraph::NO_FOOTNOTE) {
2599 file += "<INFORMALTABLE>";
2600 addNewlineAndDepth(file, ++depth);
2602 int current_cell_number = -1;
2603 int tmp = table->DocBookEndOfCell(file, current_cell_number, depth);
2605 // Parsing main loop.
2606 for (size_type i = 0; i < size(); ++i) {
2608 if (table->IsContRow(current_cell_number+1)) {
2609 if (c == LyXParagraph::META_NEWLINE)
2610 ++current_cell_number;
2615 // Fully instantiated font
2618 // Handle <emphasis> tag.
2619 if (font1.emph() != font2.emph() && i) {
2620 if (font2.emph() == LyXFont::ON) {
2621 file += "<emphasis>";
2623 } else if (emph_flag) {
2624 file += "</emphasis>";
2628 if (c == LyXParagraph::META_NEWLINE) {
2629 // We have only to control for emphasis open here!
2631 file += "</emphasis>";
2634 font1 = font2 = getFont(-1);
2635 ++current_cell_number;
2636 if (table->CellHasContRow(current_cell_number) >= 0) {
2637 DocBookContTableRows(file, extra, desc_on, i+1,
2638 current_cell_number,
2641 // if this cell follow only ContRows till end don't
2642 // put the EndOfCell because it is put after the
2644 if (table->ShouldBeVeryLastCell(current_cell_number)) {
2645 --current_cell_number;
2648 tmp = table->DocBookEndOfCell(file,
2649 current_cell_number,
2654 } else if (c == LyXParagraph::META_INSET) {
2655 inset = GetInset(i);
2657 inset->DocBook(tmp_out);
2659 // This code needs some explanation:
2660 // Two insets are treated specially
2661 // label if it is the first element in a
2662 // command paragraph
2664 // graphics inside tables or figure floats
2666 // title (the equivalente in latex for this
2668 // and title should come first
2671 if(desc_on != 3 || i != 0) {
2672 if(tmp_out[0] == '@') {
2674 extra += frontStrip(tmp_out,
2677 file += frontStrip(tmp_out,
2682 } else if (font2.latex() == LyXFont::ON) {
2683 // "TeX"-Mode on == > SGML-Mode on.
2689 if (linuxDocConvertChar(c, sgml_string)
2690 && !style.free_spacing) {
2691 // in freespacing mode, spaces are
2692 // non-breaking characters
2697 file += "</term><listitem><para>";
2703 file += sgml_string;
2709 // Needed if there is an optional argument but no contents.
2710 if (main_body > 0 && main_body == size()) {
2715 file += "</emphasis>";
2718 ++current_cell_number;
2719 tmp = table->DocBookEndOfCell(file, current_cell_number, depth);
2720 // Resets description flag correctly.
2723 // <term> not closed...
2727 if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
2728 file += "</INFORMALTABLE>";
2730 lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar...done "
2735 void LyXParagraph::DocBookContTableRows(string & file, string & extra,
2737 LyXParagraph::size_type i,
2738 int current_cell_number, int &column)
2743 lyxerr[Debug::LATEX] << "DocBookContTableRows... " << this << endl;
2748 string emph= "emphasis";
2749 bool emph_flag= false;
2750 int char_line_count= 0;
2752 LyXLayout const & style =
2753 textclasslist.Style(current_view->buffer()->params.textclass,
2756 size_type main_body;
2757 if (style.labeltype != LABEL_MANUAL)
2760 main_body = BeginningOfMainBody();
2762 // Gets paragraph main font.
2765 font1 = style.labelfont;
2769 size_type lastpos = i;
2770 int cell = table->CellHasContRow(current_cell_number);
2771 ++current_cell_number;
2773 // first find the right position
2775 for (; i < size() && current_cell_number < cell; ++i) {
2777 if (c == LyXParagraph::META_NEWLINE)
2778 ++current_cell_number;
2782 // I don't know how to handle this so I comment it
2783 // for the moment (Jug)
2784 // if (table->Linebreaks(table->FirstVirtualCell(cell))) {
2785 // file += " \\\\\n";
2788 if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
2793 && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
2797 // Fully instantiated font
2800 // Handle <emphasis> tag.
2801 if (font1.emph() != font2.emph() && i) {
2802 if (font2.emph() == LyXFont::ON) {
2803 file += "<emphasis>";
2805 } else if (emph_flag) {
2806 file += "</emphasis>";
2810 if (c == LyXParagraph::META_INSET) {
2811 inset = GetInset(i);
2813 inset->DocBook(tmp_out);
2815 // This code needs some explanation:
2816 // Two insets are treated specially
2817 // label if it is the first element in a
2818 // command paragraph
2820 // graphics inside tables or figure floats
2821 // can't go on title (the equivalente in
2822 // latex for this case is caption and title
2823 // should come first
2826 if(desc_on != 3 || i != 0) {
2827 if(tmp_out[0] == '@') {
2829 extra += frontStrip(tmp_out, '@');
2831 file += frontStrip(tmp_out, '@');
2835 } else if (font2.latex() == LyXFont::ON) {
2836 // "TeX"-Mode on == > SGML-Mode on.
2842 if (linuxDocConvertChar(c, sgml_string)
2843 && !style.free_spacing) {
2844 // in freespacing mode, spaces are
2845 // non-breaking characters
2850 file += "</term><listitem><para>";
2856 file += sgml_string;
2860 // we have only to control for emphasis open here!
2862 file += "</emphasis>";
2865 font1 = font2 = getFont(-1);
2866 cell = table->CellHasContRow(current_cell_number);
2868 lyxerr[Debug::LATEX] << "DocBookContTableRows...done " << this << endl;
2872 void LyXParagraph::SimpleTeXBlanks(string & file, TexRow & texrow,
2873 LyXParagraph::size_type const i,
2874 int & column, LyXFont const & font,
2875 LyXLayout const & style)
2877 if (column > tex_code_break_column
2879 && GetChar(i - 1) != ' '
2881 // In LaTeX mode, we don't want to
2882 // break lines since some commands
2884 && ! (font.latex() == LyXFont::ON)
2885 // same in FreeSpacing mode
2886 && !style.free_spacing
2887 // In typewriter mode, we want to avoid
2888 // ! . ? : at the end of a line
2889 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
2890 && (GetChar(i-1) == '.'
2891 || GetChar(i-1) == '?'
2892 || GetChar(i-1) == ':'
2893 || GetChar(i-1) == '!'))) {
2894 if (tex_code_break_column == 0) {
2895 // in batchmode we need LaTeX to still
2896 // see it as a space not as an extra '\n'
2902 texrow.start(this, i+1);
2904 } else if (font.latex() == LyXFont::OFF) {
2905 if (style.free_spacing) {
2914 void LyXParagraph::SimpleTeXSpecialChars(string & file, TexRow & texrow,
2916 LyXFont & running_font,
2919 LyXLayout const & style,
2920 LyXParagraph::size_type & i,
2921 int & column, char const c)
2923 // Two major modes: LaTeX or plain
2924 // Handle here those cases common to both modes
2925 // and then split to handle the two modes separately.
2927 case LyXParagraph::META_INSET: {
2928 Inset * inset = GetInset(i);
2931 int len = file.length();
2932 if ((inset->LyxCode() == Inset::GRAPHICS_CODE
2933 || inset->LyxCode() == Inset::MATH_CODE
2934 || inset->LyxCode() == Inset::URL_CODE)
2935 && running_font.getFontDirection()
2936 == LYX_DIR_RIGHT_TO_LEFT) {
2940 int tmp = inset->Latex(file, style.isCommand());
2947 column += file.length() - len;
2956 case LyXParagraph::META_NEWLINE:
2958 column += running_font.latexWriteEndChanges(file,
2959 basefont, basefont);
2962 basefont = getFont(-1);
2963 running_font = basefont;
2966 case LyXParagraph::META_HFILL:
2967 file += "\\hfill{}";
2972 // And now for the special cases within each mode
2973 // Are we in LaTeX mode?
2974 if (font.latex() == LyXFont::ON) {
2975 // at present we only have one option
2976 // but I'll leave it as a switch statement
2977 // so its simpler to extend. (ARRae)
2979 case LyXParagraph::META_PROTECTED_SEPARATOR:
2984 // make sure that we will not print
2985 // error generating chars to the tex
2986 // file. This test would not be needed
2987 // if it were done in the buffer
2995 // Plain mode (i.e. not LaTeX)
2997 case LyXParagraph::META_PROTECTED_SEPARATOR:
3002 file += "\\textbackslash{}";
3006 case '°': case '±': case '²': case '³':
3007 case '×': case '÷': case '¹': case 'ª':
3008 case 'º': case '¬': case 'µ':
3009 if (current_view->buffer()->params.inputenc == "latin1") {
3010 file += "\\ensuremath{";
3019 case '|': case '<': case '>':
3020 // In T1 encoding, these characters exist
3021 if (lyxrc->fontenc == "T1") {
3023 //... but we should avoid ligatures
3024 if ((c == '>' || c == '<')
3026 && GetChar(i+1) == c){
3027 file += "\\textcompwordmark{}";
3032 // Typewriter font also has them
3033 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
3037 // Otherwise, we use what LaTeX
3041 file += "\\textless{}";
3045 file += "\\textgreater{}";
3049 file += "\\textbar{}";
3055 case '-': // "--" in Typewriter mode -> "-{}-"
3057 && GetChar(i + 1) == '-'
3058 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
3067 file += "\\char`\\\"{}";
3072 if (current_view->buffer()->params.inputenc == "default") {
3073 file += "\\pounds{}";
3081 case '%': case '#': case '{':
3089 file += "\\textasciitilde{}";
3094 file += "\\textasciicircum{}";
3098 case '*': case '[': case ']':
3099 // avoid being mistaken for optional arguments
3107 // Blanks are printed before font switching.
3108 // Sure? I am not! (try nice-latex)
3109 // I am sure it's correct. LyX might be smarter
3110 // in the future, but for now, nothing wrong is
3115 /* idea for labels --- begin*/
3119 && font.family() != LyXFont::TYPEWRITER_FAMILY
3120 && GetChar(i + 1) == 'y'
3121 && GetChar(i + 2) == 'X') {
3129 && font.family() != LyXFont::TYPEWRITER_FAMILY
3130 && GetChar(i + 1) == 'e'
3131 && GetChar(i + 2) == 'X') {
3136 // Check for "LaTeX2e"
3139 && font.family() != LyXFont::TYPEWRITER_FAMILY
3140 && GetChar(i + 1) == 'a'
3141 && GetChar(i + 2) == 'T'
3142 && GetChar(i + 3) == 'e'
3143 && GetChar(i + 4) == 'X'
3144 && GetChar(i + 5) == '2'
3145 && GetChar(i + 6) == 'e') {
3146 file += "\\LaTeXe{}";
3150 // Check for "LaTeX"
3153 && font.family() != LyXFont::TYPEWRITER_FAMILY
3154 && GetChar(i + 1) == 'a'
3155 && GetChar(i + 2) == 'T'
3156 && GetChar(i + 3) == 'e'
3157 && GetChar(i + 4) == 'X') {
3158 file += "\\LaTeX{}";
3161 /* idea for labels --- end*/
3162 } else if (c != '\0') {
3172 bool LyXParagraph::RoffContTableRows(ostream & os,
3173 LyXParagraph::size_type i,
3179 LyXFont font1(LyXFont::ALL_INHERIT);
3184 string fname2 = TmpFileName(string(), "RAT2");
3186 int cell = table->CellHasContRow(actcell);
3189 // first find the right position
3191 for (; i < size() && actcell < cell; ++i) {
3193 if (c == LyXParagraph::META_NEWLINE)
3198 if ((c != ' ') && (c != LyXParagraph::META_NEWLINE))
3201 && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
3203 font2 = GetFontSettings(i);
3204 if (font1.latex() != font2.latex()) {
3205 if (font2.latex() != LyXFont::OFF)
3210 case LyXParagraph::META_INSET:
3211 if ((inset = GetInset(i))) {
3212 fstream fs(fname2.c_str(),
3215 WriteAlert(_("LYX_ERROR:"),
3216 _("Cannot open temporary file:"),
3220 inset->Latex(fs, -1);
3233 case LyXParagraph::META_NEWLINE:
3235 case LyXParagraph::META_HFILL:
3237 case LyXParagraph::META_PROTECTED_SEPARATOR:
3246 lyxerr.debug() << "RoffAsciiTable: "
3247 "NULL char in structure."
3252 cell = table->CellHasContRow(actcell);
3258 LyXParagraph * LyXParagraph::TeXDeeper(string & file, TexRow & texrow,
3259 string & foot, TexRow & foot_texrow,
3262 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << endl;
3263 LyXParagraph * par = this;
3265 while (par && par->depth == depth) {
3267 lyxerr << "ERROR (LyXParagraph::TeXDeeper)" << endl;
3268 if (textclasslist.Style(current_view->buffer()->params.textclass,
3269 par->layout).isEnvironment()
3270 || par->pextra_type != PEXTRA_NONE)
3272 par = par->TeXEnvironment(file, texrow,
3276 par = par->TeXOnePar(file, texrow,
3281 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
3287 LyXParagraph * LyXParagraph::TeXEnvironment(string & file, TexRow & texrow,
3289 TexRow & foot_texrow,
3292 bool eindent_open = false;
3293 bool foot_this_level = false;
3294 // flags when footnotetext should be appended to file.
3295 static bool minipage_open = false;
3296 static int minipage_open_depth = 0;
3297 char par_sep = current_view->buffer()->params.paragraph_separation;
3299 lyxerr[Debug::LATEX] << "TeXEnvironment... " << this << endl;
3301 lyxerr << "ERROR (LyXParagraph::TeXEnvironment)" << endl;
3303 LyXLayout const & style =
3304 textclasslist.Style(current_view->buffer()->params.textclass,
3307 if (pextra_type == PEXTRA_INDENT) {
3308 if (!pextra_width.empty()) {
3309 file += "\\begin{LyXParagraphIndent}{"
3310 + pextra_width + "}\n";
3312 //float ib = atof(pextra_widthp.c_str())/100;
3313 // string can't handle floats at present (971109)
3314 // so I'll do a conversion by hand knowing that
3315 // the limits are 0.0 to 1.0. ARRae.
3316 file += "\\begin{LyXParagraphIndent}{";
3317 switch (pextra_widthp.length()) {
3323 file += pextra_widthp;
3327 file += pextra_widthp;
3329 file += "\\columnwidth}\n";
3332 eindent_open = true;
3334 if ((pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3335 if (pextra_hfill && Previous() &&
3336 (Previous()->pextra_type == PEXTRA_MINIPAGE)) {
3337 file += "\\hfill{}\n";
3340 if (par_sep == BufferParams::PARSEP_INDENT) {
3341 file += "{\\setlength\\parindent{0pt}\n";
3344 file += "\\begin{minipage}";
3345 switch(pextra_alignment) {
3346 case MINIPAGE_ALIGN_TOP:
3349 case MINIPAGE_ALIGN_MIDDLE:
3352 case MINIPAGE_ALIGN_BOTTOM:
3356 if (!pextra_width.empty()) {
3358 file += pextra_width + "}\n";
3360 //float ib = atof(par->pextra_width.c_str())/100;
3361 // string can't handle floats at present
3362 // so I'll do a conversion by hand knowing that
3363 // the limits are 0.0 to 1.0. ARRae.
3365 switch (pextra_widthp.length()) {
3371 file += pextra_widthp;
3375 file += pextra_widthp;
3377 file += "\\columnwidth}\n";
3380 if (par_sep == BufferParams::PARSEP_INDENT) {
3381 file += "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3384 minipage_open = true;
3385 minipage_open_depth = depth;
3388 #ifdef WITH_WARNINGS
3389 #warning Define FANCY_FOOTNOTE_CODE to re-enable Allan footnote code
3390 //I disabled it because it breaks when lists span on several
3393 if (style.isEnvironment()){
3394 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
3395 #ifdef FANCY_FOOTNOTE_CODE
3396 if (foot_count < 0) {
3397 // flag that footnote[mark][text] should be
3398 // used for any footnotes from now on
3400 foot_this_level = true;
3403 file += "\\begin{" + style.latexname() + "}{"
3404 + labelwidthstring + "}\n";
3405 } else if (style.labeltype == LABEL_BIBLIO) {
3407 file += "\\begin{" + style.latexname() + "}{"
3408 + bibitemWidthest(current_view->painter())
3410 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
3411 #ifdef FANCY_FOOTNOTE_CODE
3412 if (foot_count < 0) {
3413 // flag that footnote[mark][text] should be
3414 // used for any footnotes from now on
3416 foot_this_level = true;
3419 file += "\\begin{" + style.latexname() + '}'
3420 + style.latexparam() + '\n';
3422 file += "\\begin{" + style.latexname() + '}'
3423 + style.latexparam() + '\n';
3426 LyXParagraph * par = this;
3428 par = par->TeXOnePar(file, texrow,
3429 foot, foot_texrow, foot_count);
3431 if (minipage_open && par && !style.isEnvironment() &&
3432 (par->pextra_type == PEXTRA_MINIPAGE) &&
3433 par->pextra_start_minipage) {
3434 file += "\\end{minipage}\n";
3436 if (par_sep == BufferParams::PARSEP_INDENT) {
3440 minipage_open = false;
3442 if (par && par->depth > depth) {
3443 if (textclasslist.Style(current_view->buffer()->params.textclass,
3444 par->layout).isParagraph()
3446 && !suffixIs(file, "\n\n")) {
3447 // There should be at least one '\n' already
3448 // but we need there to be two for Standard
3449 // paragraphs that are depth-increment'ed to be
3450 // output correctly. However, tables can
3451 // also be paragraphs so don't adjust them.
3456 par = par->TeXDeeper(file, texrow,
3457 foot, foot_texrow, foot_count);
3459 if (par && par->layout == layout && par->depth == depth &&
3460 (par->pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3461 if (par->pextra_hfill && par->Previous() &&
3462 (par->Previous()->pextra_type == PEXTRA_MINIPAGE)){
3463 file += "\\hfill{}\n";
3466 if (par_sep == BufferParams::PARSEP_INDENT) {
3467 file += "{\\setlength\\parindent{0pt}\n";
3470 file += "\\begin{minipage}";
3471 switch(par->pextra_alignment) {
3472 case MINIPAGE_ALIGN_TOP:
3475 case MINIPAGE_ALIGN_MIDDLE:
3478 case MINIPAGE_ALIGN_BOTTOM:
3482 if (!par->pextra_width.empty()) {
3484 file += par->pextra_width;
3487 //float ib = atof(par->pextra_widthp.c_str())/100;
3488 // string can't handle floats at present
3489 // so I'll do a conversion by hand knowing that
3490 // the limits are 0.0 to 1.0. ARRae.
3492 switch (par->pextra_widthp.length()) {
3498 file += par->pextra_widthp;
3502 file += par->pextra_widthp;
3504 file += "\\columnwidth}\n";
3507 if (par_sep == BufferParams::PARSEP_INDENT) {
3508 file += "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3511 minipage_open = true;
3512 minipage_open_depth = par->depth;
3515 && par->layout == layout
3516 && par->depth == depth
3517 && par->pextra_type == pextra_type);
3519 if (style.isEnvironment()) {
3520 file += "\\end{" + style.latexname() + '}';
3521 // maybe this should go after the minipage closes?
3522 if (foot_this_level) {
3523 if (foot_count >= 1) {
3524 if (foot_count > 1) {
3525 file += "\\addtocounter{footnote}{-";
3526 file += tostr(foot_count - 1);
3530 texrow += foot_texrow;
3532 foot_texrow.reset();
3537 if (minipage_open && (minipage_open_depth == depth) &&
3538 (!par || par->pextra_start_minipage ||
3539 par->pextra_type != PEXTRA_MINIPAGE)) {
3540 file += "\\end{minipage}\n";
3542 if (par_sep == BufferParams::PARSEP_INDENT) {
3546 if (par && par->pextra_type != PEXTRA_MINIPAGE) {
3547 file += "\\medskip\n\n";
3551 minipage_open = false;
3554 file += "\\end{LyXParagraphIndent}\n";
3557 if (!(par && (par->pextra_type == PEXTRA_MINIPAGE)
3558 && par->pextra_hfill)) {
3562 lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
3563 return par; // ale970302
3567 LyXParagraph * LyXParagraph::TeXFootnote(string & file, TexRow & texrow,
3568 string & foot, TexRow & foot_texrow,
3570 LyXDirection par_direction)
3572 lyxerr[Debug::LATEX] << "TeXFootnote... " << this << endl;
3573 if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
3574 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3575 "No footnote!" << endl;
3577 LyXParagraph * par = this;
3578 LyXLayout const & style = textclasslist.Style(current_view->buffer()->params.textclass,
3579 previous->GetLayout());
3581 if (style.needprotect && footnotekind != LyXParagraph::FOOTNOTE){
3582 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3583 "Float other than footnote in command"
3584 " with moving argument is illegal" << endl;
3587 if (footnotekind != LyXParagraph::FOOTNOTE
3588 && footnotekind != LyXParagraph::MARGIN
3590 && !suffixIs(file, '\n')) {
3591 // we need to ensure that real floats like tables and figures
3592 // have their \begin{} on a new line otherwise we can get
3593 // incorrect results when using the endfloat.sty package
3594 // especially if two floats follow one another. ARRae 981022
3595 // NOTE: if the file is length 0 it must have just been
3596 // written out so we assume it ended with a '\n'
3601 BufferParams * params = ¤t_view->buffer()->params;
3602 bool footer_in_body = true;
3603 switch (footnotekind) {
3604 case LyXParagraph::FOOTNOTE:
3605 if (style.intitle) {
3606 file += "\\thanks{\n";
3607 footer_in_body = false;
3609 if (foot_count == -1) {
3610 // we're at depth 0 so we can use:
3611 file += "\\footnote{%\n";
3612 footer_in_body = false;
3614 file += "\\footnotemark{}%\n";
3616 // we only need this when there are
3617 // multiple footnotes
3618 foot += "\\stepcounter{footnote}";
3620 foot += "\\footnotetext{%\n";
3621 foot_texrow.start(this, 0);
3622 foot_texrow.newline();
3627 case LyXParagraph::MARGIN:
3628 file += "\\marginpar{\n";
3630 case LyXParagraph::FIG:
3631 if (pextra_type == PEXTRA_FLOATFLT
3632 && (!pextra_width.empty()
3633 || !pextra_widthp.empty())) {
3635 if (!pextra_width.empty())
3636 sprintf(bufr, "\\begin{floatingfigure}{%s}\n",
3637 pextra_width.c_str());
3640 "\\begin{floatingfigure}{%f\\textwidth}\n",
3641 atoi(pextra_widthp.c_str())/100.0);
3644 file += "\\begin{figure}";
3645 if (!params->float_placement.empty()) {
3647 file += params->float_placement;
3654 case LyXParagraph::TAB:
3655 file += "\\begin{table}";
3656 if (!params->float_placement.empty()) {
3658 file += params->float_placement;
3664 case LyXParagraph::WIDE_FIG:
3665 file += "\\begin{figure*}";
3666 if (!params->float_placement.empty()) {
3668 file += params->float_placement;
3674 case LyXParagraph::WIDE_TAB:
3675 file += "\\begin{table*}";
3676 if (!params->float_placement.empty()) {
3678 file += params->float_placement;
3684 case LyXParagraph::ALGORITHM:
3685 file += "\\begin{algorithm}\n";
3691 LyXDirection direction = getParDirection();
3692 if (direction != par_direction) {
3693 if (direction == LYX_DIR_LEFT_TO_RIGHT)
3694 file += "\\unsethebrew\n";
3696 file += "\\sethebrew\n";
3700 if (footnotekind != LyXParagraph::FOOTNOTE
3701 || !footer_in_body) {
3702 // Process text for all floats except footnotes in body
3704 LyXLayout const & style =
3705 textclasslist.Style(current_view->buffer()->params.textclass,
3708 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3710 if (style.isEnvironment()
3711 || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3712 // Allows the use of minipages within float
3713 // environments. Shouldn't be circular because
3714 // we don't support footnotes inside
3715 // floats (yet). ARRae
3716 par = par->TeXEnvironment(file, texrow,
3720 par = par->TeXOnePar(file, texrow,
3725 if (par && !par->IsDummy() && par->depth > depth) {
3726 par = par->TeXDeeper(file, texrow,
3730 } while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3732 // process footnotes > depth 0 or in environments separately
3733 // NOTE: Currently don't support footnotes within footnotes
3734 // even though that is possible using the \footnotemark
3736 TexRow dummy_texrow;
3737 int dummy_count = 0;
3739 LyXLayout const & style =
3740 textclasslist.Style(current_view->buffer()->params.textclass,
3743 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3745 if (style.isEnvironment()
3746 || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3747 // Allows the use of minipages within float
3748 // environments. Shouldn't be circular because
3749 // we don't support footnotes inside
3750 // floats (yet). ARRae
3751 par = par->TeXEnvironment(foot, foot_texrow,
3752 dummy, dummy_texrow,
3755 par = par->TeXOnePar(foot, foot_texrow,
3756 dummy, dummy_texrow,
3760 if (par && !par->IsDummy() && par->depth > depth) {
3761 par = par->TeXDeeper(foot, foot_texrow,
3762 dummy, dummy_texrow,
3766 && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3768 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3769 "Footnote in a Footnote -- not supported"
3774 switch (footnotekind) {
3775 case LyXParagraph::FOOTNOTE:
3776 if (footer_in_body) {
3777 // This helps tell which of the multiple
3778 // footnotetexts an error was in.
3780 foot_texrow.newline();
3785 case LyXParagraph::MARGIN:
3788 case LyXParagraph::FIG:
3789 if (pextra_type == PEXTRA_FLOATFLT
3790 && (!pextra_width.empty()
3791 || !pextra_widthp.empty()))
3792 file += "\\end{floatingfigure}";
3794 file += "\\end{figure}";
3796 case LyXParagraph::TAB:
3797 file += "\\end{table}";
3799 case LyXParagraph::WIDE_FIG:
3800 file += "\\end{figure*}";
3802 case LyXParagraph::WIDE_TAB:
3803 file += "\\end{table*}";
3805 case LyXParagraph::ALGORITHM:
3806 file += "\\end{algorithm}";
3810 if (footnotekind != LyXParagraph::FOOTNOTE
3811 && footnotekind != LyXParagraph::MARGIN) {
3812 // we need to ensure that real floats like tables and figures
3813 // have their \end{} on a line of their own otherwise we can
3814 // get incorrect results when using the endfloat.sty package.
3819 lyxerr[Debug::LATEX] << "TeXFootnote...done " << par->next << endl;
3824 void LyXParagraph::SetPExtraType(int type, char const * width,
3825 char const * widthp)
3828 pextra_width = width;
3829 pextra_widthp = widthp;
3831 if (textclasslist.Style(current_view->buffer()->params.textclass,
3832 layout).isEnvironment()) {
3837 while (par && (par->layout == layout)
3838 && (par->depth == depth)) {
3840 par = par->Previous();
3842 par = par->FirstPhysicalPar();
3843 while (par && par->depth > depth) {
3844 par = par->Previous();
3846 par = par->FirstPhysicalPar();
3850 while (par && (par->layout == layout)
3851 && (par->depth == depth)) {
3852 par->pextra_type = type;
3853 par->pextra_width = width;
3854 par->pextra_widthp = widthp;
3855 par = par->NextAfterFootnote();
3856 if (par && (par->depth > depth))
3857 par->SetPExtraType(type, width, widthp);
3858 while (par && ((par->depth > depth) || par->IsDummy()))
3859 par = par->NextAfterFootnote();
3865 void LyXParagraph::UnsetPExtraType()
3867 if (pextra_type == PEXTRA_NONE)
3870 pextra_type = PEXTRA_NONE;
3871 pextra_width.clear();
3872 pextra_widthp.clear();
3874 if (textclasslist.Style(current_view->buffer()->params.textclass,
3875 layout).isEnvironment()) {
3880 while (par && (par->layout == layout)
3881 && (par->depth == depth)) {
3883 par = par->Previous();
3885 par = par->FirstPhysicalPar();
3886 while (par && par->depth > depth) {
3887 par = par->Previous();
3889 par = par->FirstPhysicalPar();
3893 while (par && (par->layout == layout)
3894 && (par->depth == depth)) {
3895 par->pextra_type = PEXTRA_NONE;
3896 par->pextra_width.clear();
3897 par->pextra_widthp.clear();
3898 par = par->NextAfterFootnote();
3899 if (par && (par->depth > depth))
3900 par->UnsetPExtraType();
3901 while (par && ((par->depth > depth) || par->IsDummy()))
3902 par = par->NextAfterFootnote();
3908 bool LyXParagraph::IsHfill(size_type pos) const
3910 return IsHfillChar(GetChar(pos));
3914 bool LyXParagraph::IsInset(size_type pos) const
3916 return IsInsetChar(GetChar(pos));
3920 bool LyXParagraph::IsFloat(size_type pos) const
3922 return IsFloatChar(GetChar(pos));
3926 bool LyXParagraph::IsNewline(size_type pos) const
3930 tmp = IsNewlineChar(GetChar(pos));
3935 bool LyXParagraph::IsSeparator(size_type pos) const
3937 return IsSeparatorChar(GetChar(pos));
3941 bool LyXParagraph::IsLineSeparator(size_type pos) const
3943 return IsLineSeparatorChar(GetChar(pos));
3947 bool LyXParagraph::IsKomma(size_type pos) const
3949 return IsKommaChar(GetChar(pos));
3953 /// Used by the spellchecker
3954 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
3956 unsigned char c = GetChar(pos);
3957 if (IsLetterChar(c))
3959 // '\0' is not a letter, allthough every string contains "" (below)
3962 // We want to pass the ' and escape chars to ispell
3963 string extra = lyxrc->isp_esc_chars + '\'';
3967 return contains(extra, ch);
3971 bool LyXParagraph::IsWord(size_type pos ) const
3973 return IsWordChar(GetChar(pos)) ;
3977 LyXDirection LyXParagraph::getParDirection() const
3979 if (!lyxrc->rtl_support || table)
3980 return LYX_DIR_LEFT_TO_RIGHT;
3983 return (getFont(0).direction() == LyXFont::RTL_DIR)
3984 ? LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
3986 return current_view->buffer()->params.getDocumentDirection();
3991 LyXParagraph::getLetterDirection(LyXParagraph::size_type pos) const
3993 if (!lyxrc->rtl_support)
3994 return LYX_DIR_LEFT_TO_RIGHT;
3996 LyXDirection direction = getFont(pos).getFontDirection();
3997 if (IsLineSeparator(pos) && 0 < pos && pos < Last() - 1
3998 && !IsLineSeparator(pos + 1)
3999 && !(table && IsNewline(pos + 1))
4000 && (getFont(pos - 1).getFontDirection() != direction
4001 || getFont(pos + 1).getFontDirection() != direction))
4002 return getParDirection();