1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2001 The LyX Team.
9 * ====================================================== */
13 #include "paragraph.h"
14 #include "paragraph_pimpl.h"
17 #include "bufferparams.h"
18 #include "BufferView.h"
24 #include "latexrunparams.h"
27 #include "paragraph_funcs.h"
28 #include "ParameterStruct.h"
33 #include "insets/insetbibitem.h"
34 #include "insets/insetoptarg.h"
35 #include "insets/insetenv.h"
37 #include "support/filetools.h"
38 #include "support/lstrings.h"
39 #include "support/lyxmanip.h"
40 #include "support/FileInfo.h"
41 #include "support/LAssert.h"
42 #include "support/textutils.h"
53 using std::lower_bound;
54 using std::upper_bound;
59 // this is a minibuffer
64 LyXFont minibuffer_font;
65 Inset * minibuffer_inset;
70 Paragraph::Paragraph()
71 : pimpl_(new Paragraph::Pimpl(this))
83 Paragraph::Paragraph(Paragraph const & lp)
84 : pimpl_(new Paragraph::Pimpl(*lp.pimpl_, this))
92 // this is because of the dummy layout of the paragraphs that
94 layout_ = lp.layout();
97 // copy everything behind the break-position to the new paragraph
98 insetlist = lp.insetlist;
99 InsetList::iterator it = insetlist.begin();
100 InsetList::iterator end = insetlist.end();
101 for (; it != end; ++it) {
102 it.setInset(it.getInset()->clone(**buffer_));
103 // tell the new inset who is the boss now
104 it.getInset()->parOwner(this);
109 // the destructor removes the new paragraph from the list
110 Paragraph::~Paragraph()
114 //lyxerr << "Paragraph::paragraph_id = "
115 // << Paragraph::paragraph_id << endl;
119 void Paragraph::write(Buffer const * buf, ostream & os,
120 BufferParams const & bparams,
121 depth_type & dth) const
123 // The beginning or end of a deeper (i.e. nested) area?
124 if (dth != params().depth()) {
125 if (params().depth() > dth) {
126 while (params().depth() > dth) {
127 os << "\n\\begin_deeper ";
131 while (params().depth() < dth) {
132 os << "\n\\end_deeper ";
138 // First write the layout
139 os << "\n\\layout " << layout()->name() << '\n';
143 LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
145 Change running_change = Change(Change::UNCHANGED);
146 lyx::time_type const curtime(lyx::current_time());
149 for (pos_type i = 0; i < size(); ++i) {
155 Change change = pimpl_->lookupChangeFull(i);
156 Changes::lyxMarkChange(os, column, curtime, running_change, change);
157 running_change = change;
159 // Write font changes
160 LyXFont font2 = getFontSettings(bparams, i);
161 if (font2 != font1) {
162 font2.lyxWriteChanges(font1, os);
167 value_type const c = getChar(i);
171 Inset const * inset = getInset(i);
173 if (inset->directWrite()) {
174 // international char, let it write
175 // code directly so it's shorter in
177 inset->write(buf, os);
179 os << "\n\\begin_inset ";
180 inset->write(buf, os);
181 os << "\n\\end_inset \n\n";
187 os << "\n\\backslash \n";
191 if (i + 1 < size() && getChar(i + 1) == ' ') {
198 if ((column > 70 && c == ' ')
203 // this check is to amend a bug. LyX sometimes
204 // inserts '\0' this could cause problems.
208 lyxerr << "ERROR (Paragraph::writeFile):"
209 " NULL char in structure." << endl;
215 // to make reading work properly
217 running_change = pimpl_->lookupChange(0);
218 Changes::lyxMarkChange(os, column, curtime,
219 Change(Change::UNCHANGED), running_change);
221 Changes::lyxMarkChange(os, column, curtime,
222 running_change, Change(Change::UNCHANGED));
226 void Paragraph::validate(LaTeXFeatures & features) const
228 pimpl_->validate(features, *layout());
232 // First few functions needed for cut and paste and paragraph breaking.
233 void Paragraph::copyIntoMinibuffer(Buffer const & buffer, pos_type pos) const
235 BufferParams bparams = buffer.params;
237 minibuffer_char = getChar(pos);
238 minibuffer_font = getFontSettings(bparams, pos);
239 minibuffer_inset = 0;
240 if (minibuffer_char == Paragraph::META_INSET) {
242 minibuffer_inset = getInset(pos)->clone(buffer);
244 minibuffer_inset = 0;
245 minibuffer_char = ' ';
246 // This reflects what GetInset() does (ARRae)
252 void Paragraph::cutIntoMinibuffer(BufferParams const & bparams, pos_type pos)
254 minibuffer_char = getChar(pos);
255 minibuffer_font = getFontSettings(bparams, pos);
256 minibuffer_inset = 0;
257 if (minibuffer_char == Paragraph::META_INSET) {
259 // the inset is not in a paragraph anymore
260 minibuffer_inset = insetlist.release(pos);
261 minibuffer_inset->parOwner(0);
263 minibuffer_inset = 0;
264 minibuffer_char = ' ';
265 // This reflects what GetInset() does (ARRae)
270 // Erase(pos); now the caller is responsible for that.
274 bool Paragraph::insertFromMinibuffer(pos_type pos)
276 if (minibuffer_char == Paragraph::META_INSET) {
277 if (!insetAllowed(minibuffer_inset->lyxCode())) {
280 insertInset(pos, minibuffer_inset, minibuffer_font);
282 LyXFont f = minibuffer_font;
283 if (!checkInsertChar(f)) {
286 insertChar(pos, minibuffer_char, f);
294 void Paragraph::eraseIntern(lyx::pos_type pos)
296 pimpl_->eraseIntern(pos);
300 bool Paragraph::erase(pos_type pos)
302 return pimpl_->erase(pos);
306 int Paragraph::erase(pos_type start, pos_type end)
308 return pimpl_->erase(start, end);
312 bool Paragraph::checkInsertChar(LyXFont & font)
314 if (pimpl_->inset_owner)
315 return pimpl_->inset_owner->checkInsertChar(font);
320 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c)
322 LyXFont const f(LyXFont::ALL_INHERIT);
323 insertChar(pos, c, f);
327 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
328 LyXFont const & font, Change change)
330 pimpl_->insertChar(pos, c, font, change);
334 void Paragraph::insertInset(pos_type pos, Inset * inset)
336 LyXFont const f(LyXFont::ALL_INHERIT);
337 insertInset(pos, inset, f);
341 void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font, Change change)
343 pimpl_->insertInset(pos, inset, font, change);
347 bool Paragraph::insetAllowed(Inset::Code code)
349 //lyxerr << "Paragraph::InsertInsetAllowed" << endl;
350 if (pimpl_->inset_owner)
351 return pimpl_->inset_owner->insetAllowed(code);
356 Inset * Paragraph::getInset(pos_type pos)
358 lyx::Assert(pos < size());
359 return insetlist.get(pos);
363 Inset const * Paragraph::getInset(pos_type pos) const
365 lyx::Assert(pos < size());
366 return insetlist.get(pos);
370 // Gets uninstantiated font setting at position.
371 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
374 lyx::Assert(pos <= size());
376 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
377 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
378 for (; cit != end; ++cit) {
379 if (cit->pos() >= pos)
385 retfont = cit->font();
386 else if (pos == size() && !empty())
387 retfont = getFontSettings(bparams, pos - 1);
389 retfont = LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
395 // Gets uninstantiated font setting at position 0
396 LyXFont const Paragraph::getFirstFontSettings() const
398 if (!empty() && !pimpl_->fontlist.empty())
399 return pimpl_->fontlist[0].font();
401 return LyXFont(LyXFont::ALL_INHERIT);
405 // Gets the fully instantiated font at a given position in a paragraph
406 // This is basically the same function as LyXText::GetFont() in text2.C.
407 // The difference is that this one is used for generating the LaTeX file,
408 // and thus cosmetic "improvements" are disallowed: This has to deliver
409 // the true picture of the buffer. (Asger)
410 LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
411 LyXFont const & outerfont) const
413 lyx::Assert(pos >= 0);
415 LyXLayout_ptr const & lout = layout();
417 pos_type const body_pos = beginningOfBody();
421 layoutfont = lout->labelfont;
423 layoutfont = lout->font;
425 LyXFont tmpfont = getFontSettings(bparams, pos);
426 tmpfont.realize(layoutfont);
427 tmpfont.realize(outerfont);
429 return realizeFont(tmpfont, bparams);
433 LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
434 LyXFont const & outerfont) const
436 LyXLayout_ptr const & lout = layout();
438 LyXFont tmpfont = lout->labelfont;
439 tmpfont.setLanguage(getParLanguage(bparams));
440 tmpfont.realize(outerfont);
442 return realizeFont(tmpfont, bparams);
446 LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
447 LyXFont const & outerfont) const
449 LyXLayout_ptr const & lout = layout();
451 LyXFont tmpfont = lout->font;
452 tmpfont.setLanguage(getParLanguage(bparams));
453 tmpfont.realize(outerfont);
455 return realizeFont(tmpfont, bparams);
459 /// Returns the height of the highest font in range
461 Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
462 LyXFont::FONT_SIZE const def_size) const
464 if (pimpl_->fontlist.empty())
467 Pimpl::FontList::const_iterator end_it = pimpl_->fontlist.begin();
468 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
469 for (; end_it != end; ++end_it) {
470 if (end_it->pos() >= endpos)
477 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
478 for (; cit != end; ++cit) {
479 if (cit->pos() >= startpos)
483 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
484 for (; cit != end_it; ++cit) {
485 LyXFont::FONT_SIZE size = cit->font().size();
486 if (size == LyXFont::INHERIT_SIZE)
488 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
495 Paragraph::value_type
496 Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
498 value_type c = getChar(pos);
499 if (!lyxrc.rtl_support)
529 if (uc != c && getFontSettings(bparams, pos).isRightToLeft())
536 void Paragraph::setFont(pos_type pos, LyXFont const & font)
538 lyx::Assert(pos <= size());
540 // First, reduce font against layout/label font
541 // Update: The SetCharFont() routine in text2.C already
542 // reduces font, so we don't need to do that here. (Asger)
543 // No need to simplify this because it will disappear
544 // in a new kernel. (Asger)
545 // Next search font table
547 Pimpl::FontList::iterator beg = pimpl_->fontlist.begin();
548 Pimpl::FontList::iterator it = beg;
549 Pimpl::FontList::iterator endit = pimpl_->fontlist.end();
550 for (; it != endit; ++it) {
551 if (it->pos() >= pos)
554 unsigned int i = std::distance(beg, it);
555 bool notfound = (it == endit);
557 if (!notfound && pimpl_->fontlist[i].font() == font)
560 bool begin = pos == 0 || notfound ||
561 (i > 0 && pimpl_->fontlist[i - 1].pos() == pos - 1);
562 // Is position pos is a beginning of a font block?
563 bool end = !notfound && pimpl_->fontlist[i].pos() == pos;
564 // Is position pos is the end of a font block?
565 if (begin && end) { // A single char block
566 if (i + 1 < pimpl_->fontlist.size() &&
567 pimpl_->fontlist[i + 1].font() == font) {
568 // Merge the singleton block with the next block
569 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
570 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
571 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i - 1);
572 } else if (i > 0 && pimpl_->fontlist[i - 1].font() == font) {
573 // Merge the singleton block with the previous block
574 pimpl_->fontlist[i - 1].pos(pos);
575 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
577 pimpl_->fontlist[i].font(font);
579 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
580 pimpl_->fontlist[i - 1].pos(pos);
582 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
583 Pimpl::FontTable(pos, font));
585 pimpl_->fontlist[i].pos(pos - 1);
586 if (!(i + 1 < pimpl_->fontlist.size() &&
587 pimpl_->fontlist[i + 1].font() == font))
588 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
589 Pimpl::FontTable(pos, font));
590 } else { // The general case. The block is splitted into 3 blocks
591 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
592 Pimpl::FontTable(pos - 1, pimpl_->fontlist[i].font()));
593 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
594 Pimpl::FontTable(pos, font));
599 void Paragraph::makeSameLayout(Paragraph const & par)
601 layout(par.layout());
603 params() = par.params();
607 int Paragraph::stripLeadingSpaces()
609 if (layout()->free_spacing || isFreeSpacing())
613 while (!empty() && (isNewline(0) || isLineSeparator(0))) {
614 pimpl_->eraseIntern(0);
622 bool Paragraph::hasSameLayout(Paragraph const & par) const
625 par.layout() == layout() &&
626 params().sameLayout(par.params());
630 Paragraph::depth_type Paragraph::getDepth() const
632 return params().depth();
636 Paragraph::depth_type Paragraph::getMaxDepthAfter() const
638 if (layout()->isEnvironment())
639 return params().depth() + 1;
641 return params().depth();
645 char Paragraph::getAlign() const
647 return params().align();
651 string const & Paragraph::getLabelstring() const
653 return params().labelString();
657 // the next two functions are for the manual labels
658 string const Paragraph::getLabelWidthString() const
660 if (!params().labelWidthString().empty())
661 return params().labelWidthString();
663 return _("Senseless with this layout!");
667 void Paragraph::setLabelWidthString(string const & s)
669 params().labelWidthString(s);
673 void Paragraph::applyLayout(LyXLayout_ptr const & new_layout)
676 params().labelWidthString(string());
677 params().align(LYX_ALIGN_LAYOUT);
678 params().spaceTop(VSpace(VSpace::NONE));
679 params().spaceBottom(VSpace(VSpace::NONE));
680 params().spacing(Spacing(Spacing::Default));
684 int Paragraph::beginningOfBody() const
686 if (layout()->labeltype != LABEL_MANUAL)
689 // Unroll the first two cycles of the loop
690 // and remember the previous character to
691 // remove unnecessary GetChar() calls
693 if (i < size() && !isNewline(i)) {
695 char previous_char = 0;
698 previous_char = getChar(i);
701 while (i < size() && previous_char != ' ') {
707 previous_char = temp;
717 // returns -1 if inset not found
718 int Paragraph::getPositionOfInset(Inset const * inset) const
721 InsetList::iterator it = insetlist.begin();
722 InsetList::iterator end = insetlist.end();
723 for (; it != end; ++it)
724 if (it.getInset() == inset)
730 InsetBibitem * Paragraph::bibitem()
732 InsetList::iterator it = insetlist.begin();
733 if (it != insetlist.end() && it.getInset()->lyxCode() == Inset::BIBTEX_CODE)
734 return static_cast<InsetBibitem *>(it.getInset());
740 // This could go to ParagraphParameters if we want to
741 int Paragraph::startTeXParParams(BufferParams const & bparams,
742 ostream & os, bool moving_arg) const
746 if (params().noindent()) {
751 switch (params().align()) {
753 case LYX_ALIGN_BLOCK:
754 case LYX_ALIGN_LAYOUT:
755 case LYX_ALIGN_SPECIAL:
758 case LYX_ALIGN_RIGHT:
759 case LYX_ALIGN_CENTER:
767 switch (params().align()) {
769 case LYX_ALIGN_BLOCK:
770 case LYX_ALIGN_LAYOUT:
771 case LYX_ALIGN_SPECIAL:
774 if (getParLanguage(bparams)->babel() != "hebrew") {
775 os << "\\begin{flushleft}";
778 os << "\\begin{flushright}";
782 case LYX_ALIGN_RIGHT:
783 if (getParLanguage(bparams)->babel() != "hebrew") {
784 os << "\\begin{flushright}";
787 os << "\\begin{flushleft}";
791 case LYX_ALIGN_CENTER:
792 os << "\\begin{center}";
801 // This could go to ParagraphParameters if we want to
802 int Paragraph::endTeXParParams(BufferParams const & bparams,
803 ostream & os, bool moving_arg) const
807 switch (params().align()) {
809 case LYX_ALIGN_BLOCK:
810 case LYX_ALIGN_LAYOUT:
811 case LYX_ALIGN_SPECIAL:
814 case LYX_ALIGN_RIGHT:
815 case LYX_ALIGN_CENTER:
823 switch (params().align()) {
825 case LYX_ALIGN_BLOCK:
826 case LYX_ALIGN_LAYOUT:
827 case LYX_ALIGN_SPECIAL:
830 if (getParLanguage(bparams)->babel() != "hebrew") {
831 os << "\\end{flushleft}";
834 os << "\\end{flushright}";
838 case LYX_ALIGN_RIGHT:
839 if (getParLanguage(bparams)->babel() != "hebrew") {
840 os << "\\end{flushright}";
843 os << "\\end{flushleft}";
847 case LYX_ALIGN_CENTER:
848 os << "\\end{center}";
856 // This one spits out the text of the paragraph
857 bool Paragraph::simpleTeXOnePar(Buffer const * buf,
858 BufferParams const & bparams,
859 LyXFont const & outerfont,
860 ostream & os, TexRow & texrow,
861 LatexRunParams const & runparams)
863 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
865 bool return_value = false;
869 // well we have to check if we are in an inset with unlimited
870 // lenght (all in one row) if that is true then we don't allow
871 // any special options in the paragraph and also we don't allow
872 // any environment other then "Standard" to be valid!
874 (inInset() && inInset()->forceDefaultParagraphs(inInset()));
877 style = bparams.getLyXTextClass().defaultLayout();
884 // Maybe we have to create a optional argument.
887 // FIXME: can we actually skip this check and just call
888 // beginningOfBody() ??
889 if (style->labeltype != LABEL_MANUAL) {
892 body_pos = beginningOfBody();
895 unsigned int column = 0;
900 basefont = getLabelFont(bparams, outerfont);
902 basefont = getLayoutFont(bparams, outerfont);
905 bool moving_arg = runparams.moving_arg;
906 moving_arg |= style->needprotect;
908 // Which font is currently active?
909 LyXFont running_font(basefont);
910 // Do we have an open font change?
911 bool open_font = false;
913 Change::Type running_change = Change::UNCHANGED;
915 texrow.start(id(), 0);
917 // if the paragraph is empty, the loop will not be entered at all
919 if (style->isCommand()) {
924 column += startTeXParParams(bparams, os, moving_arg);
928 for (pos_type i = 0; i < size(); ++i) {
930 // First char in paragraph or after label?
934 column += running_font.latexWriteEndChanges(os, basefont, basefont);
937 basefont = getLayoutFont(bparams, outerfont);
938 running_font = basefont;
942 if (style->isCommand()) {
948 column += startTeXParParams(bparams, os,
952 value_type c = getChar(i);
954 // Fully instantiated font
955 LyXFont font = getFont(bparams, i, outerfont);
957 LyXFont const last_font = running_font;
959 // Spaces at end of font change are simulated to be
960 // outside font change, i.e. we write "\textXX{text} "
961 // rather than "\textXX{text }". (Asger)
962 if (open_font && c == ' ' && i <= size() - 2) {
963 LyXFont const & next_font = getFont(bparams, i + 1, outerfont);
964 if (next_font != running_font
965 && next_font != font) {
970 // We end font definition before blanks
972 (font != running_font ||
973 font.language() != running_font.language()))
975 column += running_font.latexWriteEndChanges(os,
977 (i == body_pos-1) ? basefont : font);
978 running_font = basefont;
982 // Blanks are printed before start of fontswitch
984 // Do not print the separation of the optional argument
985 if (i != body_pos - 1) {
986 pimpl_->simpleTeXBlanks(os, texrow, i,
987 column, font, *style);
991 // Do we need to change font?
992 if ((font != running_font ||
993 font.language() != running_font.language()) &&
996 column += font.latexWriteStartChanges(os, basefont,
1002 Change::Type change = pimpl_->lookupChange(i);
1004 column += Changes::latexMarkChange(os, running_change, change);
1005 running_change = change;
1007 LatexRunParams rp = runparams;
1008 rp.moving_arg = moving_arg;
1009 rp.free_spacing = style->free_spacing;
1010 pimpl_->simpleTeXSpecialChars(buf, bparams,
1011 os, texrow, runparams,
1013 basefont, outerfont, open_font,
1015 *style, i, column, c);
1018 column += Changes::latexMarkChange(os,
1019 running_change, Change::UNCHANGED);
1021 // If we have an open font definition, we have to close it
1023 #ifdef FIXED_LANGUAGE_END_DETECTION
1026 .latexWriteEndChanges(os, basefont,
1027 next_->getFont(bparams,
1030 running_font.latexWriteEndChanges(os, basefont,
1034 #ifdef WITH_WARNINGS
1035 //#warning For now we ALWAYS have to close the foreign font settings if they are
1036 //#warning there as we start another \selectlanguage with the next paragraph if
1037 //#warning we are in need of this. This should be fixed sometime (Jug)
1039 running_font.latexWriteEndChanges(os, basefont, basefont);
1043 // Needed if there is an optional argument but no contents.
1044 if (body_pos > 0 && body_pos == size()) {
1046 return_value = false;
1050 column += endTeXParParams(bparams, os, moving_arg);
1053 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
1054 return return_value;
1060 bool Paragraph::isHfill(pos_type pos) const
1062 return IsInsetChar(getChar(pos))
1063 && getInset(pos)->lyxCode() == Inset::HFILL_CODE;
1067 bool Paragraph::isInset(pos_type pos) const
1069 return IsInsetChar(getChar(pos));
1073 bool Paragraph::isNewline(pos_type pos) const
1075 return IsInsetChar(getChar(pos))
1076 && getInset(pos)->lyxCode() == Inset::NEWLINE_CODE;
1080 bool Paragraph::isSeparator(pos_type pos) const
1082 return IsSeparatorChar(getChar(pos));
1086 bool Paragraph::isLineSeparator(pos_type pos) const
1088 value_type const c = getChar(pos);
1089 return IsLineSeparatorChar(c)
1090 || (IsInsetChar(c) && getInset(pos) &&
1091 getInset(pos)->isLineSeparator());
1095 bool Paragraph::isKomma(pos_type pos) const
1097 return IsKommaChar(getChar(pos));
1101 /// Used by the spellchecker
1102 bool Paragraph::isLetter(pos_type pos) const
1104 value_type const c = getChar(pos);
1105 if (IsLetterChar(c))
1108 return getInset(pos)->isLetter();
1109 // We want to pass the ' and escape chars to ispell
1110 string const extra = lyxrc.isp_esc_chars + '\'';
1111 return contains(extra, c);
1115 bool Paragraph::isWord(pos_type pos) const
1117 return IsWordChar(getChar(pos)) ;
1122 Paragraph::getParLanguage(BufferParams const & bparams) const
1125 return getFirstFontSettings().language();
1126 #warning FIXME we should check the prev par as well (Lgb)
1128 } else if (previous_) {
1129 return previous_->getParLanguage(bparams);
1132 return bparams.language;
1136 bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
1138 return lyxrc.rtl_support
1139 && getParLanguage(bparams)->RightToLeft()
1140 && !(inInset() && inInset()->owner() &&
1141 inInset()->owner()->lyxCode() == Inset::ERT_CODE);
1145 void Paragraph::changeLanguage(BufferParams const & bparams,
1146 Language const * from, Language const * to)
1148 for (pos_type i = 0; i < size(); ++i) {
1149 LyXFont font = getFontSettings(bparams, i);
1150 if (font.language() == from) {
1151 font.setLanguage(to);
1158 bool Paragraph::isMultiLingual(BufferParams const & bparams)
1160 Language const * doc_language = bparams.language;
1161 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
1162 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
1164 for (; cit != end; ++cit)
1165 if (cit->font().language() != ignore_language &&
1166 cit->font().language() != latex_language &&
1167 cit->font().language() != doc_language)
1173 // Convert the paragraph to a string.
1174 // Used for building the table of contents
1175 string const Paragraph::asString(Buffer const * buffer, bool label) const
1178 if (label && !params().labelString().empty())
1179 s += params().labelString() + ' ';
1181 for (pos_type i = 0; i < size(); ++i) {
1182 value_type c = getChar(i);
1185 else if (c == META_INSET &&
1186 getInset(i)->lyxCode() == Inset::MATH_CODE) {
1188 getInset(i)->ascii(buffer, ost);
1189 s += subst(STRCONV(ost.str()),'\n',' ');
1197 string const Paragraph::asString(Buffer const * buffer,
1198 pos_type beg, pos_type end, bool label) const
1202 if (beg == 0 && label && !params().labelString().empty())
1203 os << params().labelString() << ' ';
1205 for (pos_type i = beg; i < end; ++i) {
1206 value_type const c = getUChar(buffer->params, i);
1209 else if (c == META_INSET)
1210 getInset(i)->ascii(buffer, os);
1213 return STRCONV(os.str());
1217 void Paragraph::setInsetOwner(Inset * i)
1219 pimpl_->inset_owner = i;
1220 InsetList::iterator it = insetlist.begin();
1221 InsetList::iterator end = insetlist.end();
1222 for (; it != end; ++it)
1224 it.getInset()->setOwner(i);
1228 void Paragraph::deleteInsetsLyXText(BufferView * bv)
1231 insetlist.deleteInsetsLyXText(bv);
1235 void Paragraph::resizeInsetsLyXText(BufferView * bv)
1238 insetlist.resizeInsetsLyXText(bv);
1242 void Paragraph::setContentsFromPar(Paragraph const & par)
1244 pimpl_->setContentsFromPar(par);
1248 void Paragraph::trackChanges(Change::Type type)
1250 pimpl_->trackChanges(type);
1254 void Paragraph::untrackChanges()
1256 pimpl_->untrackChanges();
1260 void Paragraph::cleanChanges()
1262 pimpl_->cleanChanges();
1266 Change::Type Paragraph::lookupChange(lyx::pos_type pos) const
1268 lyx::Assert(!size() || pos < size());
1269 return pimpl_->lookupChange(pos);
1273 Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const
1275 lyx::Assert(!size() || pos < size());
1276 return pimpl_->lookupChangeFull(pos);
1280 bool Paragraph::isChanged(pos_type start, pos_type end) const
1282 return pimpl_->isChanged(start, end);
1286 bool Paragraph::isChangeEdited(pos_type start, pos_type end) const
1288 return pimpl_->isChangeEdited(start, end);
1292 void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
1294 pimpl_->setChange(pos, type);
1299 void Paragraph::markErased()
1301 pimpl_->markErased();
1305 void Paragraph::acceptChange(pos_type start, pos_type end)
1307 return pimpl_->acceptChange(start, end);
1311 void Paragraph::rejectChange(pos_type start, pos_type end)
1313 return pimpl_->rejectChange(start, end);
1317 lyx::pos_type Paragraph::size() const
1319 return pimpl_->size();
1323 bool Paragraph::empty() const
1325 return pimpl_->empty();
1329 Paragraph::value_type Paragraph::getChar(pos_type pos) const
1331 return pimpl_->getChar(pos);
1335 int Paragraph::id() const
1341 void Paragraph::id(int i)
1347 LyXLayout_ptr const & Paragraph::layout() const
1349 Inset * inset = inInset();
1350 if (inset && inset->lyxCode() == Inset::ENVIRONMENT_CODE)
1351 return static_cast<InsetEnvironment*>(inset)->layout();
1356 void Paragraph::layout(LyXLayout_ptr const & new_layout)
1358 layout_ = new_layout;
1362 Inset * Paragraph::inInset() const
1364 return pimpl_->inset_owner;
1368 void Paragraph::clearContents()
1373 void Paragraph::setChar(pos_type pos, value_type c)
1375 pimpl_->setChar(pos, c);
1379 ParagraphParameters & Paragraph::params()
1381 return pimpl_->params;
1385 ParagraphParameters const & Paragraph::params() const
1387 return pimpl_->params;
1391 bool Paragraph::isFreeSpacing() const
1393 // for now we just need this, later should we need this in some
1394 // other way we can always add a function to Inset::() too.
1395 if (pimpl_->inset_owner && pimpl_->inset_owner->owner())
1396 return (pimpl_->inset_owner->owner()->lyxCode() == Inset::ERT_CODE);
1401 bool operator==(Paragraph const & lhs, Paragraph const & rhs)
1403 #warning FIXME this implementatoin must be completely wrong...
1404 return &lhs == &rhs;