]> git.lyx.org Git - lyx.git/blobdiff - src/insets/insettext.C
clear()->erase() ; lots of using directives for cxx
[lyx.git] / src / insets / insettext.C
index 50a3788a31166fd045a23f2c3ba092beff475df9..e0b8f1f5b35ef77a7f2bdc85ec5bb3384fbc66f5 100644 (file)
@@ -4,7 +4,7 @@
  * 
  *           LyX, The Document Processor
  *
- *           Copyright 1998 The LyX Team.
+ *           Copyright 1998-2000 The LyX Team.
  *
  * ======================================================
  */
@@ -12,7 +12,7 @@
 #include <config.h>
 
 #include <fstream>
-using std::ifstream;
+#include <algorithm>
 
 #include <cstdlib>
 
@@ -49,34 +49,59 @@ using std::ifstream;
 #include "Painter.h"
 #include "lyx_gui_misc.h"
 #include "support/LAssert.h"
+#include "lyxtext.h"
+#include "lyxcursor.h"
+#include "CutAndPaste.h"
+#include "font.h"
+#include "minibuffer.h"
+#include "toolbar.h"
+
+using std::ostream;
+using std::ifstream;
+using std::endl;
+using std::min;
+using std::max;
 
 extern unsigned char getCurrentTextClass(Buffer *);
+extern LyXTextClass::size_type current_layout;
+
 
 InsetText::InsetText(Buffer * buf)
 {
     par = new LyXParagraph();
-    the_locking_inset = 0;
-    buffer = buf;
-    cursor_visible = false;
-    maxWidth = old_x = -1;
-    actpos = selection_start = selection_end = 0;
-    interline_space = 1;
-    no_selection = false;
-    init_inset = true;
+    init(buf);
 }
 
 
 InsetText::InsetText(InsetText const & ins, Buffer * buf)
 {
-    par = new LyXParagraph(ins.par);
+    par = 0;
+    init(buf, &ins);
+    autoBreakRows = ins.autoBreakRows;
+}
+
+
+void InsetText::init(Buffer * buf, InsetText const * ins)
+{
     the_locking_inset = 0;
     buffer = buf;
     cursor_visible = false;
-    maxWidth = old_x = -1;
-    actpos = selection_start = selection_end = 0;
+    cursor.x_fix = -1;
     interline_space = 1;
     no_selection = false;
     init_inset = true;
+    maxAscent = maxDescent = insetWidth = 0;
+    drawTextXOffset = drawTextYOffset = 0;
+    autoBreakRows = false;
+    xpos = 0.0;
+    if (ins) {
+       SetParagraphData(ins->par);
+       autoBreakRows = ins->autoBreakRows;
+    }
+    par->SetInsetOwner(this);
+    cursor.par = par;
+    cursor.pos = 0;
+    selection_start_cursor = selection_end_cursor = cursor;
 }
 
 
