]> git.lyx.org Git - lyx.git/blobdiff - src/paragraph.C
Continue to improve GtkLengthEntry
[lyx.git] / src / paragraph.C
index 7073f641ed2e325df6eb3506b262217732b733e6..227568b43f2067155a02c48d60358c590768753c 100644 (file)
@@ -27,6 +27,7 @@
 #include "debug.h"
 #include "gettext.h"
 #include "language.h"
+#include "LaTeXFeatures.h"
 #include "lyxfont.h"
 #include "lyxrc.h"
 #include "lyxrow.h"
 
 #include "support/lstrings.h"
 #include "support/textutils.h"
-#include "support/tostr.h"
+#include "support/convert.h"
 
 #include <boost/tuple/tuple.hpp>
 #include <boost/bind.hpp>
 
+#include <algorithm>
 #include <list>
 #include <stack>
 #include <sstream>
 
 using lyx::pos_type;
 
-using lyx::support::contains;
 using lyx::support::subst;
 
 using std::distance;
@@ -70,10 +71,8 @@ ParagraphList::ParagraphList()
 
 
 Paragraph::Paragraph()
-       : y(0), height(0), begin_of_body_(0),
-         pimpl_(new Paragraph::Pimpl(this))
+       : begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
 {
-       //lyxerr << "sizeof Paragraph::Pimpl: " << sizeof(Paragraph::Pimpl) << endl;
        itemdepth = 0;
        params().clear();
 }
@@ -81,8 +80,9 @@ Paragraph::Paragraph()
 
 Paragraph::Paragraph(Paragraph const & par)
        :       itemdepth(par.itemdepth), insetlist(par.insetlist),
-               rows(par.rows), y(par.y), height(par.height),
-               width(par.width), layout_(par.layout_),
+               dim_(par.dim_),
+               rows_(par.rows_), rowSignature_(par.rowSignature_), 
+               layout_(par.layout_),
                text_(par.text_), begin_of_body_(par.begin_of_body_),
          pimpl_(new Paragraph::Pimpl(*par.pimpl_, this))
 {
@@ -106,10 +106,9 @@ Paragraph & Paragraph::operator=(Paragraph const & par)
                for (; it != end; ++it)
                        it->inset = it->inset->clone().release();
 
-               rows = par.rows;
-               y = par.y;
-               height = par.height;
-               width = par.width;
+               rows_ = par.rows_;
+               dim_ = par.dim_;
+               rowSignature_ = par.rowSignature_;
                layout_ = par.layout();
                text_ = par.text_;
                begin_of_body_ = par.begin_of_body_;
@@ -138,12 +137,12 @@ void Paragraph::write(Buffer const & buf, ostream & os,
        if (dth != params().depth()) {
                if (params().depth() > dth) {
                        while (params().depth() > dth) {
-                               os << "\n\\begin_deeper ";
+                               os << "\n\\begin_deeper";
                                ++dth;
                        }
                } else {
                        while (params().depth() < dth) {
-                               os << "\n\\end_deeper ";
+                               os << "\n\\end_deeper";
                                --dth;
                        }
                }
@@ -161,10 +160,6 @@ void Paragraph::write(Buffer const & buf, ostream & os,
 
        int column = 0;
        for (pos_type i = 0; i < size(); ++i) {
-               if (!i) {
-                       os << '\n';
-                       column = 0;
-               }
 
                Change change = pimpl_->lookupChangeFull(i);
                Changes::lyxMarkChange(os, column, curtime, running_change, change);
@@ -190,15 +185,17 @@ void Paragraph::write(Buffer const & buf, ostream & os,
                                        // the file
                                        inset->write(buf, os);
                                } else {
-                                       os << "\n\\begin_inset ";
+                                       if (i)
+                                               os << '\n';
+                                       os << "\\begin_inset ";
                                        inset->write(buf, os);
-                                       os << "\n\\end_inset \n\n";
+                                       os << "\n\\end_inset\n\n";
                                        column = 0;
                                }
                }
                break;
                case '\\':
-                       os << "\n\\backslash \n";
+                       os << "\n\\backslash\n";
                        column = 0;
                        break;
                case '.':
@@ -266,18 +263,11 @@ int Paragraph::erase(pos_type start, pos_type end)
 void Paragraph::insert(pos_type start, string const & str,
                       LyXFont const & font)
 {
-       int size = str.size();
-       for (int i = 0 ; i < size ; ++i)
+       for (size_t i = 0, n = str.size(); i != n ; ++i)
                insertChar(start + i, str[i], font);
 }
 
 
-bool Paragraph::checkInsertChar(LyXFont &)
-{
-       return true;
-}
-
-
 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
                           Change change)
 {
@@ -307,26 +297,12 @@ void Paragraph::insertInset(pos_type pos, InsetBase * inset,
 }
 
 
-bool Paragraph::insetAllowed(InsetOld_code code)
+bool Paragraph::insetAllowed(InsetBase_code code)
 {
        return !pimpl_->inset_owner || pimpl_->inset_owner->insetAllowed(code);
 }
 
 
-InsetBase * Paragraph::getInset(pos_type pos)
-{
-       BOOST_ASSERT(pos < size());
-       return insetlist.get(pos);
-}
-
-
-InsetBase const * Paragraph::getInset(pos_type pos) const
-{
-       BOOST_ASSERT(pos < size());
-       return insetlist.get(pos);
-}
-
-
 // Gets uninstantiated font setting at position.
 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
                                         pos_type pos) const
@@ -352,20 +328,30 @@ LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
 }
 
 
-lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const
+FontSpan Paragraph::fontSpan(lyx::pos_type pos) const
 {
        BOOST_ASSERT(pos <= size());
+       lyx::pos_type start = 0;
 
        Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
        Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
-       for (; cit != end; ++cit)
-               if (cit->pos() >= pos)
-                       return cit->pos();
+       for (; cit != end; ++cit) {
+               if (cit->pos() >= pos) {
+                       if (pos >= beginOfBody())
+                               return FontSpan(std::max(start, beginOfBody()),
+                                               cit->pos());
+                       else
+                               return FontSpan(start, 
+                                               std::min(beginOfBody() - 1, 
+                                                        cit->pos()));
+               }
+               start = cit->pos() + 1;
+       }
 
        // This should not happen, but if so, we take no chances.
        //lyxerr << "Paragraph::getEndPosOfFontSpan: This should not happen!"
        //      << endl;
-       return pos;
+       return FontSpan(pos, pos);
 }
 
 
@@ -408,8 +394,8 @@ LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
 }
 
 
-LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
-                                     LyXFont const & outerfont) const
+LyXFont const Paragraph::getLabelFont
+       (BufferParams const & bparams, LyXFont const & outerfont) const
 {
        LyXFont tmpfont = layout()->labelfont;
        tmpfont.setLanguage(getParLanguage(bparams));
@@ -419,8 +405,8 @@ LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
 }
 
 
-LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
-                                      LyXFont const & outerfont) const
+LyXFont const Paragraph::getLayoutFont
+       (BufferParams const & bparams, LyXFont const & outerfont) const
 {
        LyXFont tmpfont = layout()->font;
        tmpfont.setLanguage(getParLanguage(bparams));
@@ -431,9 +417,8 @@ LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
 
 
 /// Returns the height of the highest font in range
-LyXFont_size
-Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
-                             LyXFont_size def_size) const
+LyXFont_size Paragraph::highestFontInRange
+       (pos_type startpos, pos_type endpos, LyXFont_size def_size) const
 {
        if (pimpl_->fontlist.empty())
                return def_size;
@@ -525,7 +510,7 @@ void Paragraph::setFont(pos_type pos, LyXFont const & font)
                if (it->pos() >= pos)
                        break;
        }
-       unsigned int i = distance(beg, it);
+       size_t const i = distance(beg, it);
        bool notfound = (it == endit);
 
        if (!notfound && pimpl_->fontlist[i].font() == font)
@@ -585,7 +570,9 @@ int Paragraph::stripLeadingSpaces()
 
        int i = 0;
        while (!empty() && (isNewline(0) || isLineSeparator(0))) {
-               pimpl_->eraseIntern(0);
+               // Set Change::Type to Change::INSERTED to quietly remove it
+               setChange(0, Change::INSERTED);
+               erase(0);
                ++i;
        }
 
