]> git.lyx.org Git - lyx.git/blobdiff - src/paragraph.C
* output_plaintext.C: cosmetics in comment: line length cannot be < 0
[lyx.git] / src / paragraph.C
index 88a4193cb7eae40c6d84e3f0ed303230363f8721..00dbb27ff906e99d36828bcd407957e6cda02cb0 100644 (file)
 #include "debug.h"
 #include "gettext.h"
 #include "language.h"
+#include "LaTeXFeatures.h"
 #include "lyxfont.h"
 #include "lyxrc.h"
 #include "lyxrow.h"
+#include "messages.h"
 #include "outputparams.h"
 #include "paragraph_funcs.h"
 #include "ParagraphList_fwd.h"
+
+#include "rowpainter.h"
+
 #include "sgml.h"
 #include "texrow.h"
 #include "vspace.h"
 
+#include "frontends/FontMetrics.h"
+
 #include "insets/insetbibitem.h"
 #include "insets/insetoptarg.h"
 
 #include "support/lstrings.h"
 #include "support/textutils.h"
-#include "support/tostr.h"
+#include "support/convert.h"
+#include "support/unicode.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;
 using std::endl;
 using std::list;
@@ -64,27 +67,25 @@ using std::string;
 using std::ostream;
 using std::ostringstream;
 
+namespace lyx {
 
-ParagraphList::ParagraphList()
-{}
-
+using support::contains;
+using support::rsplit;
+using support::subst;
 
 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();
 }
 
 
 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_),
-               text_(par.text_), begin_of_body_(par.begin_of_body_),
-         pimpl_(new Paragraph::Pimpl(*par.pimpl_, this))
+       : itemdepth(par.itemdepth), insetlist(par.insetlist),
+       layout_(par.layout_),
+       text_(par.text_), begin_of_body_(par.begin_of_body_),
+       pimpl_(new Paragraph::Pimpl(*par.pimpl_, this))
 {
        //lyxerr << "Paragraph::Paragraph(Paragraph const&)" << endl;
        InsetList::iterator it = insetlist.begin();
@@ -106,10 +107,6 @@ 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;
                layout_ = par.layout();
                text_ = par.text_;
                begin_of_body_ = par.begin_of_body_;
@@ -157,19 +154,17 @@ void Paragraph::write(Buffer const & buf, ostream & os,
        LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
 
        Change running_change = Change(Change::UNCHANGED);
-       lyx::time_type const curtime(lyx::current_time());
 
        int column = 0;
-       for (pos_type i = 0; i < size(); ++i) {
-               if (!i) {
-                       os << '\n';
-                       column = 0;
-               }
+       for (pos_type i = 0; i <= size(); ++i) {
 
-               Change change = pimpl_->lookupChangeFull(i);
-               Changes::lyxMarkChange(os, column, curtime, running_change, change);
+               Change change = pimpl_->lookupChange(i);
+               Changes::lyxMarkChange(os, column, running_change, change);
                running_change = change;
 
+               if (i == size())
+                       break;
+
                // Write font changes
                LyXFont font2 = getFontSettings(bparams, i);
                if (font2 != font1) {
@@ -190,7 +185,9 @@ 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";
                                        column = 0;
@@ -216,9 +213,11 @@ void Paragraph::write(Buffer const & buf, ostream & os,
                        }
                        // this check is to amend a bug. LyX sometimes
                        // inserts '\0' this could cause problems.
-                       if (c != '\0')
-                               os << c;
-                       else
+                       if (c != '\0') {
+                               std::vector<char> tmp = ucs4_to_utf8(c);
+                               tmp.push_back('\0');
+                               os << &tmp[0];
+                       } else
                                lyxerr << "ERROR (Paragraph::writeFile):"
                                        " NULL char in structure." << endl;
                        ++column;
@@ -226,15 +225,6 @@ void Paragraph::write(Buffer const & buf, ostream & os,
                }
        }
 
-       // to make reading work properly
-       if (!size()) {
-               running_change = pimpl_->lookupChange(0);
-               Changes::lyxMarkChange(os, column, curtime,
-                       Change(Change::UNCHANGED), running_change);
-       }
-       Changes::lyxMarkChange(os, column, curtime,
-               running_change, Change(Change::UNCHANGED));
-
        os << "\n\\end_layout\n";
 }
 
@@ -245,88 +235,72 @@ void Paragraph::validate(LaTeXFeatures & features) const
 }
 
 
-void Paragraph::eraseIntern(lyx::pos_type pos)
-{
-       pimpl_->eraseIntern(pos);
-}
-
-
-bool Paragraph::erase(pos_type pos)
+bool Paragraph::eraseChar(pos_type pos, bool trackChanges)
 {
-       return pimpl_->erase(pos);
+       return pimpl_->eraseChar(pos, trackChanges);
 }
 
 
-int Paragraph::erase(pos_type start, pos_type end)
+int Paragraph::eraseChars(pos_type start, pos_type end, bool trackChanges)
 {
-       return pimpl_->erase(start, end);
+       return pimpl_->eraseChars(start, end, trackChanges);
 }
 
 
-void Paragraph::insert(pos_type start, string const & str,
-                      LyXFont const & font)
+void Paragraph::insert(pos_type start, docstring const & str,
+                       LyXFont const & font, Change const & change)
 {
-       int size = str.size();
-       for (int i = 0 ; i < size ; ++i)
-               insertChar(start + i, str[i], font);
+       for (size_t i = 0, n = str.size(); i != n ; ++i)
+               insertChar(start + i, str[i], font, change);
 }
 
 
-bool Paragraph::checkInsertChar(LyXFont &)
+void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
+                           bool trackChanges)
 {
-       return true;
+       pimpl_->insertChar(pos, c, Change(trackChanges ?
+                          Change::INSERTED : Change::UNCHANGED));
 }
 
 
 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
-                          Change change)
+                           LyXFont const & font, bool trackChanges)
 {
-       pimpl_->insertChar(pos, c, change);
+       pimpl_->insertChar(pos, c, Change(trackChanges ?
+                          Change::INSERTED : Change::UNCHANGED));
+       setFont(pos, font);
 }
 
 
 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