@@ -102,272 +127,39 @@ void InsetText::Write(ostream & os) const
 
 void InsetText::WriteParagraphData(ostream & os) const
 {
-    LyXFont font1 = LyXFont(LyXFont::ALL_INHERIT);
-    LyXFont font2;
-    int column = 0;
-    char c = 0;
-
-    for (int i = 0; i < par->Last(); ++i) {
-        // Write font changes
-        font2 = par->GetFontSettings(i);
-        if (font2 != font1) {
-            font2.lyxWriteChanges(font1, os);
-            column = 0;
-            font1 = font2;
-        }
-        c = par->GetChar(i);
-        // A newline before tags
-        if (column > 0 &&
-            (c == LyXParagraph::META_INSET ||
-             c == LyXParagraph::META_NEWLINE ||
-             c == '\\')) {
-            os << "\n";
-            column = 0;
-        }
-       
-        switch (c) {
-          case LyXParagraph::META_INSET: {
-              Inset * inset = par->GetInset(i);
-              if (inset) {
-                 os << "\n\\begin_inset ";
-                 inset->Write(os);
-                 os << "\n\\end_inset \n\n";
-                  column = 0;
-              }
-          }
-          break;
-          case LyXParagraph::META_NEWLINE: 
-              os << "\\newline\n";
-              column = 0;
-              break;
-          case '\\': 
-              os << "\\backslash\n";
-              column = 0;
-              break;
-          default:
-              if (column > 65 && c==' ') {
-                  os << "\n";
-                  column = 0;
-              }
-              // this check is to amend a bug. LyX sometimes
-              // inserts '\0' this could cause problems.
-              if (c != '\0')
-                  os << c;
-              else
-                     lyxerr << "ERROR (InsetText::writeFile):"
-                             " '\\0' char in structure.\n";
-              column++;
-              break;
-        }
-    }
-    // A newline if the last c was not a tag.
-    if (column > 0 &&
-        (c != LyXParagraph::META_INSET &&
-         c != LyXParagraph::META_NEWLINE &&
-         c != '\\')) {
-        os << "\n";
-        column = 0;
-    }
+    par->writeFile(os, buffer->params, 0, 0);
 }
 
 
 void InsetText::Read(LyXLex & lex)
 {
     string token, tmptok;
-    LyXFont font = LyXFont(LyXFont::ALL_INHERIT);
     int pos = 0;
+    LyXParagraph * return_par = 0;
+    char depth = 0; // signed or unsigned?
+    LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
+    LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
+    LyXFont font(LyXFont::ALL_INHERIT);
 
     delete par;
     par = new LyXParagraph;
+    par->SetInsetOwner(this);
     
     while (lex.IsOK()) {
         lex.nextToken();
         token = lex.GetString();
         if (token.empty())
             continue;
-        else if (token[0] != '\\') {
-            int n = token.length();
-            for (int i = 0; i < n; ++i) {
-                par->InsertChar(pos, token[i]);
-                par->SetFont(pos, font);
-                ++pos;
-            }
-        } else if (token == "\\newline") {
-            par->InsertChar(pos, LyXParagraph::META_NEWLINE);
-            par->SetFont(pos, font);
-            ++pos;
-        } else if (token == "\\family") { 
-            lex.next();
-            font.setLyXFamily(lex.GetString());
-        } else if (token == "\\series") {
-            lex.next();
-            font.setLyXSeries(lex.GetString());
-        } else if (token == "\\shape") {
-            lex.next();
-            font.setLyXShape(lex.GetString());
-        } else if (token == "\\size") {
-            lex.next();
-            font.setLyXSize(lex.GetString());
-        } else if (token == "\\latex") {
-            lex.next();
-            string tok = lex.GetString();
-            // This is dirty, but gone with LyX3. (Asger)
-            if (tok == "no_latex")
-                font.setLatex(LyXFont::OFF);
-            else if (tok == "latex")
-                font.setLatex(LyXFont::ON);
-            else if (tok == "default")
-                font.setLatex(LyXFont::INHERIT);
-            else
-                lex.printError("Unknown LaTeX font flag "
-                               "`$$Token'");
-       } else if (token == "\\direction") {
-               lex.next();
-               string tok = lex.GetString();
-               if (tok == "ltr")
-                       font.setDirection(LyXFont::LTR_DIR);
-               else if (tok == "rtl")
-                       font.setDirection(LyXFont::RTL_DIR);
-               else if (tok == "default")
-                       font.setDirection(LyXFont::INHERIT_DIR);
-               else
-                       lex.printError("Unknown font flag "
-                                      "`$$Token'");
-        } else if (token == "\\emph") {
-            lex.next();
-            font.setEmph(font.setLyXMisc(lex.GetString()));
-        } else if (token == "\\bar") {
-            lex.next();
-            string tok = lex.GetString();
-            // This is dirty, but gone with LyX3. (Asger)
-            if (tok == "under")
-                font.setUnderbar(LyXFont::ON);
-            else if (tok == "no")
-                font.setUnderbar(LyXFont::OFF);
-            else if (tok == "default")
-                font.setUnderbar(LyXFont::INHERIT);
-            else
-                lex.printError("Unknown bar font flag "
-                               "`$$Token'");
-        } else if (token == "\\noun") {
-            lex.next();
-            font.setNoun(font.setLyXMisc(lex.GetString()));
-        } else if (token == "\\color") {
-            lex.next();
-            font.setLyXColor(lex.GetString());
-       } else if (token == "\\begin_inset") {
-           Inset * inset = 0;
-           lex.next();
-           tmptok = lex.GetString();
-           // Test the different insets.
-           if (tmptok == "Quotes") {
-               inset = new InsetQuotes(string());
-               inset->Read(lex);
-           } else if (tmptok == "LaTeXAccent" || tmptok == "\\i") {
-               inset = new InsetLatexAccent;
-               inset->Read(lex);
-           } else if (tmptok == "FormulaMacro") {
-               inset = new InsetFormulaMacro;
-               inset->Read(lex);
-           } else if (tmptok == "Formula") {
-               inset = new InsetFormula;
-               inset->Read(lex);
-           } else if (tmptok == "Figure") {
-               inset = new InsetFig(100,100, buffer);
-               inset->Read(lex);
-#if 0
-           } else if (tmptok == "Tabular") {
-               inset = new InsetTabular(buffer);
-               inset->Read(lex);
-#endif
-           } else if (tmptok == "Text") {
-               inset = new InsetText(buffer);
-               inset->Read(lex);
-           } else if (tmptok == "ERT") {
-               inset = new InsetERT(buffer);
-               inset->Read(lex);
-           } else if (tmptok == "Info") {
-               inset = new InsetInfo;
-               inset->Read(lex);
-           } else if (tmptok == "Include") {
-               inset = new InsetInclude(string(), buffer);
-               inset->Read(lex);
-           } else if (tmptok == "LatexCommand") {
-               InsetCommand inscmd;
-               inscmd.Read(lex);
-               if (inscmd.getCmdName()=="cite") {
-                   inset = new InsetCitation(inscmd.getContents(),
-                                             inscmd.getOptions());
-               } else if (inscmd.getCmdName()=="bibitem") {
-                   lex.printError("Wrong place for bibitem");
-                   inset = inscmd.Clone();
-               } else if (inscmd.getCmdName()=="BibTeX") {
-                   inset = new InsetBibtex(inscmd.getContents(),
-                                           inscmd.getOptions(), buffer);
-               } else if (inscmd.getCmdName()=="index") {
-                   inset = new InsetIndex(inscmd.getContents());
-               } else if (inscmd.getCmdName()=="include") {
-                   inset = new InsetInclude(inscmd.getContents(), buffer);
-               } else if (inscmd.getCmdName()=="label") {
-                   inset = new InsetLabel(inscmd.getCommand());
-               } else if (inscmd.getCmdName() == "ref" ||
-                          inscmd.getCmdName() == "pageref") {
-                   inset = new InsetRef(inscmd, buffer);
-               }
-#if 0  // Is this compatibility code needed (Lgb)
-              else
-                   // The following three are only for compatibility
-                   if (inscmd.getCmdName()=="-") {
-                       inset = new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
-                   } else if (inscmd.getCmdName()=="@.") {
-                       inset = new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
-                   } else if (inscmd.getCmdName()=="ldots") {
-                       inset = new InsetSpecialChar(InsetSpecialChar::LDOTS);
-                   } else
-                       inset = inscmd.Clone();
-#endif
-           }
-           if (inset) {
-               par->InsertChar(pos, LyXParagraph::META_INSET);
-               par->InsertInset(pos, inset);
-               par->SetFont(pos, font);
-               ++pos;
-           } else {
-               lex.printError("Unknown inset `$$Token'. "
-                              "Inserting as text.");
-           }
-#ifndef NO_COMPABILITY
-        } else if (token == "\\hfill") {
-            // now obsolete, but we have a bak compability
-//            Inset * inset = new InsetSpecialChar(LyXParagraph::META_HFILL);
-//            par->InsertChar(pos, LyXParagraph::META_INSET);
-//            par->InsertInset(pos, inset);
-            par->InsertChar(pos, LyXParagraph::META_HFILL);
-            par->SetFont(pos, font);
-            ++pos;
-        } else if (token == "\\protected_separator") {
-            // now obsolete, but we have a back compability
-            par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
-            //Inset * inset = new InsetSpecialChar(LyXParagraph::META_PROTECTED_SEPARATOR);
-//            par->InsertChar(pos, LyXParagraph::META_INSET);
-//            par->InsertInset(pos, inset);
-            par->SetFont(pos, font);
-            ++pos;
-#endif
-        } else if (token == "\\bibitem") {  // ale970302
-            if (!par->bibkey)
-                par->bibkey = new InsetBibKey;
-            par->bibkey->Read(lex);                 
-        }else if (token == "\\backslash") {
-            par->InsertChar(pos, '\\');
-            par->SetFont(pos, font);
-            ++pos;
-        } else if (token == "\\end_inset") {
-            break;
-        } else {
-            lex.printError("Unknown tabular token `$$Token'. Not handled!");
+       if (token == "\\end_inset")
            break;
-        }
+       if (buffer->parseSingleLyXformat2Token(lex, par, return_par,
+                                              token, pos, depth,
+                                              font, footnoteflag,
+                                              footnotekind)) {
+           // the_end read this should NEVER happen
+           lex.printError("\\the_end read in inset! Error in document!");
+           return;
+       }
     }
     if (token != "\\end_inset") {
         lex.printError("Missing \\end_inset at this point. "
@@ -377,78 +169,69 @@ void InsetText::Read(LyXLex & lex)
 }
 
 
-int InsetText::ascent(Painter &pain, LyXFont const & font) const
+int InsetText::ascent(Painter & pain, LyXFont const & font) const
 {
     if (init_inset) {
-       computeTextRows(pain);
+       computeTextRows(pain, xpos);
+       resetPos(pain);
        init_inset = false;
     }
     if (maxAscent)
        return maxAscent;
-    return font.maxAscent();
+    return lyxfont::maxAscent(font);
 }
 
 
-int InsetText::descent(Painter &pain, LyXFont const & font) const
+int InsetText::descent(Painter & pain, LyXFont const & font) const
 {
     if (init_inset) {
-       computeTextRows(pain);
+       computeTextRows(pain, xpos);
+       resetPos(pain);
        init_inset = false;
     }
     if (maxDescent)
        return maxDescent;
-    return font.maxDescent();
+    return lyxfont::maxDescent(font);
 }
 
 
-int InsetText::width(Painter &pain, LyXFont const &) const
+int InsetText::width(Painter & pain, LyXFont const &) const
 {
     if (init_inset) {
-       computeTextRows(pain);
+       computeTextRows(pain, xpos);
+       resetPos(pain);
        init_inset = false;
     }
     return insetWidth;
 }
 
 
-int InsetText::getMaxWidth(UpdatableInset * inset) const
-{
-    if (!the_locking_inset) {
-           lyxerr << "Text: No locking inset in this inset.\n";
-       return 0;
-    }
-
-    if (the_locking_inset==inset) 
-       return maxWidth;
-
-    return the_locking_inset->getMaxWidth(inset);
-}
-
-
 void InsetText::draw(Painter & pain, LyXFont const & f,
                     int baseline, float & x) const
 {
-//    if (init_inset) {
-       computeTextRows(pain);
-//     init_inset = false;
-//    }
+    xpos = x;
     UpdatableInset::draw(pain, f, baseline, x);
     
-    bool do_reset_pos = (x != top_x) || (baseline != top_baseline);
-    top_x = int(x);
-    top_baseline = baseline;
-    computeBaselines(baseline);
-    for(unsigned int r = 0; r < rows.size() - 1; ++r) {
-        drawRowSelection(pain, rows[r].pos, rows[r+1].pos, r, 
+    if (init_inset || (baseline != top_baseline) || (top_x != int(x))) {
+       top_baseline = baseline;
+       if (init_inset || (top_x != int(x))) {
+           top_x = int(x);
+           computeTextRows(pain, x);
+           init_inset = false;
+       }
+       computeBaselines(baseline);
+    }
+    if (the_locking_inset && (cursor.pos == inset_pos)) {
+       resetPos(pain);
+       inset_x = cursor.x - top_x + drawTextXOffset;
+       inset_y = cursor.y + drawTextYOffset;
+    }
+    for(RowList::size_type r = 0; r < rows.size() - 1; ++r) {
+        drawRowSelection(pain, rows[r].pos, rows[r + 1].pos, r, 
                          rows[r].baseline, x);
-        drawRowText(pain, rows[r].pos, rows[r+1].pos, rows[r].baseline, x);
+        drawRowText(pain, rows[r].pos, rows[r + 1].pos, rows[r].baseline, x);
     }
     x += insetWidth;
-    if (!the_locking_inset && do_reset_pos) {
-//        HideInsetCursor(bv);
-//        resetPos(bv);
-//        ShowInsetCursor(bv);
-    }
 }
 
 
@@ -459,12 +242,12 @@ void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
        return;
 
     int s_start, s_end;
-    if (selection_start > selection_end) {
-       s_start = selection_end;
-       s_end = selection_start;
+    if (selection_start_cursor.pos > selection_end_cursor.pos) {
+       s_start = selection_end_cursor.pos;
+       s_end = selection_start_cursor.pos;
     } else {
-       s_start = selection_start;
-       s_end = selection_end;
+       s_start = selection_start_cursor.pos;
+       s_end = selection_end_cursor.pos;
     }
     if ((s_start > endpos) || (s_end < startpos))
        return;
@@ -479,14 +262,14 @@ void InsetText::drawRowSelection(Painter & pain, int startpos, int endpos,
        if ((p >= s_start) && (p <= s_end))
            esel_x = int(x);
        char ch = par->GetChar(p);
-       font = GetFont(par,p);
+       font = GetDrawFont(par,p);
        if (IsFloatChar(ch)) {
            // skip for now
        } else if (ch == LyXParagraph::META_INSET) {
            Inset const * tmpinset = par->GetInset(p);
            x += tmpinset->width(pain, font);
        } else {
-           x += pain.width(ch,font);
+           x += lyxfont::width(ch, font);
        }
     }
     if (p == s_start)
@@ -509,16 +292,45 @@ void InsetText::drawRowText(Painter & pain, int startpos, int endpos,
 
     for(int p = startpos; p < endpos; ++p) {
        char ch = par->GetChar(p);
-       LyXFont font = GetFont(par,p);
+       LyXFont font = GetDrawFont(par,p);
        if (IsFloatChar(ch)) {
            // skip for now
+       } else if (par->IsNewline(p)) {
+               // Draw end-of-line marker
+               int wid = lyxfont::width('n', font);
+               int asc = lyxfont::maxAscent(font);
+               int y = baseline;
+               int xp[3], yp[3];
+               
+               xp[0] = int(x + wid * 0.375);
+               yp[0] = int(y - 0.875 * asc * 0.75);
+               
+               xp[1] = int(x);
+               yp[1] = int(y - 0.500 * asc * 0.75);
+               
+               xp[2] = int(x + wid * 0.375);
+               yp[2] = int(y - 0.125 * asc * 0.75);
+               
+               pain.lines(xp, yp, 3, LColor::eolmarker);
+               
+               xp[0] = int(x);
+               yp[0] = int(y - 0.500 * asc * 0.75);
+               
+               xp[1] = int(x + wid);
+               yp[1] = int(y - 0.500 * asc * 0.75);
+               
+               xp[2] = int(x + wid);
+               yp[2] = int(y - asc * 0.75);
+                       
+               pain.lines(xp, yp, 3, LColor::eolmarker);
+               x += wid;
        } else if (ch == LyXParagraph::META_INSET) {
            Inset * tmpinset = par->GetInset(p);
            if (tmpinset) 
                tmpinset->draw(pain, font, baseline, x);
        } else {
            pain.text(int(x), baseline, ch, font);
-           x += pain.width(ch,font);
+           x += lyxfont::width(ch, font);
        }
     }
 }
@@ -532,33 +344,74 @@ char const * InsetText::EditMessage() const
 
 void InsetText::Edit(BufferView * bv, int x, int y, unsigned int button)
 {
+    par->SetInsetOwner(this);
     UpdatableInset::Edit(bv, x, y, button);
 
-    bv->lockInset(this);
+    if (!bv->lockInset(this)) {
+       lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
+       return;
+    }
     the_locking_inset = 0;
     inset_pos = inset_x = inset_y = 0;
-    no_selection = true;
-    setPos(bv, x,y);
-    selection_start = selection_end = actpos;
-    current_font = real_current_font = GetFont(par, actpos);
+    setPos(bv->painter(), x, y);
+    checkAndActivateInset(bv, x, y, button);
+    selection_start_cursor = selection_end_cursor = cursor;
+    current_font = real_current_font = GetFont(par, cursor.pos);
+    bv->text->FinishUndo();
+    UpdateLocal(bv, true);
 }
 
 
 void InsetText::InsetUnlock(BufferView * bv)
 {
-    if (the_locking_inset)
+    if (the_locking_inset) {
        the_locking_inset->InsetUnlock(bv);
+       the_locking_inset = 0;
+    }
     HideInsetCursor(bv);
+    lyxerr[Debug::INSETS] << "InsetText::InsetUnlock(" << this <<
+           ")" << endl;
     if (hasSelection()) {
-       selection_start = selection_end = actpos;
-       bv->updateInset(this, false);
+       selection_start_cursor = selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
     }
-    the_locking_inset = 0;
     no_selection = false;
 }
 
 
-bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr)
+bool InsetText::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
+{
+    lyxerr[Debug::INSETS] << "InsetText::LockInsetInInset(" << inset << "): ";
+    if (!inset)
+       return false;
+    if (inset == par->GetInset(cursor.pos)) {
+       lyxerr[Debug::INSETS] << "OK" << endl;
+       the_locking_inset = inset;
+       resetPos(bv->painter());
+       inset_x = cursor.x - top_x + drawTextXOffset;
+       inset_y = cursor.y + drawTextYOffset;
+       inset_pos = cursor.pos;
+       return true;
+    } else if (the_locking_inset && (the_locking_inset == inset)) {
+       if (cursor.pos == inset_pos) {
+           lyxerr[Debug::INSETS] << "OK" << endl;
+           resetPos(bv->painter());
+           inset_x = cursor.x - top_x + drawTextXOffset;
+           inset_y = cursor.y + drawTextYOffset;
+       } else {
+           lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
+       }
+    } else if (the_locking_inset) {
+       lyxerr[Debug::INSETS] << "MAYBE" << endl;
+       return the_locking_inset->LockInsetInInset(bv, inset);
+    }
+    lyxerr[Debug::INSETS] << "NOT OK" << endl;
+    return false;
+}
+
+
+bool InsetText::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
+                                  bool lr)
 {
     if (!the_locking_inset)
         return false;
@@ -569,7 +422,7 @@ bool InsetText::UnlockInsetInInset(BufferView * bv, Inset * inset, bool lr)
             moveRight(bv, false);
         return true;
     }
-    return the_locking_inset->UnlockInsetInInset(bv, inset,lr);
+    return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
 }
 
 
@@ -579,74 +432,103 @@ bool InsetText::UpdateInsetInInset(BufferView * bv, Inset * inset)
         return false;
     if (the_locking_inset != inset)
         return the_locking_inset->UpdateInsetInInset(bv, inset);
-    float x = inset_x;
-    inset->draw(bv->getPainter(), real_current_font, inset_y, x);
-    bv->updateInset(this, true);
-    return true;
-}
-
-
-void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
-{
-    if (the_locking_inset) {
-        the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
-        return;
+    lyxerr[Debug::INSETS] << "InsetText::UpdateInsetInInset(" << inset <<
+           ")" << endl;
+    UpdateLocal(bv, true);
+    if (cursor.pos == inset_pos) {
+       inset_x = cursor.x - top_x + drawTextXOffset;
+       inset_y = cursor.y + drawTextYOffset;
     }
-    no_selection = false;
+    return true;
 }
 
 
 void InsetText::InsetButtonPress(BufferView * bv, int x, int y, int button)
 {
     if (hasSelection()) {
-       selection_start = selection_end = actpos;
-       bv->updateInset(this, false);
+       selection_start_cursor = selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
     }
     no_selection = false;
+    setPos(bv->painter(), x, y);
+    cursor.x_fix = -1;
     if (the_locking_inset) {
-       setPos(bv, x,y,false);
        UpdatableInset
-           *inset=0;
-       if (par->GetChar(actpos)==LyXParagraph::META_INSET)
-           inset=(UpdatableInset*)par->GetInset(actpos);
+           *inset = 0;
+       if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET)
+           inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
        if (the_locking_inset == inset) {
            the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
            return;
        } else if (inset) {
            // otherwise unlock the_locking_inset and lock the new inset
-           inset_x = cx-top_x;
-           inset_y = cy;
-           inset_pos = actpos;
            the_locking_inset->InsetUnlock(bv);
-           the_locking_inset = inset;
-           the_locking_inset->Edit(bv, x - inset_x, y - inset_y, button);
+           inset_x = cursor.x - top_x + drawTextXOffset;
+           inset_y = cursor.y + drawTextYOffset;
+           inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
+           inset->Edit(bv, x - inset_x, y - inset_y, button);
+           UpdateLocal(bv, true);
            return;
        }
        // otherwise only unlock the_locking_inset
        the_locking_inset->InsetUnlock(bv);
+       the_locking_inset = 0;
     }
-    HideInsetCursor(bv);
-    the_locking_inset = 0;
-    setPos(bv, x, y);
-    selection_start = selection_end = actpos;
-    if (!the_locking_inset)
-       ShowInsetCursor(bv);
+    if (bv->the_locking_inset) {
+       if ((par->GetChar(cursor.pos) == LyXParagraph::META_INSET) &&
+           par->GetInset(cursor.pos) &&
+           (par->GetInset(cursor.pos)->Editable() == Inset::HIGHLY_EDITABLE)) {
+           UpdatableInset *inset =
+               static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
+           inset_x = cursor.x - top_x + drawTextXOffset;
+           inset_y = cursor.y + drawTextYOffset;
+           inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
+           inset->Edit(bv, x-inset_x, y-inset_y, 0);
+           UpdateLocal(bv, true);
+       }
+    }
+    selection_start_cursor = selection_end_cursor = cursor;
+}
+
+
+void InsetText::InsetButtonRelease(BufferView * bv, int x, int y, int button)
+{
+    UpdatableInset * inset = 0;
+
+    if (the_locking_inset) {
+           the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
+    } else {
+       if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
+           inset = static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
+           if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
+               inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
+           } else {
+               inset_x = cursor.x - top_x + drawTextXOffset;
+               inset_y = cursor.y + drawTextYOffset;
+               inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
+               inset->Edit(bv, x-inset_x, y-inset_y, button);
+           }
+       }
+    }
+    no_selection = false;
 }
 
 