@@ -709,7 +696,7 @@ InsetBibitem * Paragraph::bibitem() const
 {
        if (!insetlist.empty()) {
                InsetBase * inset = insetlist.begin()->inset;
-               if (inset->lyxCode() == InsetBase::BIBTEX_CODE)
+               if (inset->lyxCode() == InsetBase::BIBITEM_CODE)
                        return static_cast<InsetBibitem *>(inset);
        }
        return 0;
@@ -718,13 +705,7 @@ InsetBibitem * Paragraph::bibitem() const
 
 bool Paragraph::forceDefaultParagraphs() const
 {
-       return inInset() && inInset()->forceDefaultParagraphs(inInset());
-}
-
-
-bool Paragraph::autoBreakRows() const
-{
-       return inInset() && static_cast<InsetText *>(inInset())->getAutoBreakRows();
+       return inInset() && inInset()->forceDefaultParagraphs(0);
 }
 
 
@@ -915,20 +896,29 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
        LyXFont basefont;
 
+       LaTeXFeatures features(buf, bparams, runparams.nice);
+
+       // output change tracking marks only if desired,
+       // if dvipost is installed,
+       // and with dvi/ps (other formats don't work)
+       bool const output = bparams.output_changes
+               && runparams.flavor == OutputParams::LATEX
+               && features.isAvailable("dvipost");
+
        // Maybe we have to create a optional argument.
        pos_type body_pos = beginOfBody();
        unsigned int column = 0;
 
        if (body_pos > 0) {
-               os << '[';
-               ++column;
+               // the optional argument is kept in curly brackets in
+               // case it contains a ']'
+               os << "[{";
+               column += 2;
                basefont = getLabelFont(bparams, outerfont);
        } else {
                basefont = getLayoutFont(bparams, outerfont);
        }
 
-       bool const moving_arg = runparams.moving_arg | style->needprotect;
-
        // Which font is currently active?
        LyXFont running_font(basefont);
        // Do we have an open font change?
@@ -945,7 +935,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                        ++column;
                }
                if (!asdefault)
-                       column += startTeXParParams(bparams, os, moving_arg);
+                       column += startTeXParParams(bparams, os,
+                                                   runparams.moving_arg);
        }
 
        for (pos_type i = 0; i < size(); ++i) {
@@ -959,8 +950,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                                }
                                basefont = getLayoutFont(bparams, outerfont);
                                running_font = basefont;
-                               os << ']';
-                               ++column;
+                               os << "}] ";
+                               column +=3;
                        }
                        if (style->isCommand()) {
                                os << '{';
@@ -969,7 +960,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
                        if (!asdefault)
                                column += startTeXParParams(bparams, os,
-                                                           moving_arg);
+                                                           runparams.moving_arg);
                }
 
                value_type c = getChar(i);
@@ -1023,24 +1014,28 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
                Change::Type change = pimpl_->lookupChange(i);
 
-               column += Changes::latexMarkChange(os, running_change, change);
+               column += Changes::latexMarkChange(os, running_change,
+                       change, output);
                running_change = change;
 
