+ d->changes_.checkAuthors(authorList);
+}
+
+
+bool Paragraph::isUnchanged(pos_type pos) const
+{
+ return lookupChange(pos).type == Change::UNCHANGED;
+}
+
+
+bool Paragraph::isInserted(pos_type pos) const
+{
+ return lookupChange(pos).type == Change::INSERTED;
+}
+
+
+bool Paragraph::isDeleted(pos_type pos) const
+{
+ return lookupChange(pos).type == Change::DELETED;
+}
+
+
+InsetList const & Paragraph::insetList() const
+{
+ return d->insetlist_;
+}
+
+
+Inset * Paragraph::releaseInset(pos_type pos)
+{
+ Inset * inset = d->insetlist_.release(pos);
+ /// does not honour change tracking!
+ eraseChar(pos, false);
+ return inset;
+}
+
+
+Inset * Paragraph::getInset(pos_type pos)
+{
+ return d->insetlist_.get(pos);
+}
+
+
+Inset const * Paragraph::getInset(pos_type pos) const
+{
+ return d->insetlist_.get(pos);
+}
+
+
+void Paragraph::changeCase(BufferParams const & bparams, pos_type pos,
+ pos_type right, TextCase action)
+{
+ // process sequences of modified characters; in change
+ // tracking mode, this approach results in much better
+ // usability than changing case on a char-by-char basis
+ docstring changes;
+
+ bool const trackChanges = bparams.trackChanges;
+
+ bool capitalize = true;
+
+ for (; pos < right; ++pos) {
+ char_type oldChar = d->text_[pos];
+ char_type newChar = oldChar;
+
+ // ignore insets and don't play with deleted text!
+ if (oldChar != META_INSET && !isDeleted(pos)) {
+ switch (action) {
+ case text_lowercase:
+ newChar = lowercase(oldChar);
+ break;
+ case text_capitalization:
+ if (capitalize) {
+ newChar = uppercase(oldChar);
+ capitalize = false;
+ }
+ break;
+ case text_uppercase:
+ newChar = uppercase(oldChar);
+ break;
+ }
+ }
+
+ if (!isLetter(pos) || isDeleted(pos)) {
+ // permit capitalization again
+ capitalize = true;
+ }
+
+ if (oldChar != newChar)
+ changes += newChar;
+
+ if (oldChar == newChar || pos == right - 1) {
+ if (oldChar != newChar) {
+ // step behind the changing area
+ pos++;
+ }
+ int erasePos = pos - changes.size();
+ for (size_t i = 0; i < changes.size(); i++) {
+ insertChar(pos, changes[i],
+ getFontSettings(bparams,
+ erasePos),
+ trackChanges);
+ if (!eraseChar(erasePos, trackChanges)) {
+ ++erasePos;
+ ++pos; // advance
+ ++right; // expand selection
+ }
+ }
+ changes.clear();
+ }
+ }
+}
+
+
+bool Paragraph::find(docstring const & str, bool cs, bool mw,
+ pos_type pos, bool del) const
+{
+ int const strsize = str.length();
+ int i = 0;
+ pos_type const parsize = d->text_.size();
+ for (i = 0; pos + i < parsize; ++i) {
+ if (i >= strsize)
+ break;
+ if (cs && str[i] != d->text_[pos + i])
+ break;
+ if (!cs && uppercase(str[i]) != uppercase(d->text_[pos + i]))
+ break;
+ if (!del && isDeleted(pos + i))
+ break;
+ }
+
+ if (i != strsize)
+ return false;
+
+ // if necessary, check whether string matches word
+ if (mw) {
+ if (pos > 0 && isLetter(pos - 1))
+ return false;
+ if (pos + strsize < parsize
+ && isLetter(pos + strsize))
+ return false;
+ }
+
+ return true;
+}
+
+
+char_type Paragraph::getChar(pos_type pos) const
+{
+ return d->text_[pos];
+}
+
+
+pos_type Paragraph::size() const
+{
+ return d->text_.size();
+}
+
+
+bool Paragraph::empty() const
+{
+ return d->text_.empty();
+}
+
+
+bool Paragraph::isInset(pos_type pos) const
+{
+ return d->text_[pos] == META_INSET;
+}
+
+
+bool Paragraph::isSeparator(pos_type pos) const
+{
+ //FIXME: Are we sure this can be the only separator?
+ return d->text_[pos] == ' ';