-void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int button)
+void InsetText::InsetMotionNotify(BufferView * bv, int x, int y, int state)
 {
     if (the_locking_inset) {
         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
-                                            y - inset_y,button);
+                                            y - inset_y,state);
         return;
     }
     if (!no_selection) {
-       int old = selection_end;
-       setPos(bv, x, y, false);
-       selection_end = actpos;
-       if (old != selection_end)
-           bv->updateInset(this, false);
+       LyXCursor old = selection_end_cursor;
+       HideInsetCursor(bv);
+       setPos(bv->painter(), x, y);
+       selection_end_cursor = cursor;
+       if (old != selection_end_cursor)
+           UpdateLocal(bv, false);
+       ShowInsetCursor(bv);
     }
     no_selection = false;
 }
@@ -661,35 +543,44 @@ void InsetText::InsetKeyPress(XKeyEvent * xke)
 }
 
 
-UpdatableInset::RESULT InsetText::LocalDispatch(BufferView * bv,
-                                               int action, string const & arg)
+UpdatableInset::RESULT
+InsetText::LocalDispatch(BufferView * bv,
+                        int action, string const & arg)
 {
     no_selection = false;
-    if (UpdatableInset::LocalDispatch(bv, action, arg)) {
-       resetPos(bv);
+    UpdatableInset::RESULT
+        result= UpdatableInset::LocalDispatch(bv, action, arg);
+    if (result != UNDISPATCHED) {
+       resetPos(bv->painter());
        return DISPATCHED;
     }
 
-    UpdatableInset::RESULT
-        result=DISPATCHED;
-
+    result=DISPATCHED;
     if ((action < 0) && arg.empty())
         return FINISHED;
 
     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
-        old_x = -1;
+        cursor.x_fix = -1;
     if (the_locking_inset) {
         result = the_locking_inset->LocalDispatch(bv, action, arg);
-       if (result == DISPATCHED) {
+       if (result == DISPATCHED_NOUPDATE)
+           return result;
+       else if (result == DISPATCHED) {
            the_locking_inset->ToggleInsetCursor(bv);
-           bv->updateInset(this, false);
+           UpdateLocal(bv, false);
            the_locking_inset->ToggleInsetCursor(bv);
             return result;
         } else if (result == FINISHED) {
-           if ((action == LFUN_RIGHT) || (action == -1)) {
-               actpos = inset_pos + 1;
-               resetPos(bv);
+           switch(action) {
+           case -1:
+           case LFUN_RIGHT:
+               cursor.pos = inset_pos + 1;
+               resetPos(bv->painter());
+               break;
+           case LFUN_DOWN:
+               moveDown(bv);
+               break;
            }
            the_locking_inset = 0;
            return DISPATCHED;
@@ -697,150 +588,254 @@ UpdatableInset::RESULT InsetText::LocalDispatch(BufferView * bv,
     }
     HideInsetCursor(bv);
     switch (action) {
-        // Normal chars
-      case -1:
-          par->InsertChar(actpos,arg[0]);
-         par->SetFont(actpos,real_current_font);
-         computeTextRows(bv->getPainter());
-         bv->updateInset(this, true);
-          ++actpos;
-         selection_start = selection_end = actpos;
-          resetPos(bv);
-          break;
+       // Normal chars
+    case -1:
+       bv->text->SetUndo(Undo::INSERT, 
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+       cutSelection();
+       cursor = selection_start_cursor;
+       par->InsertChar(cursor.pos,arg[0]);
+       SetCharFont(cursor.pos,current_font);
+       ++cursor.pos;
+       selection_start_cursor = selection_end_cursor = cursor;
+       UpdateLocal(bv, true);
+       break;
         // --- Cursor Movements ---------------------------------------------
-      case LFUN_RIGHTSEL:
-          moveRight(bv, false);
-         selection_end = actpos;
-         bv->updateInset(this, false);
-         break;
-      case LFUN_RIGHT:
-          result= DISPATCH_RESULT(moveRight(bv));
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_LEFTSEL:
-          moveLeft(bv, false);
-         selection_end = actpos;
-         bv->updateInset(this, false);
-         break;
-      case LFUN_LEFT:
-          result= DISPATCH_RESULT(moveLeft(bv));
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_DOWNSEL:
-          moveDown(bv, false);
-         selection_end = actpos;
-         bv->updateInset(this, false);
-         break;
-      case LFUN_DOWN:
-          result= DISPATCH_RESULT(moveDown(bv));
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_UPSEL:
-          moveUp(bv, false);
-         selection_end = actpos;
-         bv->updateInset(this, false);
-         break;
-      case LFUN_UP:
-          result= DISPATCH_RESULT(moveUp(bv));
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_BACKSPACE:
-          if (!actpos || par->IsNewline(actpos-1)) {
-             if (hasSelection()) {
-                 selection_start = selection_end = actpos;
-                 bv->updateInset(this, false);
-             }
-              break;
-         }
-          moveLeft(bv);
-      case LFUN_DELETE:
-          if (Delete()) { // we need update
-             selection_start = selection_end = actpos;
-             computeTextRows(bv->getPainter());
-             bv->updateInset(this, true);
-          } else if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         }
-          break;
-      case LFUN_HOME:
-          for(; actpos > rows[actrow].pos; --actpos)
-              cx -= SingleWidth(bv->getPainter(), par, actpos);
-         cx -= SingleWidth(bv->getPainter(), par, actpos);
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_END:
-          for(; actpos < rows[actrow + 1].pos; ++actpos)
-              cx += SingleWidth(bv->getPainter(), par, actpos);
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          break;
-      case LFUN_MATH_MODE:   // Open or create a math inset
-          InsertInset(bv, new InsetFormula);
-         if (hasSelection()) {
-             selection_start = selection_end = actpos;
-             bv->updateInset(this, false);
-         } else {
-             selection_start = selection_end = actpos;
-         }
-          return DISPATCHED;
-      default:
-          result = UNDISPATCHED;
-          break;
+    case LFUN_RIGHTSEL:
+       bv->text->FinishUndo();
+       moveRight(bv, false);
+       selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
+       break;
+    case LFUN_RIGHT:
+       bv->text->FinishUndo();
+       result = moveRight(bv);
+       if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       } else {
+           selection_start_cursor = selection_end_cursor = cursor;
+       }
+       break;
+    case LFUN_LEFTSEL:
+       bv->text->FinishUndo();
+       moveLeft(bv, false);
+       selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
+       break;
+    case LFUN_LEFT:
+       bv->text->FinishUndo();
+       result= moveLeft(bv);
+       if (hasSelection()) {
+               selection_start_cursor = selection_end_cursor = cursor;
+               UpdateLocal(bv, false);
+       } else {
+               selection_start_cursor = selection_end_cursor = cursor;
+       }
+       break;
+    case LFUN_DOWNSEL:
+       bv->text->FinishUndo();
+       moveDown(bv);
+       selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
+       break;
+    case LFUN_DOWN:
+       bv->text->FinishUndo();
+       result = moveDown(bv);
+       if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       } else {
+           selection_start_cursor = selection_end_cursor = cursor;
+       }
+       break;
+    case LFUN_UPSEL:
+       bv->text->FinishUndo();
+       moveUp(bv);
+       selection_end_cursor = cursor;
+       UpdateLocal(bv, false);
+       break;
+    case LFUN_UP:
+       bv->text->FinishUndo();
+       result = moveUp(bv);
+       if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       } else {
+           selection_start_cursor = selection_end_cursor = cursor;
+       }
+       break;
+    case LFUN_BACKSPACE:
+       if (!cursor.pos) {
+           if (hasSelection()) {
+               selection_start_cursor = selection_end_cursor = cursor;
+               UpdateLocal(bv, false);
+           }
+           break;
+       }
+       moveLeft(bv);
+    case LFUN_DELETE:
+    {
+       bv->text->SetUndo(Undo::DELETE, 
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+       bool ret = true;
+       if (hasSelection()) {
+           LyXParagraph::size_type i = selection_start_cursor.pos;
+           for (; i < selection_end_cursor.pos; ++i) {
+               par->Erase(selection_start_cursor.pos);
+           }
+       } else
+           ret = Delete();
+       if (ret) { // we need update
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, true);
+       } else if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       }
+    }
+    resetPos(bv->painter());
+    break;
+    case LFUN_CUT:
+       bv->text->SetUndo(Undo::DELETE, 
+         bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+         bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+
+       if (cutSelection()) {
+           // we need update
+           cursor = selection_end_cursor = selection_start_cursor;
+           UpdateLocal(bv, true);
+       } else if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       }
+       resetPos(bv->painter());
+       break;
+    case LFUN_COPY:
+       bv->text->FinishUndo();
+       if (copySelection()) {
+           // we need update
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, true);
+       } else if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       }
+       break;
+    case LFUN_PASTE:
+    {
+       bv->text->SetUndo(Undo::INSERT, 
+         bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+         bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+       if (pasteSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, true);
+       }
+    }
+    resetPos(bv->painter());
+    break;
+    case LFUN_HOME:
+       bv->text->FinishUndo();
+       for(; cursor.pos > rows[actrow].pos; --cursor.pos)
+           cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
+       cursor.x -= SingleWidth(bv->painter(), par, cursor.pos);
+       if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       } else {
+           selection_start_cursor = selection_end_cursor = cursor;
+       }
+       resetPos(bv->painter());
+       break;
+    case LFUN_END:
+    {
+       bv->text->FinishUndo();
+       int checkpos = (int)rows[actrow + 1].pos;
+       if ((actrow + 2) < (int)rows.size())
+           --checkpos;
+       for(; cursor.pos < checkpos; ++cursor.pos)
+           cursor.x += SingleWidth(bv->painter(), par, cursor.pos);
+       if (hasSelection()) {
+           selection_start_cursor = selection_end_cursor = cursor;
+           UpdateLocal(bv, false);
+       } else {
+           selection_start_cursor = selection_end_cursor = cursor;
+       }
+    }
+    resetPos(bv->painter());
+    break;
+    case LFUN_MATH_MODE:
+       InsertInset(bv, new InsetFormula);
+       return DISPATCHED;
+    case LFUN_INSET_ERT:
+       InsertInset(bv, new InsetERT(buffer));
+       return DISPATCHED;
+    case LFUN_BREAKPARAGRAPH:
+    case LFUN_BREAKLINE:
+       if (!autoBreakRows)
+           return DISPATCHED;
+       bv->text->SetUndo(Undo::INSERT, 
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+           bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+       par->InsertChar(cursor.pos,LyXParagraph::META_NEWLINE);
+       SetCharFont(cursor.pos,current_font);
+       UpdateLocal(bv, true);
+       ++cursor.pos;
+       selection_start_cursor = selection_end_cursor = cursor;
+       resetPos(bv->painter());
+       break;
+    case LFUN_LAYOUT:
+    {
+       // Derive layout number from given argument (string)
+       // and current buffer's textclass (number). */    
+       LyXTextClassList::ClassList::size_type tclass =
+           buffer->params.textclass;
+       std::pair <bool, LyXTextClass::size_type> layout = 
+           textclasslist.NumberOfLayout(tclass, arg);
+
+       // If the entry is obsolete, use the new one instead.
+       if (layout.first) {
+           string obs = textclasslist.Style(tclass,layout.second).
+               obsoleted_by();
+           if (!obs.empty()) 
+               layout = textclasslist.NumberOfLayout(tclass, obs);
+       }
+
+       // see if we found the layout number:
+       if (!layout.first) {
+           string msg = string(N_("Layout ")) + arg + N_(" not known");
+
+           bv->owner()->getMiniBuffer()->Set(msg);
+           break;
+       }
+
+       if (current_layout != layout.second) {
+           bv->text->SetLayout(cursor, selection_start_cursor,
+                               selection_end_cursor, layout.second);
+           bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
+           UpdateLocal(bv, true);
+       }
+    }
+    break;
+    default:
+       result = UNDISPATCHED;
+       break;
     }
     if (result != FINISHED) {
-       if (!the_locking_inset)
-           ShowInsetCursor(bv);
+       ShowInsetCursor(bv);
     } else
         bv->unlockInset(this);
     return result;
 }
 
 