-                          LyXFont const & font, Change change)
+                           LyXFont const & font, Change const & change)
 {
        pimpl_->insertChar(pos, c, change);
        setFont(pos, font);
 }
 
 
-void Paragraph::insertInset(pos_type pos, InsetBase * inset, Change change)
+void Paragraph::insertInset(pos_type pos, InsetBase * inset,
+                            Change const & change)
 {
        pimpl_->insertInset(pos, inset, change);
 }
 
 
 void Paragraph::insertInset(pos_type pos, InsetBase * inset,
-                           LyXFont const & font, Change change)
+                            LyXFont const & font, Change const & change)
 {
        pimpl_->insertInset(pos, inset, change);
        setFont(pos, font);
 }
 
 
-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,30 +326,40 @@ LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
 }
 
 
-lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const
+FontSpan Paragraph::fontSpan(pos_type pos) const
 {
        BOOST_ASSERT(pos <= size());
+       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);
 }
 
 
 // Gets uninstantiated font setting at position 0
-LyXFont const Paragraph::getFirstFontSettings() const
+LyXFont const Paragraph::getFirstFontSettings(BufferParams const & bparams) const
 {
        if (!empty() && !pimpl_->fontlist.empty())
                return pimpl_->fontlist[0].font();
 
-       return LyXFont(LyXFont::ALL_INHERIT);
+       return LyXFont(LyXFont::ALL_INHERIT, bparams.language);
 }
 
 
@@ -402,38 +386,37 @@ LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
        LyXFont font = getFontSettings(bparams, pos);
        font.realize(layoutfont);
        font.realize(outerfont);
-       font.realize(bparams.getLyXTextClass().defaultfont());
+       font.realize(bparams.getFont());
 
        return font;
 }
 
 
-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));
        tmpfont.realize(outerfont);
-       tmpfont.realize(bparams.getLyXTextClass().defaultfont());
+       tmpfont.realize(bparams.getFont());
        return tmpfont;
 }
 
 
-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));
        tmpfont.realize(outerfont);
-       tmpfont.realize(bparams.getLyXTextClass().defaultfont());
+       tmpfont.realize(bparams.getFont());
        return tmpfont;
 }
 
 
 /// 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 +508,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)
@@ -578,18 +561,22 @@ void Paragraph::makeSameLayout(Paragraph const & par)
 }
 
 
-int Paragraph::stripLeadingSpaces()
+int Paragraph::stripLeadingSpaces(bool trackChanges)
 {
        if (isFreeSpacing())
                return 0;
 
-       int i = 0;
-       while (!empty() && (isNewline(0) || isLineSeparator(0))) {
-               pimpl_->eraseIntern(0);
-               ++i;
+       int pos = 0;
+       int count = 0;
+
+       while (pos < size() && (isNewline(pos) || isLineSeparator(pos))) {
+               if (eraseChar(pos, trackChanges))
+                       ++count;
+               else
+                       ++pos;
        }
 
-       return i;
+       return count;
 }
 
 
@@ -599,13 +586,13 @@ bool Paragraph::hasSameLayout(Paragraph const & par) const
 }
 
 
-Paragraph::depth_type Paragraph::getDepth() const
+depth_type Paragraph::getDepth() const
 {
        return params().depth();
 }
 
 
