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"
19 #include "bufferparams.h"
22 #include "BufferView.h"
24 #include "ParameterStruct.h"
27 #include "paragraph_funcs.h"
30 #include "insets/insetbibitem.h"
31 #include "insets/insetoptarg.h"
32 #include "insets/insetenv.h"
34 #include "support/filetools.h"
35 #include "support/lstrings.h"
36 #include "support/lyxmanip.h"
37 #include "support/FileInfo.h"
38 #include "support/LAssert.h"
39 #include "support/textutils.h"
50 using std::lower_bound;
51 using std::upper_bound;
56 // this is a minibuffer
61 LyXFont minibuffer_font;
62 Inset * minibuffer_inset;
67 extern BufferView * current_view;
70 Paragraph::Paragraph()
71 : pimpl_(new Paragraph::Pimpl(this))
84 // This constructor inserts the new paragraph in a list.
85 // It is placed after par.
86 Paragraph::Paragraph(Paragraph * par)
87 : pimpl_(new Paragraph::Pimpl(this))
92 // double linked list begin
95 next_->previous_ = this;
97 previous_->next_ = this;
105 Paragraph::Paragraph(Paragraph const & lp, bool same_ids)
106 : pimpl_(new Paragraph::Pimpl(*lp.pimpl_, this, same_ids))
114 // this is because of the dummy layout of the paragraphs that
116 layout_ = lp.layout();
118 // copy everything behind the break-position to the new paragraph
119 insetlist = lp.insetlist;
120 InsetList::iterator it = insetlist.begin();
121 InsetList::iterator end = insetlist.end();
122 for (; it != end; ++it) {
123 it.setInset(it.getInset()->clone(*current_view->buffer(),
125 // tell the new inset who is the boss now
126 it.getInset()->parOwner(this);
131 // the destructor removes the new paragraph from the list
132 Paragraph::~Paragraph()
136 previous_->next_ = next_;
138 next_->previous_ = previous_;
143 //lyxerr << "Paragraph::paragraph_id = "
144 // << Paragraph::paragraph_id << endl;
148 void Paragraph::write(Buffer const * buf, ostream & os,
149 BufferParams const & bparams,
150 depth_type & dth) const
152 // The beginning or end of a deeper (i.e. nested) area?
153 if (dth != params().depth()) {
154 if (params().depth() > dth) {
155 while (params().depth() > dth) {
156 os << "\n\\begin_deeper ";
160 while (params().depth() < dth) {
161 os << "\n\\end_deeper ";
167 // First write the layout
168 os << "\n\\layout " << layout()->name() << '\n';
172 LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
174 Change running_change = Change(Change::UNCHANGED);
175 lyx::time_type const curtime(lyx::current_time());
178 for (pos_type i = 0; i < size(); ++i) {
184 Change change = pimpl_->lookupChangeFull(i);
185 Changes::lyxMarkChange(os, column, curtime, running_change, change);
186 running_change = change;
188 // Write font changes
189 LyXFont font2 = getFontSettings(bparams, i);
190 if (font2 != font1) {
191 font2.lyxWriteChanges(font1, os);
196 value_type const c = getChar(i);
200 Inset const * inset = getInset(i);
202 if (inset->directWrite()) {
203 // international char, let it write
204 // code directly so it's shorter in
206 inset->write(buf, os);
208 os << "\n\\begin_inset ";
209 inset->write(buf, os);
210 os << "\n\\end_inset \n\n";
216 os << "\n\\backslash \n";
220 if (i + 1 < size() && getChar(i + 1) == ' ') {
227 if ((column > 70 && c == ' ')
232 // this check is to amend a bug. LyX sometimes
233 // inserts '\0' this could cause problems.
237 lyxerr << "ERROR (Paragraph::writeFile):"
238 " NULL char in structure." << endl;
244 // to make reading work properly
246 running_change = pimpl_->lookupChange(0);
247 Changes::lyxMarkChange(os, column, curtime,
248 Change(Change::UNCHANGED), running_change);
250 Changes::lyxMarkChange(os, column, curtime,
251 running_change, Change(Change::UNCHANGED));
255 void Paragraph::validate(LaTeXFeatures & features) const
257 pimpl_->validate(features, *layout());
261 // First few functions needed for cut and paste and paragraph breaking.
262 void Paragraph::copyIntoMinibuffer(Buffer const & buffer, pos_type pos) const
264 BufferParams bparams = buffer.params;
266 minibuffer_char = getChar(pos);
267 minibuffer_font = getFontSettings(bparams, pos);
268 minibuffer_inset = 0;
269 if (minibuffer_char == Paragraph::META_INSET) {
271 minibuffer_inset = getInset(pos)->clone(buffer);
273 minibuffer_inset = 0;
274 minibuffer_char = ' ';
275 // This reflects what GetInset() does (ARRae)
281 void Paragraph::cutIntoMinibuffer(BufferParams const & bparams, pos_type pos)
283 minibuffer_char = getChar(pos);
284 minibuffer_font = getFontSettings(bparams, pos);
285 minibuffer_inset = 0;
286 if (minibuffer_char == Paragraph::META_INSET) {
288 // the inset is not in a paragraph anymore
289 minibuffer_inset = insetlist.release(pos);
290 minibuffer_inset->parOwner(0);
292 minibuffer_inset = 0;
293 minibuffer_char = ' ';
294 // This reflects what GetInset() does (ARRae)
299 // Erase(pos); now the caller is responsible for that.
303 bool Paragraph::insertFromMinibuffer(pos_type pos)
305 if (minibuffer_char == Paragraph::META_INSET) {
306 if (!insetAllowed(minibuffer_inset->lyxCode())) {
309 insertInset(pos, minibuffer_inset, minibuffer_font);
311 LyXFont f = minibuffer_font;
312 if (!checkInsertChar(f)) {
315 insertChar(pos, minibuffer_char, f);
323 void Paragraph::eraseIntern(lyx::pos_type pos)
325 pimpl_->eraseIntern(pos);
329 bool Paragraph::erase(pos_type pos)
331 return pimpl_->erase(pos);
335 int Paragraph::erase(pos_type start, pos_type end)
337 return pimpl_->erase(start, end);
341 bool Paragraph::checkInsertChar(LyXFont & font)
343 if (pimpl_->inset_owner)
344 return pimpl_->inset_owner->checkInsertChar(font);
349 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c)
351 LyXFont const f(LyXFont::ALL_INHERIT);
352 insertChar(pos, c, f);
356 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
357 LyXFont const & font, Change change)
359 pimpl_->insertChar(pos, c, font, change);
363 void Paragraph::insertInset(pos_type pos, Inset * inset)
365 LyXFont const f(LyXFont::ALL_INHERIT);
366 insertInset(pos, inset, f);
370 void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font, Change change)
372 pimpl_->insertInset(pos, inset, font, change);
376 bool Paragraph::insetAllowed(Inset::Code code)
378 //lyxerr << "Paragraph::InsertInsetAllowed" << endl;
379 if (pimpl_->inset_owner)
380 return pimpl_->inset_owner->insetAllowed(code);
385 Inset * Paragraph::getInset(pos_type pos)
387 lyx::Assert(pos < size());
388 return insetlist.get(pos);
392 Inset const * Paragraph::getInset(pos_type pos) const
394 lyx::Assert(pos < size());
395 return insetlist.get(pos);
399 // Gets uninstantiated font setting at position.
400 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
403 lyx::Assert(pos <= size());
405 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
406 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
407 for (; cit != end; ++cit) {
408 if (cit->pos() >= pos)
414 retfont = cit->font();
415 else if (pos == size() && !empty())
416 retfont = getFontSettings(bparams, pos - 1);
418 retfont = LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
424 // Gets uninstantiated font setting at position 0
425 LyXFont const Paragraph::getFirstFontSettings() const
427 if (!empty() && !pimpl_->fontlist.empty())
428 return pimpl_->fontlist[0].font();
430 return LyXFont(LyXFont::ALL_INHERIT);
434 // Gets the fully instantiated font at a given position in a paragraph
435 // This is basically the same function as LyXText::GetFont() in text2.C.
436 // The difference is that this one is used for generating the LaTeX file,
437 // and thus cosmetic "improvements" are disallowed: This has to deliver
438 // the true picture of the buffer. (Asger)
439 LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
440 LyXFont const & outerfont) const
442 lyx::Assert(pos >= 0);
444 LyXLayout_ptr const & lout = layout();
446 pos_type const body_pos = beginningOfBody();
450 layoutfont = lout->labelfont;
452 layoutfont = lout->font;
454 LyXFont tmpfont = getFontSettings(bparams, pos);
455 tmpfont.realize(layoutfont);
456 tmpfont.realize(outerfont);
458 return realizeFont(tmpfont, bparams);
462 LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
463 LyXFont const & outerfont) const
465 LyXLayout_ptr const & lout = layout();
467 LyXFont tmpfont = lout->labelfont;
468 tmpfont.setLanguage(getParLanguage(bparams));
469 tmpfont.realize(outerfont);
471 return realizeFont(tmpfont, bparams);
475 LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
476 LyXFont const & outerfont) const
478 LyXLayout_ptr const & lout = layout();
480 LyXFont tmpfont = lout->font;
481 tmpfont.setLanguage(getParLanguage(bparams));
482 tmpfont.realize(outerfont);
484 return realizeFont(tmpfont, bparams);
488 /// Returns the height of the highest font in range
490 Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
491 LyXFont::FONT_SIZE const def_size) const
493 if (pimpl_->fontlist.empty())
496 Pimpl::FontList::const_iterator end_it = pimpl_->fontlist.begin();
497 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
498 for (; end_it != end; ++end_it) {
499 if (end_it->pos() >= endpos)
506 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
507 for (; cit != end; ++cit) {
508 if (cit->pos() >= startpos)
512 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
513 for (; cit != end_it; ++cit) {
514 LyXFont::FONT_SIZE size = cit->font().size();
515 if (size == LyXFont::INHERIT_SIZE)
517 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
524 Paragraph::value_type
525 Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
527 value_type c = getChar(pos);
528 if (!lyxrc.rtl_support)
558 if (uc != c && getFontSettings(bparams, pos).isRightToLeft())
565 void Paragraph::setFont(pos_type pos, LyXFont const & font)
567 lyx::Assert(pos <= size());
569 // First, reduce font against layout/label font
570 // Update: The SetCharFont() routine in text2.C already
571 // reduces font, so we don't need to do that here. (Asger)
572 // No need to simplify this because it will disappear
573 // in a new kernel. (Asger)
574 // Next search font table
576 Pimpl::FontList::iterator beg = pimpl_->fontlist.begin();
577 Pimpl::FontList::iterator it = beg;
578 Pimpl::FontList::iterator endit = pimpl_->fontlist.end();
579 for (; it != endit; ++it) {
580 if (it->pos() >= pos)
583 unsigned int i = std::distance(beg, it);
584 bool notfound = (it == endit);
586 if (!notfound && pimpl_->fontlist[i].font() == font)
589 bool begin = pos == 0 || notfound ||
590 (i > 0 && pimpl_->fontlist[i - 1].pos() == pos - 1);
591 // Is position pos is a beginning of a font block?
592 bool end = !notfound && pimpl_->fontlist[i].pos() == pos;
593 // Is position pos is the end of a font block?
594 if (begin && end) { // A single char block
595 if (i + 1 < pimpl_->fontlist.size() &&
596 pimpl_->fontlist[i + 1].font() == font) {
597 // Merge the singleton block with the next block
598 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
599 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
600 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i - 1);
601 } else if (i > 0 && pimpl_->fontlist[i - 1].font() == font) {
602 // Merge the singleton block with the previous block
603 pimpl_->fontlist[i - 1].pos(pos);
604 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
606 pimpl_->fontlist[i].font(font);
608 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
609 pimpl_->fontlist[i - 1].pos(pos);
611 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
612 Pimpl::FontTable(pos, font));
614 pimpl_->fontlist[i].pos(pos - 1);
615 if (!(i + 1 < pimpl_->fontlist.size() &&
616 pimpl_->fontlist[i + 1].font() == font))
617 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
618 Pimpl::FontTable(pos, font));
619 } else { // The general case. The block is splitted into 3 blocks
620 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
621 Pimpl::FontTable(pos - 1, pimpl_->fontlist[i].font()));
622 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
623 Pimpl::FontTable(pos, font));
629 void Paragraph::next(Paragraph * p)
635 // This function is able to hide closed footnotes.
636 Paragraph * Paragraph::next()
642 Paragraph const * Paragraph::next() const
648 void Paragraph::previous(Paragraph * p)
654 // This function is able to hide closed footnotes.
655 Paragraph * Paragraph::previous()
661 // This function is able to hide closed footnotes.
662 Paragraph const * Paragraph::previous() const
669 void Paragraph::makeSameLayout(Paragraph const & par)
671 layout(par.layout());
673 params() = par.params();
677 int Paragraph::stripLeadingSpaces()
679 if (layout()->free_spacing || isFreeSpacing())
683 while (!empty() && (isNewline(0) || isLineSeparator(0))) {
684 pimpl_->eraseIntern(0);
692 bool Paragraph::hasSameLayout(Paragraph const & par) const
695 par.layout() == layout() &&
696 params().sameLayout(par.params());
700 Paragraph::depth_type Paragraph::getDepth() const
702 return params().depth();
706 Paragraph::depth_type Paragraph::getMaxDepthAfter() const
708 if (layout()->isEnvironment())
709 return params().depth() + 1;
711 return params().depth();
715 char Paragraph::getAlign() const
717 return params().align();
721 string const & Paragraph::getLabelstring() const
723 return params().labelString();
727 // the next two functions are for the manual labels
728 string const Paragraph::getLabelWidthString() const
730 if (!params().labelWidthString().empty())
731 return params().labelWidthString();
733 return _("Senseless with this layout!");
737 void Paragraph::setLabelWidthString(string const & s)
739 params().labelWidthString(s);
743 void Paragraph::applyLayout(LyXLayout_ptr const & new_layout)
746 params().labelWidthString(string());
747 params().align(LYX_ALIGN_LAYOUT);
748 params().spaceTop(VSpace(VSpace::NONE));
749 params().spaceBottom(VSpace(VSpace::NONE));
750 params().spacing(Spacing(Spacing::Default));
754 int Paragraph::beginningOfBody() const
756 if (layout()->labeltype != LABEL_MANUAL)
759 // Unroll the first two cycles of the loop
760 // and remember the previous character to
761 // remove unnecessary GetChar() calls
763 if (i < size() && !isNewline(i)) {
765 char previous_char = 0;
768 previous_char = getChar(i);
771 while (i < size() && previous_char != ' ') {
777 previous_char = temp;
787 // returns -1 if inset not found
788 int Paragraph::getPositionOfInset(Inset const * inset) const
791 InsetList::iterator it = insetlist.begin();
792 InsetList::iterator end = insetlist.end();
793 for (; it != end; ++it)
794 if (it.getInset() == inset)
800 InsetBibitem * Paragraph::bibitem()
802 InsetList::iterator it = insetlist.begin();
803 if (it != insetlist.end() && it.getInset()->lyxCode() == Inset::BIBTEX_CODE)
804 return static_cast<InsetBibitem *>(it.getInset());
810 // This could go to ParagraphParameters if we want to
811 int Paragraph::startTeXParParams(BufferParams const & bparams,
812 ostream & os, bool moving_arg) const
816 if (params().noindent()) {
821 switch (params().align()) {
823 case LYX_ALIGN_BLOCK:
824 case LYX_ALIGN_LAYOUT:
825 case LYX_ALIGN_SPECIAL:
828 case LYX_ALIGN_RIGHT:
829 case LYX_ALIGN_CENTER:
837 switch (params().align()) {
839 case LYX_ALIGN_BLOCK:
840 case LYX_ALIGN_LAYOUT:
841 case LYX_ALIGN_SPECIAL:
844 if (getParLanguage(bparams)->babel() != "hebrew") {
845 os << "\\begin{flushleft}";
848 os << "\\begin{flushright}";
852 case LYX_ALIGN_RIGHT:
853 if (getParLanguage(bparams)->babel() != "hebrew") {
854 os << "\\begin{flushright}";
857 os << "\\begin{flushleft}";
861 case LYX_ALIGN_CENTER:
862 os << "\\begin{center}";
871 // This could go to ParagraphParameters if we want to
872 int Paragraph::endTeXParParams(BufferParams const & bparams,
873 ostream & os, bool moving_arg) const
877 switch (params().align()) {
879 case LYX_ALIGN_BLOCK:
880 case LYX_ALIGN_LAYOUT:
881 case LYX_ALIGN_SPECIAL:
884 case LYX_ALIGN_RIGHT:
885 case LYX_ALIGN_CENTER:
893 switch (params().align()) {
895 case LYX_ALIGN_BLOCK:
896 case LYX_ALIGN_LAYOUT:
897 case LYX_ALIGN_SPECIAL:
900 if (getParLanguage(bparams)->babel() != "hebrew") {
901 os << "\\end{flushleft}";
904 os << "\\end{flushright}";
908 case LYX_ALIGN_RIGHT:
909 if (getParLanguage(bparams)->babel() != "hebrew") {
910 os << "\\end{flushright}";
913 os << "\\end{flushleft}";
917 case LYX_ALIGN_CENTER:
918 os << "\\end{center}";
926 // This one spits out the text of the paragraph
927 bool Paragraph::simpleTeXOnePar(Buffer const * buf,
928 BufferParams const & bparams,
929 LyXFont const & outerfont,
930 ostream & os, TexRow & texrow,
933 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
935 bool return_value = false;
939 // well we have to check if we are in an inset with unlimited
940 // lenght (all in one row) if that is true then we don't allow
941 // any special options in the paragraph and also we don't allow
942 // any environment other then "Standard" to be valid!
944 (inInset() && inInset()->forceDefaultParagraphs(inInset()));
947 style = bparams.getLyXTextClass().defaultLayout();
954 // Maybe we have to create a optional argument.
957 // FIXME: can we actually skip this check and just call
958 // beginningOfBody() ??
959 if (style->labeltype != LABEL_MANUAL) {
962 body_pos = beginningOfBody();
965 unsigned int column = 0;
970 basefont = getLabelFont(bparams, outerfont);
972 basefont = getLayoutFont(bparams, outerfont);
975 moving_arg |= style->needprotect;
977 // Which font is currently active?
978 LyXFont running_font(basefont);
979 // Do we have an open font change?
980 bool open_font = false;
982 Change::Type running_change = Change::UNCHANGED;
984 texrow.start(id(), 0);
986 // if the paragraph is empty, the loop will not be entered at all
988 if (style->isCommand()) {
993 column += startTeXParParams(bparams, os, moving_arg);
997 for (pos_type i = 0; i < size(); ++i) {
999 // First char in paragraph or after label?
1000 if (i == body_pos) {
1003 column += running_font.latexWriteEndChanges(os, basefont, basefont);
1006 basefont = getLayoutFont(bparams, outerfont);
1007 running_font = basefont;
1011 if (style->isCommand()) {
1017 column += startTeXParParams(bparams, os,
1021 value_type c = getChar(i);
1023 // Fully instantiated font
1024 LyXFont font = getFont(bparams, i, outerfont);
1026 LyXFont const last_font = running_font;
1028 // Spaces at end of font change are simulated to be
1029 // outside font change, i.e. we write "\textXX{text} "
1030 // rather than "\textXX{text }". (Asger)
1031 if (open_font && c == ' ' && i <= size() - 2) {
1032 LyXFont const & next_font = getFont(bparams, i + 1, outerfont);
1033 if (next_font != running_font
1034 && next_font != font) {
1039 // We end font definition before blanks
1041 (font != running_font ||
1042 font.language() != running_font.language()))
1044 column += running_font.latexWriteEndChanges(os,
1046 (i == body_pos-1) ? basefont : font);
1047 running_font = basefont;
1051 // Blanks are printed before start of fontswitch
1053 // Do not print the separation of the optional argument
1054 if (i != body_pos - 1) {
1055 pimpl_->simpleTeXBlanks(os, texrow, i,
1056 column, font, *style);
1060 // Do we need to change font?
1061 if ((font != running_font ||
1062 font.language() != running_font.language()) &&
1065 column += font.latexWriteStartChanges(os, basefont,
1067 running_font = font;
1071 Change::Type change = pimpl_->lookupChange(i);
1073 column += Changes::latexMarkChange(os, running_change, change);
1074 running_change = change;
1076 pimpl_->simpleTeXSpecialChars(buf, bparams,
1077 os, texrow, moving_arg,
1079 basefont, outerfont, open_font,
1081 *style, i, column, c);
1084 column += Changes::latexMarkChange(os,
1085 running_change, Change::UNCHANGED);
1087 // If we have an open font definition, we have to close it
1089 #ifdef FIXED_LANGUAGE_END_DETECTION
1092 .latexWriteEndChanges(os, basefont,
1093 next_->getFont(bparams,
1096 running_font.latexWriteEndChanges(os, basefont,
1100 #ifdef WITH_WARNINGS
1101 //#warning For now we ALWAYS have to close the foreign font settings if they are
1102 //#warning there as we start another \selectlanguage with the next paragraph if
1103 //#warning we are in need of this. This should be fixed sometime (Jug)
1105 running_font.latexWriteEndChanges(os, basefont, basefont);
1109 // Needed if there is an optional argument but no contents.
1110 if (body_pos > 0 && body_pos == size()) {
1112 return_value = false;
1116 column += endTeXParParams(bparams, os, moving_arg);
1119 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
1120 return return_value;
1126 bool Paragraph::isHfill(pos_type pos) const
1128 return IsInsetChar(getChar(pos))
1129 && getInset(pos)->lyxCode() == Inset::HFILL_CODE;
1133 bool Paragraph::isInset(pos_type pos) const
1135 return IsInsetChar(getChar(pos));
1139 bool Paragraph::isNewline(pos_type pos) const
1141 return IsInsetChar(getChar(pos))
1142 && getInset(pos)->lyxCode() == Inset::NEWLINE_CODE;
1146 bool Paragraph::isSeparator(pos_type pos) const
1148 return IsSeparatorChar(getChar(pos));
1152 bool Paragraph::isLineSeparator(pos_type pos) const
1154 value_type const c = getChar(pos);
1155 return IsLineSeparatorChar(c)
1156 || (IsInsetChar(c) && getInset(pos) &&
1157 getInset(pos)->isLineSeparator());
1161 bool Paragraph::isKomma(pos_type pos) const
1163 return IsKommaChar(getChar(pos));
1167 /// Used by the spellchecker
1168 bool Paragraph::isLetter(pos_type pos) const
1170 value_type const c = getChar(pos);
1171 if (IsLetterChar(c))
1174 return getInset(pos)->isLetter();
1175 // We want to pass the ' and escape chars to ispell
1176 string const extra = lyxrc.isp_esc_chars + '\'';
1177 return contains(extra, c);
1181 bool Paragraph::isWord(pos_type pos) const
1183 return IsWordChar(getChar(pos)) ;
1188 Paragraph::getParLanguage(BufferParams const & bparams) const
1191 return getFirstFontSettings().language();
1192 #warning FIXME we should check the prev par as well (Lgb)
1194 } else if (previous_) {
1195 return previous_->getParLanguage(bparams);
1198 return bparams.language;
1202 bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
1204 return lyxrc.rtl_support
1205 && getParLanguage(bparams)->RightToLeft()
1206 && !(inInset() && inInset()->owner() &&
1207 inInset()->owner()->lyxCode() == Inset::ERT_CODE);
1211 void Paragraph::changeLanguage(BufferParams const & bparams,
1212 Language const * from, Language const * to)
1214 for (pos_type i = 0; i < size(); ++i) {
1215 LyXFont font = getFontSettings(bparams, i);
1216 if (font.language() == from) {
1217 font.setLanguage(to);
1224 bool Paragraph::isMultiLingual(BufferParams const & bparams)
1226 Language const * doc_language = bparams.language;
1227 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
1228 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
1230 for (; cit != end; ++cit)
1231 if (cit->font().language() != ignore_language &&
1232 cit->font().language() != latex_language &&
1233 cit->font().language() != doc_language)
1239 // Convert the paragraph to a string.
1240 // Used for building the table of contents
1241 string const Paragraph::asString(Buffer const * buffer, bool label) const
1244 if (label && !params().labelString().empty())
1245 s += params().labelString() + ' ';
1247 for (pos_type i = 0; i < size(); ++i) {
1248 value_type c = getChar(i);
1251 else if (c == META_INSET &&
1252 getInset(i)->lyxCode() == Inset::MATH_CODE) {
1254 getInset(i)->ascii(buffer, ost);
1255 s += subst(STRCONV(ost.str()),'\n',' ');
1263 string const Paragraph::asString(Buffer const * buffer,
1264 pos_type beg, pos_type end, bool label) const
1268 if (beg == 0 && label && !params().labelString().empty())
1269 os << params().labelString() << ' ';
1271 for (pos_type i = beg; i < end; ++i) {
1272 value_type const c = getUChar(buffer->params, i);
1275 else if (c == META_INSET)
1276 getInset(i)->ascii(buffer, os);
1279 return STRCONV(os.str());
1283 void Paragraph::setInsetOwner(Inset * i)
1285 pimpl_->inset_owner = i;
1286 InsetList::iterator it = insetlist.begin();
1287 InsetList::iterator end = insetlist.end();
1288 for (; it != end; ++it)
1290 it.getInset()->setOwner(i);
1294 void Paragraph::deleteInsetsLyXText(BufferView * bv)
1297 insetlist.deleteInsetsLyXText(bv);
1301 void Paragraph::resizeInsetsLyXText(BufferView * bv)
1304 insetlist.resizeInsetsLyXText(bv);
1308 void Paragraph::setContentsFromPar(Paragraph const & par)
1310 pimpl_->setContentsFromPar(par);
1314 void Paragraph::trackChanges(Change::Type type)
1316 pimpl_->trackChanges(type);
1320 void Paragraph::untrackChanges()
1322 pimpl_->untrackChanges();
1326 void Paragraph::cleanChanges()
1328 pimpl_->cleanChanges();
1332 Change::Type Paragraph::lookupChange(lyx::pos_type pos) const
1334 lyx::Assert(!size() || pos < size());
1335 return pimpl_->lookupChange(pos);
1339 Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const
1341 lyx::Assert(!size() || pos < size());
1342 return pimpl_->lookupChangeFull(pos);
1346 bool Paragraph::isChanged(pos_type start, pos_type end) const
1348 return pimpl_->isChanged(start, end);
1352 bool Paragraph::isChangeEdited(pos_type start, pos_type end) const
1354 return pimpl_->isChangeEdited(start, end);
1358 void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
1360 pimpl_->setChange(pos, type);
1365 void Paragraph::markErased()
1367 pimpl_->markErased();
1371 void Paragraph::acceptChange(pos_type start, pos_type end)
1373 return pimpl_->acceptChange(start, end);
1377 void Paragraph::rejectChange(pos_type start, pos_type end)
1379 return pimpl_->rejectChange(start, end);
1383 lyx::pos_type Paragraph::size() const
1385 return pimpl_->size();
1389 bool Paragraph::empty() const
1391 return pimpl_->empty();
1395 Paragraph::value_type Paragraph::getChar(pos_type pos) const
1397 return pimpl_->getChar(pos);
1401 int Paragraph::id() const
1407 LyXLayout_ptr const & Paragraph::layout() const
1409 Inset * inset = inInset();
1410 if (inset && inset->lyxCode() == Inset::ENVIRONMENT_CODE)
1411 return static_cast<InsetEnvironment*>(inset)->layout();
1416 void Paragraph::layout(LyXLayout_ptr const & new_layout)
1418 layout_ = new_layout;
1422 Inset * Paragraph::inInset() const
1424 return pimpl_->inset_owner;
1428 void Paragraph::clearContents()
1433 void Paragraph::setChar(pos_type pos, value_type c)
1435 pimpl_->setChar(pos, c);
1439 ParagraphParameters & Paragraph::params()
1441 return pimpl_->params;
1445 ParagraphParameters const & Paragraph::params() const
1447 return pimpl_->params;
1451 bool Paragraph::isFreeSpacing() const
1453 // for now we just need this, later should we need this in some
1454 // other way we can always add a function to Inset::() too.
1455 if (pimpl_->inset_owner && pimpl_->inset_owner->owner())
1456 return (pimpl_->inset_owner->owner()->lyxCode() == Inset::ERT_CODE);