-int InsetText::Latex(ostream &os, signed char fragile) const
-{
-    string fstr;
-
-    int i = Latex(fstr, fragile);
-    os << fstr;
-    return i;
-}
-
-
-int InsetText::Latex(string & file, signed char /* fragile */) const
+int InsetText::Latex(ostream & os, bool /*fragile*/, bool /*fp*/) const
 {
     TexRow texrow;
-
-    return par->SimpleTeXOnePar(file, texrow);
+    buffer->latexParagraphs(os, par, 0, texrow);
+    return texrow.rows();
 }
 
 
@@ -853,13 +848,13 @@ void InsetText::Validate(LaTeXFeatures & features) const
 // Returns the width of a character at a certain spot
 int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
 {
-    LyXFont font = GetFont(par, pos);
+    LyXFont font = GetDrawFont(par, pos);
     char c = par->GetChar(pos);
 
     if (IsPrintable(c)) {
-        return font.width(c);
+        return lyxfont::width(c, font);
     } else if (c == LyXParagraph::META_INSET) {
-        Inset const * tmpinset=par->GetInset(pos);
+        Inset const * tmpinset = par->GetInset(pos);
         if (tmpinset)
             return tmpinset->width(pain, font);
         else
@@ -868,7 +863,7 @@ int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
         c = ' ';
     else if (IsNewlineChar(c))
         c = 'n';
-    return font.width(c);
+    return lyxfont::width(c, font);
 }
 
 
@@ -876,7 +871,7 @@ int InsetText::SingleWidth(Painter & pain, LyXParagraph * par, int pos) const
 void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
                             int & asc, int & desc) const
 {
-    LyXFont font = GetFont(par, pos);
+    LyXFont font = GetDrawFont(par, pos);
     char c = par->GetChar(pos);
 
     asc = desc = 0;
@@ -887,8 +882,8 @@ void InsetText::SingleHeight(Painter & pain, LyXParagraph * par,int pos,
            desc = tmpinset->descent(pain, font);
         }
     } else {
-        asc = font.maxAscent();
-        desc = font.maxDescent();
+        asc = lyxfont::maxAscent(font);
+        desc = lyxfont::maxDescent(font);
     }
     return;
 }