-               OutputParams rp = runparams;
-               rp.moving_arg = moving_arg;
-               rp.free_spacing = style->free_spacing;
-               rp.lang = font.language()->babel();
-               rp.intitle = style->intitle;
-               pimpl_->simpleTeXSpecialChars(buf, bparams,
-                                             os, texrow, rp,
-                                             font, running_font,
-                                             basefont, outerfont, open_font,
-                                             running_change,
-                                             *style, i, column, c);
+               // do not output text which is marked deleted
+               // if change tracking output is not desired
+               if (output || running_change != Change::DELETED) {
+                       OutputParams rp = runparams;
+                       rp.free_spacing = style->free_spacing;
+                       rp.local_font = &font;
+                       rp.intitle = style->intitle;
+                       pimpl_->simpleTeXSpecialChars(buf, bparams,
+                                               os, texrow, rp,
+                                               font, running_font,
+                                               basefont, outerfont, open_font,
+                                               running_change,
+                                               *style, i, column, c);
+               }
        }
 
        column += Changes::latexMarkChange(os,
-                       running_change, Change::UNCHANGED);
+                       running_change, Change::UNCHANGED, output);
 
        // If we have an open font definition, we have to close it
        if (open_font) {
@@ -1066,12 +1061,12 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
        // Needed if there is an optional argument but no contents.
        if (body_pos > 0 && body_pos == size()) {
-               os << "]~";
+               os << "}]~";
                return_value = false;
        }
 
        if (!asdefault) {
-               column += endTeXParParams(bparams, os, moving_arg);
+               column += endTeXParParams(bparams, os, runparams.moving_arg);
        }
 
        lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
@@ -1277,7 +1272,7 @@ void Paragraph::simpleLinuxDocOnePar(Buffer const & buf,
                        os << '<' << tag_name(*j) << '>';
                }
 
-               char c = getChar(i);
+               value_type c = getChar(i);
 
 
                if (c == Paragraph::META_INSET) {
@@ -1329,14 +1324,39 @@ void Paragraph::simpleLinuxDocOnePar(Buffer const & buf,
 }
 
 
-string Paragraph::getDocbookId() const
+bool Paragraph::emptyTag() const
+{
+       for (pos_type i = 0; i < size(); ++i) {
+               if (isInset(i)) {
+                       InsetBase const * inset = getInset(i);
+                       InsetBase::Code lyx_code = inset->lyxCode();
+                       if (lyx_code != InsetBase::TOC_CODE &&
+                           lyx_code != InsetBase::INCLUDE_CODE &&
+                           lyx_code != InsetBase::GRAPHICS_CODE &&
+                           lyx_code != InsetBase::ERT_CODE &&
+                           lyx_code != InsetBase::FLOAT_CODE &&
+                           lyx_code != InsetBase::TABULAR_CODE) {
+                               return false;
+                       }
+               } else {
+                       value_type c = getChar(i);
+                       if (c != ' ' && c != '\t')
+                               return false;
+               }
+       }
+       return true;
+}
+
+
+string Paragraph::getID(Buffer const & buf, OutputParams const & runparams) const
 {
        for (pos_type i = 0; i < size(); ++i) {
                if (isInset(i)) {
                        InsetBase const * inset = getInset(i);
                        InsetBase::Code lyx_code = inset->lyxCode();
                        if (lyx_code == InsetBase::LABEL_CODE) {
-                               return static_cast<InsetCommand const *>(inset)->getContents();
+                               string const id = static_cast<InsetCommand const *>(inset)->getContents();
+                               return "id=\"" + sgml::cleanID(buf, runparams, id) + "\"";
                        }
                }
 
@@ -1345,155 +1365,107 @@ string Paragraph::getDocbookId() const
 }
 
 
+pos_type Paragraph::getFirstWord(Buffer const & buf, ostream & os, OutputParams const & runparams) const
+{
+       pos_type i;
+       for (i = 0; i < size(); ++i) {
+               if (isInset(i)) {
+                       InsetBase const * inset = getInset(i);
+                       inset->docbook(buf, os, runparams);
+               } else {
+                       value_type c = getChar(i);
+                       if (c == ' ')
+                               break;
+                       bool ws;
+                       string str;
+                       boost::tie(ws, str) = sgml::escapeChar(c);
+
+                       os << str;
+               }
+       }
+       return i;
+}
+
+
+bool Paragraph::onlyText(Buffer const & buf, LyXFont const & outerfont, pos_type initial) const
+{
+       LyXFont font_old;
+
+       for (pos_type i = initial; i < size(); ++i) {
+               LyXFont font = getFont(buf.params(), i, outerfont);
+               if (isInset(i))
+                       return false;
+               if (i != initial && font != font_old)
+                       return false;
+               font_old = font;
+       }
+
+       return true;
+}
+
+
 void Paragraph::simpleDocBookOnePar(Buffer const & buf,
                                    ostream & os,
-                                   LyXFont const & outerfont,
                                    OutputParams const & runparams,
-                                   lyx::depth_type depth) const
+                                   LyXFont const & outerfont,
+                                   pos_type initial) const
 {
        bool emph_flag = false;
 
        LyXLayout_ptr const & style = layout();
-       LyXLayout_ptr const & defaultstyle =
-               buf.params().getLyXTextClass().defaultLayout();
-
        LyXFont font_old =
                style->labeltype == LABEL_MANUAL ? style->labelfont : style->font;
 
-       int char_line_count = depth;
-       bool label_closed = true;
-       bool para_closed = true;
-
-       if (style->latextype == LATEX_ITEM_ENVIRONMENT) {
-               string ls = "";
-               Counters & counters = buf.params().getLyXTextClass().counters();
-               if (!style->free_spacing)
-                       os << string(depth,' ');
-               if (!style->labeltag().empty()) {
-                       os << "<" << style->labeltag() << ">\n";
-                       label_closed = false;
-               } else {
-                       if (!defaultstyle->latexparam().empty()) {
-                               counters.step("para");
-                               ls = tostr(counters.value("para"));
-                               ls = " id=\""
-                                       + subst(defaultstyle->latexparam(), "#", ls) + '"';
-                       }
-                       os << "<" << style->itemtag() << ">\n"
-                          << string(depth, ' ') << "<"
-                          << defaultstyle->latexname() << ls << ">\n";
-                       para_closed = false;
-               }
-       }
+       if (style->pass_thru && !onlyText(buf, outerfont, initial))
+               os << "]]>";
 
        // parsing main loop
-       for (pos_type i = 0; i < size(); ++i) {
+       for (pos_type i = initial; i < size(); ++i) {
                LyXFont font = getFont(buf.params(), i, outerfont);
 
                // handle <emphasis> tag
                if (font_old.emph() != font.emph()) {
                        if (font.emph() == LyXFont::ON) {
-                               if (style->latexparam() == "CDATA")
-                                       os << "]]>";
                                os << "<emphasis>";
-                               if (style->latexparam() == "CDATA")
-                                       os << "<![CDATA[";
                                emph_flag = true;
-                       } else if (i) {
-                               if (style->latexparam() == "CDATA")
-                                       os << "]]>";
+                       } else if (i != initial) {
                                os << "</emphasis>";
-                               if (style->latexparam() == "CDATA")
-                                       os << "<![CDATA[";
                                emph_flag = false;
                        }
                }
 
                if (isInset(i)) {
                        InsetBase const * inset = getInset(i);
-                       if (style->latexparam() == "CDATA")
-                               os << "]]>";
                        inset->docbook(buf, os, runparams);
-                       if (style->latexparam() == "CDATA")
-                               os << "<![CDATA[";
                } else {
-                       char c = getChar(i);
+                       value_type c = getChar(i);
                        bool ws;
                        string str;
                        boost::tie(ws, str) = sgml::escapeChar(c);
 
-                       if (style->pass_thru) {
+                       if (style->pass_thru)
                                os << c;
-                       } else if (isFreeSpacing() || c != ' ') {
-                                       os << str;
-                       } else if (!style->labeltag().empty() && !label_closed) {
-                               ++char_line_count;
-                               os << "\n</" << style->labeltag() << "><"
-                                  << style->itemtag() << "><"
-                                  << defaultstyle->latexname() << ">";
-                               label_closed = true;
-                               para_closed = false;
-                       } else {
-                               os << ' ';
-                       }
+                       else
+                               os << str;
                }
                font_old = font;
        }
 
        if (emph_flag) {
-               if (style->latexparam() == "CDATA")
-                       os << "]]>";
                os << "</emphasis>";
-               if (style->latexparam() == "CDATA")
-                       os << "<![CDATA[";
        }
 
-       // resets description flag correctly
-       if (!label_closed) {
-               // <term> not closed...
-               os << "</" << style->labeltag() << ">\n<"
-                  << style->itemtag() << "><"
-                  << defaultstyle->latexname() << ">&nbsp;";
-       }
-       if (!para_closed) {
-               os << "\n" << string(depth, ' ') << "</"
-                  << defaultstyle->latexname() << ">\n";
-       }
        if (style->free_spacing)
                os << '\n';
-}
-
-
-namespace {
-
-/// return true if the char is a meta-character for an inset
-inline
-bool IsInsetChar(char c)
-{
-       return (c == Paragraph::META_INSET);
-}
-
-} // namespace anon
-
-
-
-bool Paragraph::isHfill(pos_type pos) const
-{
-       return
-               isInset(pos) && getInset(pos)->lyxCode() == InsetBase::HFILL_CODE;
+       if (style->pass_thru && !onlyText(buf, outerfont, initial))
+               os << "<![CDATA[";
 }
 
 
 bool Paragraph::isNewline(pos_type pos) const
 {
-       return
-               isInset(pos) && getInset(pos)->lyxCode() == InsetBase::NEWLINE_CODE;
-}
-
-
-bool Paragraph::isSeparator(pos_type pos) const
-{
-       return IsSeparatorChar(getChar(pos));
+       return isInset(pos)
+               && getInset(pos)->lyxCode() == InsetBase::NEWLINE_CODE;
 }
 
 
@@ -1501,39 +1473,20 @@ bool Paragraph::isLineSeparator(pos_type pos) const
 {
        value_type const c = getChar(pos);
        return IsLineSeparatorChar(c)
-               || (IsInsetChar(c) && getInset(pos) &&
+               || (c == Paragraph::META_INSET && getInset(pos) &&
                getInset(pos)->isLineSeparator());
 }
 
 
-bool Paragraph::isKomma(pos_type pos) const
-{
-       return IsKommaChar(getChar(pos));
-}
-
-
 /// Used by the spellchecker
 bool Paragraph::isLetter(pos_type pos) const
 {
-       value_type const c = getChar(pos);
-       if (IsLetterChar(c))
-               return true;
        if (isInset(pos))
                return getInset(pos)->isLetter();
-       // We want to pass the ' and escape chars to ispell
-       string const extra = lyxrc.isp_esc_chars + '\'';
-       return contains(extra, c);
-}
-
-
-bool Paragraph::isWord(pos_type pos) const
-{
-       if (isInset(pos))
-               return getInset(pos)->isLetter();
-       value_type const c = getChar(pos);
-       return !(IsSeparatorChar(c)
-                 || IsKommaChar(c)
-                 || IsInsetChar(c));
+       else {
+               value_type const c = getChar(pos);
+               return IsLetterChar(c) || IsDigit(c);
+       }
 }
 
 
@@ -1647,14 +1600,14 @@ string const Paragraph::asString(Buffer const & buffer,
                if (IsPrintable(c))
                        os << c;
                else if (c == META_INSET)
-                       getInset(i)->plaintext(buffer, os, runparams);
+                       getInset(i)->textString(buffer, os, runparams);
        }
 
        return os.str();
 }
 
 
-void Paragraph::setInsetOwner(UpdatableInset * inset)
+void Paragraph::setInsetOwner(InsetBase * inset)
 {
        pimpl_->inset_owner = inset;
 }
@@ -1716,9 +1669,9 @@ void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
 }
 
 
-void Paragraph::markErased()
+void Paragraph::markErased(bool erased)
 {
-       pimpl_->markErased();
+       pimpl_->markErased(erased);
 }
 
 
@@ -1734,25 +1687,6 @@ void Paragraph::rejectChange(pos_type start, pos_type end)
 }
 
 
-Paragraph::value_type Paragraph::getChar(pos_type pos) const
-{
-       // This is in the critical path!
-       pos_type const siz = text_.size();
-
-       BOOST_ASSERT(0 <= pos);
-       BOOST_ASSERT(pos <= siz);
-
-       if (pos == siz) {
-               lyxerr << "getChar() on pos " << pos << " in par id "
-                      << id() << " of size " << siz
-                      << "  is a bit silly !" << endl;
-               BOOST_ASSERT(false);
-       }
-
-       return text_[pos];
-}
-
-
 int Paragraph::id() const
 {
        return pimpl_->id_;
@@ -1771,7 +1705,7 @@ void Paragraph::layout(LyXLayout_ptr const & new_layout)
 }
 
 
-UpdatableInset * Paragraph::inInset() const
+InsetBase * Paragraph::inInset() const
 {
        return pimpl_->inset_owner;
 }
@@ -1827,34 +1761,50 @@ bool Paragraph::allowEmpty() const
 }
 
 