-Paragraph::depth_type Paragraph::getMaxDepthAfter() const
+depth_type Paragraph::getMaxDepthAfter() const
 {
        if (layout()->isEnvironment())
                return params().depth() + 1;
@@ -616,18 +603,21 @@ Paragraph::depth_type Paragraph::getMaxDepthAfter() const
 
 char Paragraph::getAlign() const
 {
-       return params().align();
+       if (params().align() == LYX_ALIGN_LAYOUT)
+               return layout()->align;
+       else
+               return params().align();
 }
 
 
-string const & Paragraph::getLabelstring() const
+docstring const & Paragraph::getLabelstring() const
 {
        return params().labelString();
 }
 
 
 // the next two functions are for the manual labels
-string const Paragraph::getLabelWidthString() const
+docstring const Paragraph::getLabelWidthString() const
 {
        if (!params().labelWidthString().empty())
                return params().labelWidthString();
@@ -636,16 +626,59 @@ string const Paragraph::getLabelWidthString() const
 }
 
 
-void Paragraph::setLabelWidthString(string const & s)
+void Paragraph::setLabelWidthString(docstring const & s)
 {
        params().labelWidthString(s);
 }
 
 
+docstring const Paragraph::translateIfPossible(docstring const & s,
+               BufferParams const & bparams) const
+{
+       if (!support::isAscii(s) || s.empty()) {
+               // This must be a user defined layout. We cannot translate
+               // this, since gettext accepts only ascii keys.
+               return s;
+       }
+       // Probably standard layout, try to translate
+       Messages & m = getMessages(getParLanguage(bparams)->code());
+       return m.get(to_ascii(s));
+}
+
+
+docstring Paragraph::expandLabel(LyXLayout_ptr const & layout,
+               BufferParams const & bparams, bool process_appendix) const
+{
+       LyXTextClass const & tclass = bparams.getLyXTextClass();
+
+       docstring fmt;
+       if (process_appendix && params().appendix())
+               fmt = translateIfPossible(layout->labelstring_appendix(),
+                       bparams);
+       else
+               fmt = translateIfPossible(layout->labelstring(), bparams);
+
+       // handle 'inherited level parts' in 'fmt',
+       // i.e. the stuff between '@' in   '@Section@.\arabic{subsection}'
+       size_t const i = fmt.find('@', 0);
+       if (i != docstring::npos) {
+               size_t const j = fmt.find('@', i + 1);
+               if (j != docstring::npos) {
+                       docstring parent(fmt, i + 1, j - i - 1);
+                       // FIXME UNICODE
+                       docstring label = expandLabel(tclass[to_utf8(parent)], bparams);
+                       fmt = docstring(fmt, 0, i) + label + docstring(fmt, j + 1, docstring::npos);
+               }
+       }
+
+       return tclass.counters().counterLabel(fmt);
+}
+
+
 void Paragraph::applyLayout(LyXLayout_ptr const & new_layout)
 {
        layout(new_layout);
-       params().labelWidthString(string());
+       params().labelWidthString(docstring());
        params().align(LYX_ALIGN_LAYOUT);
        params().spacing(Spacing(Spacing::Default));
 }
@@ -671,8 +704,8 @@ void Paragraph::setBeginOfBody()
        pos_type end = size();
        if (i < end && !isNewline(i)) {
                ++i;
-               char previous_char = 0;
-               char temp = 0;
+               char_type previous_char = 0;
+               char_type temp = 0;
                if (i < end) {
                        previous_char = text_[i];
                        if (!isNewline(i)) {
@@ -709,7 +742,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 +751,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);
 }
 
 
@@ -759,7 +786,21 @@ string const corrected_env(string const & suffix, string const & env,
                output += correction(env);
        else
                output += env;
-       return output + "}";
+       output += "}";
+       if (suffix == "\\begin")
+               output += "\n";
+       return output;
+}
+
+
+int adjust_column_count(string const & str, int oldcol)
+{
+       if (!contains(str, "\n"))
+               return oldcol + str.size();
+       else {
+               string tmp;
+               return rsplit(str, tmp, '\n').size();
+       }
 }
 
 } // namespace anon
@@ -767,7 +808,7 @@ string const corrected_env(string const & suffix, string const & env,
 
 // This could go to ParagraphParameters if we want to
 int Paragraph::startTeXParParams(BufferParams const & bparams,
-                                ostream & os, bool moving_arg) const
+                                 odocstream & os, bool moving_arg) const
 {
        int column = 0;
 
@@ -804,8 +845,8 @@ int Paragraph::startTeXParParams(BufferParams const & bparams,
                        output = corrected_env("\\begin", "flushleft", ownerCode());
                else
                        output = corrected_env("\\begin", "flushright", ownerCode());
-               os << output;
-               column += output.size();
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        } case LYX_ALIGN_RIGHT: {
                string output;
@@ -813,14 +854,14 @@ int Paragraph::startTeXParParams(BufferParams const & bparams,
                        output = corrected_env("\\begin", "flushright", ownerCode());
                else
                        output = corrected_env("\\begin", "flushleft", ownerCode());
-               os << output;
-               column += output.size();
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        } case LYX_ALIGN_CENTER: {
                string output;
                output = corrected_env("\\begin", "center", ownerCode());
-               os << output;
-               column += output.size();
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        }
        }
@@ -831,7 +872,7 @@ int Paragraph::startTeXParParams(BufferParams const & bparams,
 
 // This could go to ParagraphParameters if we want to
 int Paragraph::endTeXParParams(BufferParams const & bparams,
-                              ostream & os, bool moving_arg) const
+                               odocstream & os, bool moving_arg) const
 {
        int column = 0;
 
@@ -860,26 +901,26 @@ int Paragraph::endTeXParParams(BufferParams const & bparams,
        case LYX_ALIGN_LEFT: {
                string output;
                if (getParLanguage(bparams)->babel() != "hebrew")
-                       output = corrected_env("\\par\\end", "flushleft", ownerCode());
+                       output = corrected_env("\n\\par\\end", "flushleft", ownerCode());
                else
-                       output = corrected_env("\\par\\end", "flushright", ownerCode());
-               os << output;
-               column += output.size();
+                       output = corrected_env("\n\\par\\end", "flushright", ownerCode());
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        } case LYX_ALIGN_RIGHT: {
                string output;
                if (getParLanguage(bparams)->babel() != "hebrew")
-                       output = corrected_env("\\par\\end", "flushright", ownerCode());
+                       output = corrected_env("\n\\par\\end", "flushright", ownerCode());
                else
-                       output = corrected_env("\\par\\end", "flushleft", ownerCode());
-               os << output;
-               column += output.size();
+                       output = corrected_env("\n\\par\\end", "flushleft", ownerCode());
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        } case LYX_ALIGN_CENTER: {
                string output;
-               output = corrected_env("\\par\\end", "center", ownerCode());
-               os << output;
-               column += output.size();
+               output = corrected_env("\n\\par\\end", "center", ownerCode());
+               os << from_ascii(output);
+               column = adjust_column_count(output, column);
                break;
        }
        }
@@ -892,7 +933,7 @@ int Paragraph::endTeXParParams(BufferParams const & bparams,
 bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                                BufferParams const & bparams,
                                LyXFont const & outerfont,
-                               ostream & os, TexRow & texrow,
+                               odocstream & os, TexRow & texrow,
                                OutputParams const & runparams) const
 {
        lyxerr[Debug::LATEX] << "SimpleTeXOnePar...     " << this << endl;
@@ -904,7 +945,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
        // well we have to check if we are in an inset with unlimited
        // length (all in one row) if that is true then we don't allow
        // any special options in the paragraph and also we don't allow
-       // any environment other then "Standard" to be valid!
+       // any environment other than the default layout of the text class
+       // to be valid!
        bool asdefault = forceDefaultParagraphs();
 
        if (asdefault) {
@@ -913,8 +955,24 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                style = layout();
        }
 
+       // Current base font for all inherited font changes, without any
+       // change caused by an individual character, except for the language:
+       // It is set to the language of the first character.
+       // As long as we are in the label, this font is the base font of the
+       // label. Before the first body character it is set to the base font
+       // of the body.
+       // This must be identical to basefont in TeXOnePar().
        LyXFont basefont;
 
+       LaTeXFeatures features(buf, bparams, runparams);
+
+       // output change tracking marks only if desired,
+       // if dvipost is installed,
+       // and with dvi/ps (other formats don't work)
+       bool const output = bparams.outputChanges
+               && runparams.flavor == OutputParams::LATEX
+               && features.isAvailable("dvipost");
+
        // Maybe we have to create a optional argument.
        pos_type body_pos = beginOfBody();
        unsigned int column = 0;
@@ -929,14 +987,12 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                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?
        bool open_font = false;
 
-       Change::Type running_change = Change::UNCHANGED;
+       Change::Type runningChangeType = Change::UNCHANGED;
 
        texrow.start(id(), 0);
 
@@ -947,7 +1003,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) {
@@ -956,7 +1013,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                if (i == body_pos) {
                        if (body_pos > 0) {
                                if (open_font) {
-                                       column += running_font.latexWriteEndChanges(os, basefont, basefont);
+                                       column += running_font.latexWriteEndChanges(
+                                               os, basefont, basefont, bparams);
                                        open_font = false;
                                }
                                basefont = getLayoutFont(bparams, outerfont);
@@ -971,7 +1029,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
                        if (!asdefault)
                                column += startTeXParParams(bparams, os,
-                                                           moving_arg);
+                                                           runparams.moving_arg);
                }
 
                value_type c = getChar(i);
@@ -996,9 +1054,10 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                    (font != running_font ||
                     font.language() != running_font.language()))
                {
-                       column += running_font.latexWriteEndChanges(os,
-                                                                   basefont,
-                                                                   (i == body_pos-1) ? basefont : font);
+                       column += running_font.latexWriteEndChanges(
+                                       os, basefont,
+                                       (i == body_pos-1) ? basefont : font,
+                                       bparams);
                        running_font = basefont;
                        open_font = false;
                }
@@ -1017,32 +1076,36 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                     font.language() != running_font.language()) &&
                        i != body_pos - 1)
                {
-                       column += font.latexWriteStartChanges(os, basefont,
-                                                             last_font);
+                       column += font.latexWriteStartChanges(
+                                       os, basefont, last_font, bparams);
                        running_font = font;
                        open_font = true;
                }
 
-               Change::Type change = pimpl_->lookupChange(i);
-
-               column += Changes::latexMarkChange(os, running_change, change);
-               running_change = change;
-
-               OutputParams rp = runparams;
-               rp.moving_arg = moving_arg;
-               rp.free_spacing = style->free_spacing;
-               rp.local_language = 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);
+               Change::Type changeType = pimpl_->lookupChange(i).type;
+
+               column += Changes::latexMarkChange(os, runningChangeType,
+                       changeType, output);
+               runningChangeType = changeType;
+
+               // do not output text which is marked deleted
+               // if change tracking output is not desired
+               if (output || runningChangeType != 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,
+                                               runningChangeType,
+                                               *style, i, column, c);
+               }
        }
 
        column += Changes::latexMarkChange(os,
-                       running_change, Change::UNCHANGED);
+                       runningChangeType, Change::UNCHANGED, output);
 
        // If we have an open font definition, we have to close it
        if (open_font) {
@@ -1050,11 +1113,11 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                if (next_) {
                        running_font
                                .latexWriteEndChanges(os, basefont,
-                                                     next_->getFont(bparams,
-                                                     0, outerfont));
+                                       next_->getFont(bparams, 0, outerfont),
+                                       bparams);
                } else {
                        running_font.latexWriteEndChanges(os, basefont,
-                                                         basefont);
+                                                         basefont, bparams);
                }
 #else
 #ifdef WITH_WARNINGS