@@ -905,7 +900,7 @@ LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
 {
     char par_depth = par->GetDepth();
 
-    LyXLayout layout =
+    LyXLayout const & layout =
            textclasslist.Style(buffer->params.textclass, par->GetLayout());
 
     // We specialize the 95% common case:
@@ -967,6 +962,13 @@ LyXFont InsetText::GetFont(LyXParagraph * par, int pos) const
 }
 
 
+// the font for drawing may be different from the real font
+LyXFont InsetText::GetDrawFont(LyXParagraph * par, int pos) const
+{
+    return GetFont(par, pos);
+}
+
+
 int InsetText::BeginningOfMainBody(LyXParagraph * par) const
 {
     if (textclasslist.Style(buffer->params.textclass,
@@ -979,8 +981,8 @@ int InsetText::BeginningOfMainBody(LyXParagraph * par) const
 
 void InsetText::GetCursorPos(int & x, int & y) const
 {
-    x = cx;
-    y = cy;
+    x = cursor.x;
+    y = cursor.y;
 }
 
 
@@ -989,9 +991,7 @@ int InsetText::InsetInInsetY()
     if (!the_locking_inset)
        return 0;
 
-    int
-       y = inset_y;
-    return (y + the_locking_inset->InsetInInsetY());
+    return (inset_y + the_locking_inset->InsetInInsetY());
 }
 
 
@@ -1002,28 +1002,32 @@ void InsetText::ToggleInsetCursor(BufferView * bv)
         return;
     }
 
-    LyXFont font = GetFont(par, actpos);
+    LyXFont font = GetDrawFont(par, cursor.pos);
 
-    int asc = font.maxAscent();
-    int desc = font.maxDescent();
+    int asc = lyxfont::maxAscent(font);
+    int desc = lyxfont::maxDescent(font);
   
     if (cursor_visible)
         bv->hideLockedInsetCursor();
     else
-        bv->showLockedInsetCursor(cx, cy, asc, desc);
+        bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
     cursor_visible = !cursor_visible;
 }
 
 
 void InsetText::ShowInsetCursor(BufferView * bv)
 {
+    if (the_locking_inset) {
+       the_locking_inset->ShowInsetCursor(bv);
+       return;
+    }
     if (!cursor_visible) {
-       LyXFont font = GetFont(par, actpos);
+       LyXFont font = GetDrawFont(par, cursor.pos);
        
-       int asc = font.maxAscent();
-       int desc = font.maxDescent();
-       bv->fitLockedInsetCursor(cx, cy, asc, desc);
-       bv->showLockedInsetCursor(cx, cy, asc, desc);
+       int asc = lyxfont::maxAscent(font);
+       int desc = lyxfont::maxDescent(font);
+       bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
+       bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
        cursor_visible = true;
     }
 }