-RowList::iterator Paragraph::getRow(pos_type pos)
+Row & Paragraph::getRow(pos_type pos, bool boundary)
 {
-       RowList::iterator rit = rows.end();
-       RowList::iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       // If boundary is set we should return the row on which
+       // the character before is inside.
+       if (pos > 0 && boundary)
+               --pos;
+
+       RowList::iterator rit = rows_.end();
+       RowList::iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
 
-       return rit;
+       return *rit;
 }
 
 
-RowList::const_iterator Paragraph::getRow(pos_type pos) const
+Row const & Paragraph::getRow(pos_type pos, bool boundary) const
 {
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       // If boundary is set we should return the row on which
+       // the character before is inside.
+       if (pos > 0 && boundary)
+               --pos;
+
+       RowList::const_iterator rit = rows_.end();
+       RowList::const_iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
 
-       return rit;
+       return *rit;
 }
 
 
-size_t Paragraph::row(pos_type pos) const
+size_t Paragraph::pos2row(pos_type pos) const
 {
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       RowList::const_iterator rit = rows_.end();
+       RowList::const_iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
@@ -1896,3 +1846,13 @@ unsigned char Paragraph::transformChar(unsigned char c, pos_type pos) const
                        return Encodings::TransformChar(c, Encodings::FORM_ISOLATED);
        }
 }
+
+
+void Paragraph::dump() const
+{
+       lyxerr << "Paragraph::dump: rows.size(): " << rows_.size() << endl;
+       for (size_t i = 0; i != rows_.size(); ++i) {
+               lyxerr << "  row " << i << ":   ";
+               rows_[i].dump();
+       }
+}