@@ -1062,18 +1125,19 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 //#warning there as we start another \selectlanguage with the next paragraph if
 //#warning we are in need of this. This should be fixed sometime (Jug)
 #endif
-               running_font.latexWriteEndChanges(os, basefont,  basefont);
+               running_font.latexWriteEndChanges(os, basefont, basefont,
+                                                 bparams);
 #endif
        }
 
        // 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;
@@ -1083,18 +1147,6 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
 namespace {
 
-// checks, if newcol chars should be put into this line
-// writes newline, if necessary.
-void sgmlLineBreak(ostream & os, string::size_type & colcount,
-                         string::size_type newcol)
-{
-       colcount += newcol;
-       if (colcount > lyxrc.ascii_linelen) {
-               os << "\n";
-               colcount = newcol; // assume write after this call
-       }
-}
-
 enum PAR_TAG {
        PAR_NONE=0,
        TT = 1,
@@ -1136,227 +1188,31 @@ void reset(PAR_TAG & p1, PAR_TAG const & p2)
 } // anon
 
 
-// Handle internal paragraph parsing -- layout already processed.
-void Paragraph::simpleLinuxDocOnePar(Buffer const & buf,
-                                    ostream & os,
-                                    LyXFont const & outerfont,
-                                    OutputParams const & runparams,
-                                    lyx::depth_type /*depth*/) const
-{
-       LyXLayout_ptr const & style = layout();
-
-       string::size_type char_line_count = 5;     // Heuristic choice ;-)
-
-       // gets paragraph main font
-       LyXFont font_old;
-       bool desc_on;
-       if (style->labeltype == LABEL_MANUAL) {
-               font_old = style->labelfont;
-               desc_on = true;
-       } else {
-               font_old = style->font;
-               desc_on = false;
-       }
-
-       LyXFont::FONT_FAMILY family_type = LyXFont::ROMAN_FAMILY;
-       LyXFont::FONT_SERIES series_type = LyXFont::MEDIUM_SERIES;
-       LyXFont::FONT_SHAPE  shape_type  = LyXFont::UP_SHAPE;
-       bool is_em = false;
-
-       stack<PAR_TAG> tag_state;
-       // parsing main loop
-       for (pos_type i = 0; i < size(); ++i) {
-
-               PAR_TAG tag_close = PAR_NONE;
-               list < PAR_TAG > tag_open;
-
-               LyXFont const font = getFont(buf.params(), i, outerfont);
-
-               if (font_old.family() != font.family()) {
-                       switch (family_type) {
-                       case LyXFont::SANS_FAMILY:
-                               tag_close |= SF;
-                               break;
-                       case LyXFont::TYPEWRITER_FAMILY:
-                               tag_close |= TT;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       family_type = font.family();
-
-                       switch (family_type) {
-                       case LyXFont::SANS_FAMILY:
-                               tag_open.push_back(SF);
-                               break;
-                       case LyXFont::TYPEWRITER_FAMILY:
-                               tag_open.push_back(TT);
-                               break;
-                       default:
-                               break;
-                       }
-               }
-
-               if (font_old.series() != font.series()) {
-                       switch (series_type) {
-                       case LyXFont::BOLD_SERIES:
-                               tag_close |= BF;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       series_type = font.series();
-
-                       switch (series_type) {
-                       case LyXFont::BOLD_SERIES:
-                               tag_open.push_back(BF);
-                               break;
-                       default:
-                               break;
-                       }
-
-               }
-
-               if (font_old.shape() != font.shape()) {
-                       switch (shape_type) {
-                       case LyXFont::ITALIC_SHAPE:
-                               tag_close |= IT;
-                               break;
-                       case LyXFont::SLANTED_SHAPE:
-                               tag_close |= SL;
-                               break;
-                       default:
-                               break;
-                       }
-
-                       shape_type = font.shape();
-
-                       switch (shape_type) {
-                       case LyXFont::ITALIC_SHAPE:
-                               tag_open.push_back(IT);
-                               break;
-                       case LyXFont::SLANTED_SHAPE:
-                               tag_open.push_back(SL);
-                               break;
-                       default:
-                               break;
-                       }
-               }
-               // handle <em> tag
-               if (font_old.emph() != font.emph()) {
-                       if (font.emph() == LyXFont::ON) {
-                               tag_open.push_back(EM);
-                               is_em = true;
-                       }
-                       else if (is_em) {
-                               tag_close |= EM;
-                               is_em = false;
-                       }
-               }
-
-               list < PAR_TAG > temp;
-               while (!tag_state.empty() && tag_close) {
-                       PAR_TAG k =  tag_state.top();
-                       tag_state.pop();
-                       os << "</" << tag_name(k) << '>';
-                       if (tag_close & k)
-                               reset(tag_close,k);
-                       else
-                               temp.push_back(k);
-               }
-
-               for(list< PAR_TAG >::const_iterator j = temp.begin();
-                   j != temp.end(); ++j) {
-                       tag_state.push(*j);
-                       os << '<' << tag_name(*j) << '>';
-               }
-
-               for(list< PAR_TAG >::const_iterator j = tag_open.begin();
-                   j != tag_open.end(); ++j) {
-                       tag_state.push(*j);
-                       os << '<' << tag_name(*j) << '>';
-               }
-
-               char c = getChar(i);
-
-
-               if (c == Paragraph::META_INSET) {
-                       getInset(i)->linuxdoc(buf, os, runparams);
-                       font_old = font;
-                       continue;
-               }
-
-               if (style->latexparam() == "CDATA") {
-                       // "TeX"-Mode on == > SGML-Mode on.
-                       if (c != '\0')
-                               os << c;
-                       ++char_line_count;
-               } else {
-                       bool ws;
-                       string str;
-                       boost::tie(ws, str) = sgml::escapeChar(c);
-                       if (ws && !isFreeSpacing()) {
-                               // in freespacing mode, spaces are
-                               // non-breaking characters
-                               if (desc_on) { // if char is ' ' then...
-                                       ++char_line_count;
-                                       sgmlLineBreak(os, char_line_count, 6);
-                                       os << "</tag>";
-                                       desc_on = false;
-                               } else  {
-                                       sgmlLineBreak(os, char_line_count, 1);
-                                       os << c;
-                               }
-                       } else {
-                               os << str;
-                               char_line_count += str.length();
-                       }
-               }
-               font_old = font;
-       }
-
-       while (!tag_state.empty()) {
-               os << "</" << tag_name(tag_state.top()) << '>';
-               tag_state.pop();
-       }
-
-       // resets description flag correctly
-       if (desc_on) {
-               // <tag> not closed...
-               sgmlLineBreak(os, char_line_count, 6);
-               os << "</tag>";
-       }
-}
-
-
 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 and
-                           lyx_code != InsetBase::INCLUDE_CODE and
-                           lyx_code != InsetBase::GRAPHICS_CODE and
-                           lyx_code != InsetBase::ERT_CODE and
-                           lyx_code != InsetBase::FLOAT_CODE and
+                       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 {
-                       char c = getChar(i);
-                       if(c!= ' ' and c!= '\t')
+                       value_type c = getChar(i);
+                       if (c != ' ' && c != '\t')
                                return false;
                }
-
        }
        return true;
 }
 
 
-string Paragraph::getID() const
+string Paragraph::getID(Buffer const & buf, OutputParams const & runparams) const
 {
        for (pos_type i = 0; i < size(); ++i) {
                if (isInset(i)) {
@@ -1364,7 +1220,7 @@ string Paragraph::getID() const
                        InsetBase::Code lyx_code = inset->lyxCode();
                        if (lyx_code == InsetBase::LABEL_CODE) {
                                string const id = static_cast<InsetCommand const *>(inset)->getContents();
-                               return "id=\"" + sgml::cleanID(id) + "\"";
+                               return "id='" + to_utf8(sgml::cleanID(buf, runparams, from_utf8(id))) + "'";
                        }
                }
 
@@ -1373,30 +1229,43 @@ string Paragraph::getID() const
 }
 
 
-pos_type Paragraph::getFirstWord(Buffer const & buf, ostream & os, OutputParams const & runparams) const
+pos_type Paragraph::getFirstWord(Buffer const & buf, odocstream & os, OutputParams const & runparams) const
 {
        pos_type i;
-       LyXLayout_ptr const & style = layout();
        for (i = 0; i < size(); ++i) {
                if (isInset(i)) {
                        InsetBase const * inset = getInset(i);
                        inset->docbook(buf, os, runparams);
                } else {
-                       char c = getChar(i);
+                       value_type c = getChar(i);
                        if (c == ' ')
                                break;
-                       bool ws;
-                       string str;
-                       boost::tie(ws, str) = sgml::escapeChar(c);
-
-                       os << str;
-               }
+                       os << sgml::escapeChar(c);
+               }
        }
        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,
+                                   odocstream & os,
                                    OutputParams const & runparams,
                                    LyXFont const & outerfont,
                                    pos_type initial) const
@@ -1407,7 +1276,9 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
        LyXFont font_old =
                style->labeltype == LABEL_MANUAL ? style->labelfont : style->font;
 
-       bool cdata = style->pass_thru;
+       if (style->pass_thru && !onlyText(buf, outerfont, initial))
+               os << "]]>";
+
        // parsing main loop
        for (pos_type i = initial; i < size(); ++i) {
                LyXFont font = getFont(buf.params(), i, outerfont);
@@ -1415,73 +1286,36 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
                // handle <emphasis> tag
                if (font_old.emph() != font.emph()) {
                        if (font.emph() == LyXFont::ON) {
-                               if (cdata)
-                                       os << "]]>";
                                os << "<emphasis>";
-                               if (cdata)
-                                       os << "<![CDATA[";
                                emph_flag = true;
                        } else if (i != initial) {
-                               if (cdata)
-                                       os << "]]>";
                                os << "</emphasis>";
-                               if (cdata)
-                                       os << "<![CDATA[";
                                emph_flag = false;
                        }
                }
 
                if (isInset(i)) {
                        InsetBase const * inset = getInset(i);
-                       if (cdata)
-                               os << "]]>";
                        inset->docbook(buf, os, runparams);
-                       if (cdata)
-                               os << "<![CDATA[";
                } else {
-                       char c = getChar(i);
-                       bool ws;
-                       string str;
-                       boost::tie(ws, str) = sgml::escapeChar(c);
+                       value_type c = getChar(i);
 
                        if (style->pass_thru)
-                               os << c;
+                                os.put(c);
                        else
-                               os << str;
+                                os << sgml::escapeChar(c);
                }
                font_old = font;
        }
 
        if (emph_flag) {
-               if (cdata)
-                       os << "]]>";
                os << "</emphasis>";
-               if (cdata)
-                       os << "<![CDATA[";
        }
 
        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[";
 }
 
 
@@ -1492,49 +1326,24 @@ bool Paragraph::isNewline(pos_type pos) const
 }
 
 