@@ -1031,161 +1035,162 @@ void InsetText::ShowInsetCursor(BufferView * bv)
 
 void InsetText::HideInsetCursor(BufferView * bv)
 {
-    if (cursor_visible)
-        ToggleInsetCursor(bv);
+    if (cursor_visible) {
+        bv->hideLockedInsetCursor();
+       cursor_visible = false;
+    }
+    if (the_locking_inset)
+       the_locking_inset->HideInsetCursor(bv);
 }
 
 
-void InsetText::setPos(BufferView * bv, int x, int y, bool activate_inset)
+void InsetText::setPos(Painter & pain, int x, int y) const
 {
-    int ox = x,
-       oy = y;
+    x -= drawTextXOffset;
+    y -= drawTextYOffset;
     // search right X-pos x==0 -> top_x
-    actpos = actrow = 0;
-    cy = top_baseline;
-    y += cy;
+    cursor.pos = actrow = 0;
+    cursor.y = top_baseline;
+    y += cursor.y;
     for(unsigned int i = 1;
-       ((cy + rows[i - 1].desc) < y) && (i < rows.size() - 1); ++i) {
-       cy = rows[i].baseline;
-       actpos = rows[i].pos;
+       (long(cursor.y + rows[i - 1].desc) < y)
+               && (i < rows.size() - 1); ++i) {
+       cursor.y = rows[i].baseline;
+       cursor.pos = rows[i].pos;
        actrow = i;
     }
-    cy -= top_baseline;
-    cx = top_x;
+    cursor.y -= top_baseline;
+    cursor.x = top_x;
     x += top_x;
 
     int swh;
-    int sw = swh = SingleWidth(bv->getPainter(), par,actpos);
-    if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
+    int sw = swh = SingleWidth(pain, par,cursor.pos);
+    if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
        swh /= 2;
-    while ((actpos < (rows[actrow + 1].pos - 1)) && ((cx + swh) < x)) {
-       cx += sw;
-       ++actpos;
-       sw = swh = SingleWidth(bv->getPainter(), par,actpos);
-       if (par->GetChar(actpos)!=LyXParagraph::META_INSET)
+    int checkpos = rows[actrow + 1].pos;
+    if ((actrow+2) < (int)rows.size())
+       --checkpos;
+    while ((cursor.pos < checkpos) && ((cursor.x + swh) < x)) {
+       cursor.x += sw;
+       ++cursor.pos;
+       sw = swh = SingleWidth(pain, par,cursor.pos);
+       if (par->GetChar(cursor.pos)!=LyXParagraph::META_INSET)
            swh /= 2;
     }
-    if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
-        the_locking_inset =
-               static_cast<UpdatableInset*>(par->GetInset(actpos));
-       inset_x = cx - top_x;
-       inset_y = cy;
-       inset_pos = actpos;
-        the_locking_inset->Edit(bv, ox - inset_x, oy - inset_y, 0);
-    }
 }
 
 
-bool InsetText::moveRight(BufferView * bv, bool activate_inset)
+void InsetText::resetPos(Painter & pain) const
 {
-    if (actpos >= par->Last())
-       return false;
-    if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
-       the_locking_inset =
-               static_cast<UpdatableInset*>(par->GetInset(actpos));
-       inset_x = cx - top_x;
-       inset_y = cy;
-       inset_pos = actpos;
-       the_locking_inset->Edit(bv, 0, 0, 0);
-    } else {
-       ++actpos;
-       resetPos(bv);
+    cursor.par = par;
+
+    if (!rows.size())
+       return;
+
+    int old_pos = cursor.pos;
+
+    cursor.y = top_baseline;
+    actrow = 0;
+    for(unsigned int i = 0;
+       (i < (rows.size()-1)) && (rows[i].pos <= cursor.pos);
+       ++i) {
+       cursor.y = rows[i].baseline;
+       actrow = i;
+    }
+    cursor.y -= top_baseline;
+    setPos(pain, 0, cursor.y);
+    cursor.x = top_x;
+    while(cursor.pos < old_pos) {
+       cursor.x += SingleWidth(pain, par,cursor.pos);
+       ++cursor.pos;
     }
-    return true;
 }
 
 
-bool InsetText::moveLeft(BufferView * bv, bool activate_inset)
+UpdatableInset::RESULT
+InsetText::moveRight(BufferView * bv, bool activate_inset)
 {
-    if (actpos <= 0)
-       return false;
-    --actpos;
-    if (activate_inset && par->GetChar(actpos)==LyXParagraph::META_INSET) {
-       the_locking_inset =
-               static_cast<UpdatableInset*>(par->GetInset(actpos));
-       resetPos(bv);
-       inset_x = cx - top_x;
-       inset_y = cy;
-       inset_pos = actpos;
-       the_locking_inset->Edit(bv, the_locking_inset->
-                               width(bv->getPainter(), GetFont(par,actpos)),
-                               0, 0);
-    } else {
-       resetPos(bv);
+    if (cursor.pos >= par->Last())
+       return FINISHED;
+    if (activate_inset && checkAndActivateInset(bv)) {
+       return DISPATCHED;
     }
-    return true;
+    ++cursor.pos;
+    resetPos(bv->painter());
+    real_current_font = current_font = GetFont(par, cursor.pos);
+    return DISPATCHED_NOUPDATE;
 }
 
 
-bool InsetText::moveUp(BufferView * bv, bool activate_inset)
+UpdatableInset::RESULT
+InsetText::moveLeft(BufferView * bv, bool activate_inset)
 {
-    if (!actrow)
-       return false;
-    cy = rows[actrow - 1].baseline - top_baseline;
-    setPos(bv, cx - top_x, cy, activate_inset);
-    return true;
+    if (cursor.pos <= 0)
+       return FINISHED;
+    --cursor.pos;
+    resetPos(bv->painter());
+    if (activate_inset)
+       if (checkAndActivateInset(bv, -1, -1))
+           return DISPATCHED;
+    return DISPATCHED_NOUPDATE;
 }
 
 
-bool InsetText::moveDown(BufferView * bv, bool activate_inset)
+UpdatableInset::RESULT
+InsetText::moveUp(BufferView * bv)
 {
-    if (actrow >= int(rows.size() - 2))
-       return false;
-    cy = rows[actrow + 1].baseline - top_baseline;
-    setPos(bv, cx - top_x, cy, activate_inset);
-    return true;
+    if (!actrow)
+       return FINISHED;
+    cursor.y = rows[actrow - 1].baseline - top_baseline;
+    if (cursor.x_fix < 0)
+       cursor.x_fix = cursor.x;
+    setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
+    return DISPATCHED_NOUPDATE;
 }
 
 
-void InsetText::resetPos(BufferView * bv)
+UpdatableInset::RESULT
+InsetText::moveDown(BufferView * bv)
 {
-    int old_pos = actpos;
-
-    cy = top_baseline;
-    actrow = 0;
-    for(int i = 0; rows[i].pos <= actpos; ++i) {
-       cy = rows[i].baseline;
-       actrow = i;
-    }
-    cy -= top_baseline;
-    setPos(bv, 0, cy, false);
-    cx = top_x;
-    while(actpos < old_pos) {
-       cx += SingleWidth(bv->getPainter(), par,actpos);
-       ++actpos;
-    }
+    if (actrow >= int(rows.size() - 2))
+       return FINISHED;
+    cursor.y = rows[actrow + 1].baseline - top_baseline;
+    if (cursor.x_fix < 0)
+       cursor.x_fix = cursor.x;
+    setPos(bv->painter(), cursor.x_fix-top_x+drawTextXOffset, cursor.y);
+    return DISPATCHED_NOUPDATE;
 }
 
 
 bool InsetText::Delete()
 {
-    /* some insets are undeletable here */
-    if (par->GetChar(actpos)==LyXParagraph::META_INSET) {
-        /* force complete redo when erasing display insets */ 
-        /* this is a cruel mathod but save..... Matthias */ 
-        if (par->GetInset(actpos)->Deletable() &&
-            par->GetInset(actpos)->display()) {
-            par->Erase(actpos);
-            return true;
-        }
-        return false;
+    if ((par->GetChar(cursor.pos)==LyXParagraph::META_INSET) &&
+       !par->GetInset(cursor.pos)->Deletable()) {
+       return false;
     }
-    par->Erase(actpos);
+    par->Erase(cursor.pos);
     return true;
 }
 
 
 bool InsetText::InsertInset(BufferView * bv, Inset * inset)
 {
-    par->InsertChar(actpos, LyXParagraph::META_INSET);
-    par->InsertInset(actpos, inset);
-    computeTextRows(bv->getPainter());
-    bv->updateInset(this, true);
-    the_locking_inset = static_cast<UpdatableInset*>(inset);
-    inset_x = cx - top_x;
-    inset_y = cy;
-    inset_pos = actpos;
-    inset->Edit(bv, 0, 0, 0);
+    bv->text->SetUndo(Undo::INSERT, 
+             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->previous,
+             bv->text->cursor.par->ParFromPos(bv->text->cursor.pos)->next);
+    if (inset->Editable() == Inset::IS_EDITABLE) {
+       UpdatableInset *i = (UpdatableInset *)inset;
+       i->setOwner((UpdatableInset *)this);
+    }
+    par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
+    par->InsertInset(cursor.pos, inset);
+    if (hasSelection()) {
+       selection_start_cursor = selection_end_cursor = cursor;
+    } else {
+       selection_start_cursor = selection_end_cursor = cursor;
+    }
+    UpdateLocal(bv, true);
+    static_cast<UpdatableInset*>(inset)->Edit(bv, 0, 0, 0);
     return true;
 }
 
@@ -1202,13 +1207,14 @@ void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
     if (!hasSelection()) {
        // Determine basis font
        LyXFont layoutfont;
-       if (actpos < BeginningOfMainBody(par))
+       if (cursor.pos < BeginningOfMainBody(par))
            layoutfont = GetFont(par, -2);
        else
            layoutfont = GetFont(par, -1);
        
        // Update current font
-       real_current_font.update(font, toggleall);
+       real_current_font.update(font, bv->buffer()->params.language_info,
+                                toggleall);
        
        // Reduce to implicit settings
        current_font = real_current_font;
@@ -1219,22 +1225,21 @@ void InsetText::SetFont(BufferView * bv, LyXFont const & font, bool toggleall)
     }
     
     int s_start, s_end;
-    if (selection_start > selection_end) {
-       s_start = selection_end;
-       s_end = selection_start;
+    if (selection_start_cursor.pos > selection_end_cursor.pos) {
+       s_start = selection_end_cursor.pos;
+       s_end = selection_start_cursor.pos;
     } else {
-       s_start = selection_start;
-       s_end = selection_end;
+       s_start = selection_start_cursor.pos;
+       s_end = selection_end_cursor.pos;
     }
     LyXFont newfont;
     while(s_start < s_end) {
        newfont = GetFont(par,s_start);
-       newfont.update(font, toggleall);
+       newfont.update(font, bv->buffer()->params.language_info, toggleall);
        SetCharFont(s_start, newfont);
        ++s_start;
     }
-    computeTextRows(bv->getPainter());
-    bv->updateInset(this, true);
+    UpdateLocal(bv, true);
 }
 
 
@@ -1247,7 +1252,7 @@ void InsetText::SetCharFont(int pos, LyXFont const & f)
        if (par->GetInset(pos))
            font = par->GetInset(pos)->ConvertFont(font);
     }
-    LyXLayout layout =
+    LyXLayout const & layout =
            textclasslist.Style(buffer->params.textclass,par->GetLayout());
 
     // Get concrete layout font to reduce against
@@ -1269,7 +1274,7 @@ void InsetText::SetCharFont(int pos, LyXFont const & f)
 }
 
 