-bool Paragraph::isSeparator(pos_type pos) const
-{
-       return IsSeparatorChar(getChar(pos));
-}
-
-
 bool Paragraph::isLineSeparator(pos_type pos) const
 {
        value_type const c = getChar(pos);
-       return IsLineSeparatorChar(c)
-               || (IsInsetChar(c) && getInset(pos) &&
+       return isLineSeparatorChar(c)
+               || (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);
+       }
 }
 
 
@@ -1542,7 +1351,7 @@ Language const *
 Paragraph::getParLanguage(BufferParams const & bparams) const
 {
        if (!empty())
-               return getFirstFontSettings().language();
+               return getFirstFontSettings(bparams).language();
 #ifdef WITH_WARNINGS
 #warning FIXME we should check the prev par as well (Lgb)
 #endif
@@ -1553,7 +1362,7 @@ Paragraph::getParLanguage(BufferParams const & bparams) const
 bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
 {
        return lyxrc.rtl_support
-               && getParLanguage(bparams)->RightToLeft()
+               && getParLanguage(bparams)->rightToLeft()
                && ownerCode() != InsetBase::ERT_CODE;
 }
 
@@ -1561,7 +1370,8 @@ bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
 void Paragraph::changeLanguage(BufferParams const & bparams,
                               Language const * from, Language const * to)
 {
-       for (pos_type i = 0; i < size(); ++i) {
+       // change language including dummy font change at the end
+       for (pos_type i = 0; i <= size(); ++i) {
                LyXFont font = getFontSettings(bparams, i);
                if (font.language() == from) {
                        font.setLanguage(to);
@@ -1588,150 +1398,79 @@ bool Paragraph::isMultiLingual(BufferParams const & bparams) const
 
 // Convert the paragraph to a string.
 // Used for building the table of contents
-string const Paragraph::asString(Buffer const & buffer, bool label) const
-{
-       OutputParams runparams;
-       return asString(buffer, runparams, label);
-}
-
-
-string const Paragraph::asString(Buffer const & buffer,
-                                OutputParams const & runparams,
-                                bool label) const
+docstring const Paragraph::asString(Buffer const & buffer, bool label) const
 {
-#if 0
-       string s;
-       if (label && !params().labelString().empty())
-               s += params().labelString() + ' ';
-
-       for (pos_type i = 0; i < size(); ++i) {
-               value_type c = getChar(i);
-               if (IsPrintable(c))
-                       s += c;
-               else if (c == META_INSET &&
-                        getInset(i)->lyxCode() == InsetBase::MATH_CODE) {
-                       ostringstream os;
-                       getInset(i)->plaintext(buffer, os, runparams);
-                       s += subst(STRCONV(os.str()),'\n',' ');
-               }
-       }
-
-       return s;
-#else
-       // This should really be done by the caller and not here.
-       string ret = asString(buffer, runparams, 0, size(), label);
-       return subst(ret, '\n', ' ');
-#endif
+       return asString(buffer, 0, size(), label);
 }
 
 
-string const Paragraph::asString(Buffer const & buffer,
+docstring const Paragraph::asString(Buffer const & buffer,
                                 pos_type beg, pos_type end, bool label) const
 {
 
-       OutputParams const runparams;
-       return asString(buffer, runparams, beg, end, label);
-}
-
-
-string const Paragraph::asString(Buffer const & buffer,
-                                OutputParams const & runparams,
-                                pos_type beg, pos_type end, bool label) const
-{
-       ostringstream os;
+       odocstringstream os;
 
        if (beg == 0 && label && !params().labelString().empty())
                os << params().labelString() << ' ';
 
        for (pos_type i = beg; i < end; ++i) {
                value_type const c = getUChar(buffer.params(), i);
-               if (IsPrintable(c))
-                       os << c;
+               if (isPrintable(c))
+                       os.put(c);
                else if (c == META_INSET)
-                       getInset(i)->plaintext(buffer, os, runparams);
+                       getInset(i)->textString(buffer, os);
        }
 
        return os.str();
 }
 
 
-void Paragraph::setInsetOwner(UpdatableInset * inset)
+void Paragraph::setInsetOwner(InsetBase * inset)
 {
        pimpl_->inset_owner = inset;
 }
 
 
-void Paragraph::setContentsFromPar(Paragraph const & par)
+Change const & Paragraph::lookupChange(pos_type pos) const
 {
-       pimpl_->setContentsFromPar(par);
-}
-
-
-void Paragraph::trackChanges(Change::Type type)
-{
-       pimpl_->trackChanges(type);
-}
-
-
-void Paragraph::untrackChanges()
-{
-       pimpl_->untrackChanges();
-}
-
-
-void Paragraph::cleanChanges()
-{
-       pimpl_->cleanChanges();
-}
-
-
-Change::Type Paragraph::lookupChange(lyx::pos_type pos) const
-{
-       BOOST_ASSERT(empty() || pos < size());
+       BOOST_ASSERT(pos <= size());
        return pimpl_->lookupChange(pos);
 }
 
 
-Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const
-{
-       BOOST_ASSERT(empty() || pos < size());
-       return pimpl_->lookupChangeFull(pos);
-}
-
-
 bool Paragraph::isChanged(pos_type start, pos_type end) const
 {
        return pimpl_->isChanged(start, end);
 }
 
 
-bool Paragraph::isChangeEdited(pos_type start, pos_type end) const
+bool Paragraph::isMergedOnEndOfParDeletion(bool trackChanges) const
 {
-       return pimpl_->isChangeEdited(start, end);
+       return pimpl_->isMergedOnEndOfParDeletion(trackChanges);
 }
 
 
-void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
+void Paragraph::setChange(Change const & change)
 {
-       pimpl_->setChange(pos, type);
+       pimpl_->setChange(change);
 }
 
 
-void Paragraph::markErased()
+void Paragraph::setChange(pos_type pos, Change const & change)
 {
-       pimpl_->markErased();
+       pimpl_->setChange(pos, change);
 }
 
 
-void Paragraph::acceptChange(pos_type start, pos_type end)
+void Paragraph::acceptChanges(pos_type start, pos_type end)
 {
-       return pimpl_->acceptChange(start, end);
+       return pimpl_->acceptChanges(start, end);
 }
 
 
-void Paragraph::rejectChange(pos_type start, pos_type end)
+void Paragraph::rejectChanges(pos_type start, pos_type end)
 {
-       return pimpl_->rejectChange(start, end);
+       return pimpl_->rejectChanges(start, end);
 }
 
 
@@ -1753,7 +1492,7 @@ void Paragraph::layout(LyXLayout_ptr const & new_layout)
 }
 
 
-UpdatableInset * Paragraph::inInset() const
+InsetBase * Paragraph::inInset() const
 {
        return pimpl_->inset_owner;
 }
@@ -1772,12 +1511,6 @@ void Paragraph::clearContents()
 }
 
 
-void Paragraph::setChar(pos_type pos, value_type c)
-{
-       text_[pos] = c;
-}
-
-
 ParagraphParameters & Paragraph::params()
 {
        return pimpl_->params;
@@ -1809,56 +1542,21 @@ bool Paragraph::allowEmpty() const
 }
 
 
-RowList::iterator Paragraph::getRow(pos_type pos)
-{
-       RowList::iterator rit = rows.end();
-       RowList::iterator const begin = rows.begin();
-
-       for (--rit; rit != begin && rit->pos() > pos; --rit)
-               ;
-
-       return rit;
-}
-
-
-RowList::const_iterator Paragraph::getRow(pos_type pos) const
-{
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
-
-       for (--rit; rit != begin && rit->pos() > pos; --rit)
-               ;
-
-       return rit;
-}
-
-
-size_t Paragraph::row(pos_type pos) const
-{
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
-
-       for (--rit; rit != begin && rit->pos() > pos; --rit)
-               ;
-
-       return rit - begin;
-}
-
-
-unsigned char Paragraph::transformChar(unsigned char c, pos_type pos) const
+char_type Paragraph::transformChar(char_type c, pos_type pos) const
 {
        if (!Encodings::is_arabic(c))
-               if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && IsDigit(c))
+               if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && isDigit(c))
+                       // FIXME UNICODE What does this do?
                        return c + (0xb0 - '0');
                else
                        return c;
 
-       unsigned char const prev_char = pos > 0 ? getChar(pos - 1) : ' ';
-       unsigned char next_char = ' ';
+       value_type const prev_char = pos > 0 ? getChar(pos - 1) : ' ';
+       value_type next_char = ' ';
 
        for (pos_type i = pos + 1, end = size(); i < end; ++i) {
-               unsigned char const par_char = getChar(i);
-               if (!Encodings::IsComposeChar_arabic(par_char)) {
+               value_type const par_char = getChar(i);
+               if (!Encodings::isComposeChar_arabic(par_char)) {
                        next_char = par_char;
                        break;
                }
@@ -1867,14 +1565,74 @@ unsigned char Paragraph::transformChar(unsigned char c, pos_type pos) const
        if (Encodings::is_arabic(next_char)) {
                if (Encodings::is_arabic(prev_char) &&
                        !Encodings::is_arabic_special(prev_char))
-                       return Encodings::TransformChar(c, Encodings::FORM_MEDIAL);
+                       return Encodings::transformChar(c, Encodings::FORM_MEDIAL);
                else
-                       return Encodings::TransformChar(c, Encodings::FORM_INITIAL);
+                       return Encodings::transformChar(c, Encodings::FORM_INITIAL);
        } else {
                if (Encodings::is_arabic(prev_char) &&
                        !Encodings::is_arabic_special(prev_char))
-                       return Encodings::TransformChar(c, Encodings::FORM_FINAL);
+                       return Encodings::transformChar(c, Encodings::FORM_FINAL);
                else
-                       return Encodings::TransformChar(c, Encodings::FORM_ISOLATED);
+                       return Encodings::transformChar(c, Encodings::FORM_ISOLATED);
+       }
+}
+
+
+bool Paragraph::hfillExpansion(Row const & row, pos_type pos) const
+{
+       if (!isHfill(pos))
+               return false;
+
+       BOOST_ASSERT(pos >= row.pos() && pos < row.endpos());
+
+       // expand at the end of a row only if there is another hfill on the same row
+       if (pos == row.endpos() - 1) {
+               for (pos_type i = row.pos(); i < pos; i++) {
+                       if (isHfill(i))
+                               return true;
+               }
+               return false;
+       }
+
+       // expand at the beginning of a row only if it is the first row of a paragraph
+       if (pos == row.pos()) {
+               return pos == 0;
        }
+
+       // do not expand in some labels
+       if (layout()->margintype != MARGIN_MANUAL && pos < beginOfBody())
+               return false;
+
+       // if there is anything between the first char of the row and
+       // the specified position that is neither a newline nor an hfill,
+       // the hfill will be expanded, otherwise it won't
+       for (pos_type i = row.pos(); i < pos; i++) {
+               if (!isNewline(i) && !isHfill(i))
+                       return true;
+       }
+       return false;
+}
+
+
+bool Paragraph::checkBiblio(bool track_changes)
+{
+       // Add bibitem insets if necessary
+       if (layout()->labeltype != LABEL_BIBLIO)
+               return false;
+
+       bool hasbibitem = !insetlist.empty()
+               // Insist on it being in pos 0
+               && getChar(0) == Paragraph::META_INSET
+               && insetlist.begin()->inset->lyxCode() == InsetBase::BIBITEM_CODE;
+
+       if (hasbibitem)
+               return false;
+
+       InsetBibitem * inset(new InsetBibitem(InsetCommandParams("bibitem")));
+       insertInset(0, static_cast<InsetBase *>(inset),
+               Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
+
+       return true;
 }
+
+} // namespace lyx