-void InsetText::computeTextRows(Painter & pain) const
+void InsetText::computeTextRows(Painter & pain, float x) const
 {
     int p,
        nwp = 0,
@@ -1283,7 +1288,7 @@ void InsetText::computeTextRows(Painter & pain) const
     row_struct row;
 
     if (rows.size())
-       rows.erase(rows.begin(),rows.end());
+           rows.clear();
     int width = wordAscent = wordDescent = 0;
     insetWidth = maxAscent = maxDescent = 0;
     row.asc      = 0;
@@ -1291,14 +1296,12 @@ void InsetText::computeTextRows(Painter & pain) const
     row.pos      = 0;
     row.baseline = 0;
     rows.push_back(row);
-    if (maxWidth < 0) {
-       for(p=0; p < par->Last(); ++p) {
+    if (!autoBreakRows) {
+       for(p = 0; p < par->Last(); ++p) {
            insetWidth += SingleWidth(pain, par, p);
            SingleHeight(pain, par, p, asc, desc);
-           if (asc > maxAscent)
-               maxAscent = asc;
-           if (desc > maxDescent)
-               maxDescent = desc;
+           maxAscent = max(maxAscent, asc);
+           maxDescent = max(maxDescent, desc);
        }
        rows[0].asc = maxAscent;
        rows[0].desc = maxDescent;
@@ -1307,86 +1310,106 @@ void InsetText::computeTextRows(Painter & pain) const
        rows.push_back(row);
        return;
     }
-    bool is_first_word_in_row = true;
 
-    int cw,
-       lastWordWidth=0;
+    bool is_first_word_in_row = true;
+    int cw, lastWordWidth = 0;
+    int maxWidth = getMaxTextWidth(pain, this, x);
 
     for(p = 0; p < par->Last(); ++p) {
        cw = SingleWidth(pain, par, p);
        width += cw;
        lastWordWidth += cw;
        SingleHeight(pain, par, p, asc, desc);
-       if (asc > wordAscent)
-           wordAscent = asc;
-       if (desc > wordDescent)
-           wordDescent = desc;
-       Inset const * inset = 0;
-       if (((p + 1) < par->Last()) &&
-           (par->GetChar(p+1)==LyXParagraph::META_INSET))
-           inset = par->GetInset(p+1);
-       if (inset && inset->display()) {
+       wordAscent = max(wordAscent, asc);
+       wordDescent = max(wordDescent, desc);
+       if (par->IsNewline(p)) {
            if (!is_first_word_in_row && (width >= maxWidth)) {
                // we have to split also the row above
-               rows[rows.size()-1].asc = oasc;
-               rows[rows.size()-1].desc = odesc;
+               rows.back().asc = oasc;
+               rows.back().desc = odesc;
                row.pos = nwp;
                rows.push_back(row);
                oasc = wordAscent;
                odesc = wordDescent;
-               if (insetWidth < owidth)
-                   insetWidth = owidth;
+               insetWidth = max(insetWidth, owidth);
                width = lastWordWidth;
                lastWordWidth = 0;
-           } else {
-               if (oasc < wordAscent)
-                   oasc = wordAscent;
-               if (odesc < wordDescent)
-                   odesc = wordDescent;
            }
-           rows[rows.size() - 1].asc = oasc;
-           rows[rows.size() - 1].desc = odesc;
+           rows.back().asc = wordAscent;
+           rows.back().desc = wordDescent;
            row.pos = ++p;
            rows.push_back(row);
-           SingleHeight(pain, par, p, asc, desc);
-           rows[rows.size() - 1].asc = asc;
-           rows[rows.size() - 1].desc = desc;
-           row.pos = nwp = p + 1;
-           rows.push_back(row);
-           oasc = odesc = width = lastWordWidth = 0;
+           SingleHeight(pain, par, p, oasc, odesc);
+           insetWidth = max(insetWidth, owidth);
+           width = 0;
            is_first_word_in_row = true;
-           wordAscent = wordDescent = 0;
+           wordAscent = wordDescent = lastWordWidth = 0;
+           nwp = p;
            continue;
+       }
+       Inset * inset = 0;
+       if (((p + 1) < par->Last()) &&
+           (par->GetChar(p + 1)==LyXParagraph::META_INSET))
+           inset = par->GetInset(p + 1);
+       if (inset) {
+               inset->setOwner(const_cast<InsetText*>(this)); // is this safe?
+           if (inset->display()) {
+               if (!is_first_word_in_row && (width >= maxWidth)) {
+                   // we have to split also the row above
+                   rows.back().asc = oasc;
+                   rows.back().desc = odesc;
+                   row.pos = nwp;
+                   rows.push_back(row);
+                   oasc = wordAscent;
+                   odesc = wordDescent;
+                   insetWidth = max(insetWidth, owidth);
+                   width = lastWordWidth;
+                   lastWordWidth = 0;
+               } else {
+                   oasc = max(oasc, wordAscent);
+                   odesc = max(odesc, wordDescent);
+               }
+               rows.back().asc = oasc;
+               rows.back().desc = odesc;
+               row.pos = ++p;
+               rows.push_back(row);
+               SingleHeight(pain, par, p, asc, desc);
+               rows.back().asc = asc;
+               rows.back().desc = desc;
+               row.pos = nwp = p + 1;
+               rows.push_back(row);
+               oasc = odesc = width = lastWordWidth = 0;
+               is_first_word_in_row = true;
+               wordAscent = wordDescent = 0;
+               continue;
+           }
        } else if (par->IsSeparator(p)) {
            if (width >= maxWidth) {
                if (is_first_word_in_row) {
-                   rows[rows.size()-1].asc = wordAscent;
-                   rows[rows.size()-1].desc = wordDescent;
-                   row.pos = p+1;
+                   rows.back().asc = wordAscent;
+                   rows.back().desc = wordDescent;
+                   row.pos = p + 1;
                    rows.push_back(row);
                    oasc = odesc = width = 0;
                } else {
-                   rows[rows.size()-1].asc = oasc;
-                   rows[rows.size()-1].desc = odesc;
+                   rows.back().asc = oasc;
+                   rows.back().desc = odesc;
                    row.pos = nwp;
                    rows.push_back(row);
                    oasc = wordAscent;
                    odesc = wordDescent;
-                   if (insetWidth < owidth)
-                       insetWidth = owidth;
+                   insetWidth = max(insetWidth, owidth);
                    width = lastWordWidth;
                }
                wordAscent = wordDescent = lastWordWidth = 0;
-               nwp = p+1;
+               nwp = p + 1;
                continue;
            }
            owidth = width;
-           if (oasc < wordAscent)
-               oasc = wordAscent;
-           if (odesc < wordDescent)
-               odesc = wordDescent;
+           oasc = max(oasc, wordAscent);
+           odesc = max(odesc, wordDescent);
            wordAscent = wordDescent = lastWordWidth = 0;
-           nwp = p+1;
+           nwp = p + 1;
            is_first_word_in_row = false;
        }
     }
@@ -1394,54 +1417,148 @@ void InsetText::computeTextRows(Painter & pain) const
     if (p) {
        if (width >= maxWidth) {
            // assign upper row
-           rows[rows.size()-1].asc = oasc;
-           rows[rows.size()-1].desc = odesc;
+           rows.back().asc = oasc;
+           rows.back().desc = odesc;
            // assign and allocate lower row
            row.pos = nwp;
            rows.push_back(row);
-           rows[rows.size()-1].asc = wordAscent;
-           rows[rows.size()-1].desc = wordDescent;
-           if (insetWidth < owidth)
-               insetWidth = owidth;
-           width -= owidth;
-           if (insetWidth < width)
-               insetWidth = width;
+           rows.back().asc = wordAscent;
+           rows.back().desc = wordDescent;
+           width -= lastWordWidth;
        } else {
            // assign last row data
-           if (oasc < wordAscent)
-               oasc = wordAscent;
-           if (odesc < wordDescent)
-               odesc = wordDescent;
-           rows[rows.size()-1].asc = oasc;
-           rows[rows.size()-1].desc = odesc;
+           rows.back().asc = max(oasc, wordAscent);
+           rows.back().desc = max(odesc, wordDescent);
        }
     }
+    insetWidth = max(insetWidth, width);
     // alocate a dummy row for the endpos
     row.pos = par->Last();
     rows.push_back(row);
     // calculate maxAscent/Descent
     maxAscent = rows[0].asc;
     maxDescent = rows[0].desc;
-    for (unsigned int i=1; i<rows.size()-1; ++i) {
+    for (RowList::size_type i = 1; i < rows.size() - 1; ++i) {
        maxDescent += rows[i].asc + rows[i].desc + interline_space;
     }
-#if 0
-    if (the_locking_inset) {
-       computeBaselines(top_baseline);
-       actpos = inset_pos;
-       resetPos(bv);
-       inset_x = cx-top_x;
-       inset_y = cy;
-    }
-#endif
 }
 
 
 void InsetText::computeBaselines(int baseline) const
 {
     rows[0].baseline = baseline;
-    for (unsigned int i=1; i<rows.size()-1; i++) {
-       rows[i].baseline = rows[i-1].baseline + rows[i-1].desc + 
+    for (unsigned int i = 1; i < rows.size() - 1; i++) {
+       rows[i].baseline = rows[i - 1].baseline + rows[i - 1].desc + 
            rows[i].asc + interline_space;
     }
 }
+
+
+void InsetText::UpdateLocal(BufferView * bv, bool flag)
+{
+    if (flag) {
+       computeTextRows(bv->painter(), xpos);
+       computeBaselines(top_baseline);
+    }
+    bv->updateInset(this, flag);
+    if (flag)
+       resetPos(bv->painter());
+    bv->owner()->getToolbar()->combox->select(cursor.par->GetLayout()+1);
+}
+
+
+bool InsetText::cutSelection()
+{
+    if (!hasSelection())
+       return false;
+
+    CutAndPaste cap;
+
+    LyXParagraph * endpar = par;
+    int start, end;
+    if (selection_start_cursor.pos > selection_end_cursor.pos) {
+           start = selection_end_cursor.pos;
+           end = selection_start_cursor.pos;
+    } else {
+           start = selection_start_cursor.pos;
+           end = selection_end_cursor.pos;
+    }
+
+    return cap.cutSelection(par, &endpar, start, end,buffer->params.textclass);
+}
+
+
+bool InsetText::copySelection()
+{
+    if (!hasSelection())
+       return false;
+
+    CutAndPaste cap;
+
+    int start, end;
+    if (selection_start_cursor.pos > selection_end_cursor.pos) {
+           start = selection_end_cursor.pos;
+           end = selection_start_cursor.pos;
+    } else {
+           start = selection_start_cursor.pos;
+           end = selection_end_cursor.pos;
+    }
+    return cap.copySelection(par, par, start, end, buffer->params.textclass);
+}
+
+
+bool InsetText::pasteSelection()
+{
+    CutAndPaste cap;
+
+    if (cap.nrOfParagraphs() > 1) {
+       WriteAlert(_("Impossible operation"),
+                  _("Cannot include more than one paragraph!"),
+                  _("Sorry."));
+       return false;
+    }
+    LyXParagraph *endpar;
+    LyXParagraph *actpar = par;
+
+    return cap.pasteSelection(&actpar, &endpar, cursor.pos,
+                             buffer->params.textclass);
+}
+
+
+bool InsetText::checkAndActivateInset(BufferView * bv, int x, int y,
+                                     int button)
+{
+    if (par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
+       UpdatableInset * inset =
+           static_cast<UpdatableInset*>(par->GetInset(cursor.pos));
+       LyXFont font = GetFont(par, cursor.pos);
+       if (x < 0)
+           x = inset->width(bv->painter(), font);
+       if (y < 0)
+           y = inset->descent(bv->painter(), font);
+       inset_x = cursor.x - top_x + drawTextXOffset;
+       inset_y = cursor.y + drawTextYOffset;
+       inset->Edit(bv, x-inset_x, y-inset_y, button);
+       if (!the_locking_inset)
+           return false;
+       UpdateLocal(bv, true);
+       return true;
+    }
+    return false;
+}
+
+
+int InsetText::getMaxTextWidth(Painter & pain, UpdatableInset const * inset,
+                              int x) const
+{
+    return getMaxWidth(pain, inset) - x;
+}
+
+void InsetText::SetParagraphData(LyXParagraph *p)
+{
+    if (par)
+       delete par;
+    par = p->Clone();
+    par->SetInsetOwner(this);
+    init_inset = true;
+}