]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/math_cursor.C
OK I'll try guii1 again ...
[lyx.git] / src / mathed / math_cursor.C
index 64fbade29c2e29a4582de29254cd677ff9103b18..36834e7612654ec9826a7aa0dd2ef95018f9a7f7 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <config.h>
+#include <lyxrc.h>
 
 #ifdef __GNUG__
 #pragma implementation
@@ -25,7 +26,7 @@
 #include "support/LAssert.h"
 #include "debug.h"
 #include "LColor.h"
-#include "Painter.h"
+#include "frontends/Painter.h"
 #include "math_cursor.h"
 #include "formulabase.h"
 #include "math_arrayinset.h"
@@ -38,6 +39,7 @@
 #include "math_hullinset.h"
 #include "math_iterator.h"
 #include "math_macroarg.h"
+#include "math_macrotemplate.h"
 #include "math_mathmlstream.h"
 #include "math_parser.h"
 #include "math_replace.h"
@@ -55,7 +57,8 @@ using std::endl;
 using std::min;
 using std::max;
 using std::swap;
-using std::isalnum;
+using std::vector;
+using std::ostringstream;
 
 namespace {
 
@@ -76,11 +79,11 @@ struct Selection
                c1 = p->col(i1.idx_);
                c2 = p->col(i2.idx_);
                if (c1 > c2)
-                       std::swap(c1, c2);
+                       swap(c1, c2);
                r1 = p->row(i1.idx_);
                r2 = p->row(i2.idx_);
                if (r1 > r2)
-                       std::swap(r1, r2);
+                       swap(r1, r2);
        }
 
        void grab(MathCursor const & cursor)
@@ -128,18 +131,28 @@ struct Selection
        {
                if (data_.nargs() == 1) {
                        // single cell/part of cell
-                       cursor.insert(data_.cell(0));
+                       cursor.paste(data_.cell(0));
                } else {
                        // mulitple cells
-                       idx_type idx;
+                       idx_type idx; // index of upper left cell
                        MathGridInset * p = cursor.enclosingGrid(idx);
                        col_type const numcols = min(data_.ncols(), p->ncols() - p->col(idx));
                        row_type const numrows = min(data_.nrows(), p->nrows() - p->row(idx));
-                       for (row_type row = 0; row < numrows; ++row)
+                       for (row_type row = 0; row < numrows; ++row) {
                                for (col_type col = 0; col < numcols; ++col) {
                                        idx_type i = p->index(row + p->row(idx), col + p->col(idx));
                                        p->cell(i).push_back(data_.cell(data_.index(row, col)));
                                }
+                               // append the left over horizontal cells to the last column
+                               idx_type i = p->index(row + p->row(idx), p->ncols() - 1);
+                               for (col_type col = numcols; col < data_.ncols(); ++col)
+                                       p->cell(i).push_back(data_.cell(data_.index(row, col)));
+                       }
+                       // append the left over vertical cells to the last _cell_
+                       idx_type i = p->nargs() - 1;
+                       for (row_type row = numrows; row < data_.nrows(); ++row)
+                               for (col_type col = 0; col < data_.ncols(); ++col)
+                                       p->cell(i).push_back(data_.cell(data_.index(row, col)));
                }
        }
 
@@ -200,14 +213,9 @@ void MathCursor::pushRight(MathAtom & t)
 
 bool MathCursor::popLeft()
 {
-       //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " left\n";
+       //cerr << "Leaving atom to the left\n";
        if (Cursor_.size() <= 1)
                return false;
-       if (par()->asScriptInset()) {
-               par()->asScriptInset()->removeEmptyScripts();
-               if (par()->asScriptInset()->empty())
-                       plainErase();
-       }
        Cursor_.pop_back();
        return true;
 }
@@ -218,11 +226,6 @@ bool MathCursor::popRight()
        //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n";
        if (Cursor_.size() <= 1)
                return false;
-       if (par()->asScriptInset()) {
-               par()->asScriptInset()->removeEmptyScripts();
-               if (par()->asScriptInset()->empty())
-                       plainErase();
-       }
        Cursor_.pop_back();
        posRight();
        return true;
@@ -247,12 +250,6 @@ bool MathCursor::popRight()
 #endif
 
 
-UpdatableInset * MathCursor::asHyperActiveInset() const
-{
-       return par()->asHyperActiveInset();
-}
-
-
 bool MathCursor::isInside(MathInset const * p) const
 {
        for (unsigned i = 0; i < Cursor_.size(); ++i)
@@ -264,9 +261,6 @@ bool MathCursor::isInside(MathInset const * p) const
 
 bool MathCursor::openable(MathAtom const & t, bool sel) const
 {
-       if (t->isHyperActive())
-               return true;
-
        if (!t->isActive())
                return false;
 
@@ -314,9 +308,6 @@ bool MathCursor::left(bool sel)
        lastcode_ = LM_TC_MIN;
 
        if (hasPrevAtom() && openable(prevAtom(), sel)) {
-               if (prevAtom()->isHyperActive()) {
-                       lyxerr << "entering hyperactive inset\n";
-               }
                pushRight(prevAtom());
                return true;
        }
@@ -337,12 +328,6 @@ bool MathCursor::right(bool sel)
        lastcode_ = LM_TC_MIN;
 
        if (hasNextAtom() && openable(nextAtom(), sel)) {
-               if (nextAtom()->isHyperActive()) {
-                       lyxerr << "entering hyperactive inset\n";
-                       int x, y;
-                       getPos(x, y);
-                       nextAtom()->edit(formula()->view(), x, y, 0);
-               }
                pushLeft(nextAtom());
                return true;
        }
@@ -366,7 +351,7 @@ void MathCursor::last()
 
 
 bool positionable(MathCursor::cursor_type const & cursor,
-                  MathCursor::cursor_type const & anchor)
+                 MathCursor::cursor_type const & anchor)
 {
        // avoid deeper nested insets when selecting
        if (cursor.size() > anchor.size())
@@ -428,6 +413,20 @@ void MathCursor::plainErase()
 }
 
 
+void MathCursor::markInsert()
+{
+       //lyxerr << "inserting mark\n";
+       array().insert(pos(), MathAtom(new MathCharInset(0, lastcode_)));
+}
+
+
+void MathCursor::markErase()
+{
+       //lyxerr << "deleting mark\n";
+       array().erase(pos());
+}
+
+
 void MathCursor::plainInsert(MathAtom const & t)
 {
        array().insert(pos(), t);
@@ -438,6 +437,7 @@ void MathCursor::plainInsert(MathAtom const & t)
 void MathCursor::insert(char c, MathTextCodes t)
 {
        //lyxerr << "inserting '" << c << "'\n";
+       selClearOrDel();        
        plainInsert(MathAtom(new MathCharInset(c, t)));
 }
 
@@ -456,7 +456,7 @@ void MathCursor::insert(MathAtom const & t)
                if (t->nargs())
                        selCut();
                else
-                       selDel();
+                       selClearOrDel();
        }
 
        plainInsert(t);
@@ -531,18 +531,16 @@ void MathCursor::erase()
                return;
        }
 
-       // delete empty cells if necessary
-       if (array().empty()) {
-               bool popit;
-               bool removeit;
-               par()->idxDelete(idx(), popit, removeit);
-               if (popit && popLeft() && removeit)
-                       plainErase();
-               return;
-       }
+       // delete empty cells if possible
+       if (array().empty())
+               if (par()->idxDelete(idx()))
+                       return;
 
-       if (pos() == size())
+       // old behaviour when in last position of cell
+       if (pos() == size()) {
+               par()->idxGlue(idx());
                return;
+       }
 
        MathScriptInset * p = nextAtom()->asScriptInset();
        if (p) {
@@ -571,8 +569,8 @@ void MathCursor::delLine()
                par()->asGridInset()->delRow(hullRow());
        }
 
-       if (idx() > par()->nargs())
-               idx() = par()->nargs();
+       if (idx() >= par()->nargs())
+               idx() = par()->nargs() - 1;
 
        if (pos() > size())
                pos() = size();
@@ -620,13 +618,14 @@ bool MathCursor::toggleLimits()
 
 void MathCursor::macroModeClose()
 {
+       MathInset::difference_type const t = macroNamePos();
+       if (t == -1)
+               return;
        string s = macroName();
-       if (s.size()) {
-               size_type old = pos();
-               pos() -= s.size();
-               array().erase(pos(), old);
+       array().erase(t, pos());
+       pos() = t;
+       if (s != "\\")
                interpret(s);
-       }
 }
 
 
@@ -645,7 +644,7 @@ string MathCursor::macroName() const
 {
        string s;
        MathInset::difference_type i = macroNamePos();
-       for ( ; i >= 0 && i < int(pos()); ++i)
+       for (; i >= 0 && i < int(pos()); ++i)
                s += array().at(i)->getChar();
        return s;
 }
@@ -656,7 +655,7 @@ void MathCursor::selCopy()
        dump("selCopy");
        if (selection_) {
                theSelection.grab(*this);
-               selClear();
+               //selClear();
        }
 }
 
@@ -689,9 +688,10 @@ void MathCursor::selDel()
 void MathCursor::selPaste()
 {
        dump("selPaste");
+       selClearOrDel();
        theSelection.paste(*this);
        //theSelection.grab(*this);
-       //selClear();
+       selClear();
 }
 
 
@@ -723,6 +723,15 @@ void MathCursor::selClear()
 }
 
 
+void MathCursor::selClearOrDel()
+{
+       if (lyxrc.auto_region_delete)
+               selDel();
+       else
+               selClear();
+}
+
+
 void MathCursor::selGet(MathArray & ar)
 {
        dump("selGet");
@@ -752,7 +761,7 @@ void MathCursor::drawSelection(Painter & pain) const
                int y2 = c.yo() + c.descent();
                pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
        } else {
-               std::vector<MathInset::idx_type> indices
+               vector<MathInset::idx_type> indices
                        = i1.par_->idxBetween(i1.idx_, i2.idx_);
                for (unsigned i = 0; i < indices.size(); ++i) {
                        MathXArray & c = i1.xcell(indices[i]);
@@ -818,6 +827,9 @@ void MathCursor::getPos(int & x, int & y)
 #warning This should probably take cellXOffset and cellYOffset into account
 #endif
        x = xarray().xo() + xarray().pos2x(pos());
+       // move cursor visually into empty cells ("blue rectangles");
+       if (array().empty())
+               x += 2;
        y = xarray().yo();
 }
 
@@ -883,12 +895,20 @@ MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const
                if (p) {
                        idx = Cursor_[i].idx_;
                        return p;
+                       lyxerr << "found grid and idx: " << idx << "\n";
                }
        }
        return 0;
 }
 
 
+void MathCursor::popToEnclosingGrid()
+{
+       while (Cursor_.size() && !Cursor_.back().par_->asGridInset())
+               Cursor_.pop_back();
+}
+
+
 void MathCursor::pullArg(bool goright)
 {
        dump("pullarg");
@@ -912,38 +932,66 @@ void MathCursor::pullArg(bool goright)
                array().insert(pos(), a);
                if (goright)
                        pos() += a.size();
+       } else {
+               formula()->mutateToText();
        }
 }
 
 
+void MathCursor::touch()
+{
+       cursor_type::const_iterator it = Cursor_.begin();
+       cursor_type::const_iterator et = Cursor_.end();
+       for ( ; it != et; ++it)
+               it->xcell().touch();
+}
+
+
 void MathCursor::normalize()
 {
+#if 0
        // rebreak
        {
                MathIterator it = ibegin(formula()->par().nucleus());
                MathIterator et = iend(formula()->par().nucleus());
-               for ( ; it != et; ++it)
+               for (; it != et; ++it)
                        if (it.par()->asBoxInset())
                                it.par()->asBoxInset()->rebreak();
        }
+#endif
 
-       if (idx() >= par()->nargs()) {
+       if (idx() >= par()->nargs()) {
                lyxerr << "this should not really happen - 1: "
                       << idx() << " " << par()->nargs() << "\n";
                dump("error 2");
        }
-       idx() = min(idx(), par()->nargs() - 1);
+       idx() = min(idx(), par()->nargs() - 1);
 
        if (pos() > size()) {
                lyxerr << "this should not really happen - 2: "
                        << pos() << " " << size() <<  " in idx: " << idx()
                        << " in atom: '";
-               WriteStream wi(lyxerr, false);
+               WriteStream wi(lyxerr, false, true);
                par()->write(wi);
                lyxerr << "\n";
                dump("error 4");
        }
        pos() = min(pos(), size());
+
+       // remove empty scripts if possible
+       if (1) {
+               for (pos_type i = 0; i < size(); ++i) {
+                       MathScriptInset * p = array().at(i)->asScriptInset();
+                       if (p) {
+                               p->removeEmptyScripts();
+                               //if (p->empty())
+                               //      array().erase(i);
+                       }
+               }
+       }
+
+       // fix again position
+       pos() = min(pos(), size());
 }
 
 
@@ -1143,33 +1191,75 @@ MathCursorPos const & MathCursor::cursor() const
 
 bool MathCursor::goUpDown(bool up)
 {
+       // Be warned: The 'logic' implemented in this function is highly fragile.
+       // A distance of one pixel or a '<' vs '<=' _really_ matters.
+       // So fiddle around with it only if you know what you are doing!
        int xlow, xhigh, ylow, yhigh;
 
   int xo, yo;
        getPos(xo, yo);
 
-       // try current cell first
-       xarray().boundingBox(xlow, xhigh, ylow, yhigh);
-       if (up)
-               yhigh = yo - 4;
-       else
-               ylow = yo + 4;
-       if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh))
-               return true;
+       // try neigbouring script insets
+       // try left
+       if (hasPrevAtom()) {
+               MathScriptInset * p = prevAtom()->asScriptInset();
+               if (p && p->has(up)) {
+                       --pos();
+                       push(nextAtom());
+                       idx() = up; // the superscript has index 1
+                       pos() = size();
+                       ///lyxerr << "updown: handled by scriptinset to the left\n";
+                       return true;
+               }
+       }
+
+       // try right
+       if (hasNextAtom()) {
+               MathScriptInset * p = nextAtom()->asScriptInset();
+               if (p && p->has(up)) {
+                       push(nextAtom());
+                       idx() = up;
+                       pos() = 0;
+                       ///lyxerr << "updown: handled by scriptinset to the right\n";
+                       return true;
+               }
+       }
+
+       // try current cell
+       //xarray().boundingBox(xlow, xhigh, ylow, yhigh);
+       //if (up)
+       //      yhigh = yo - 4;
+       //else
+       //      ylow = yo + 4;
+       //if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) {
+       //      lyxerr << "updown: handled by brute find in the same cell\n";
+       //      return true;
+       //}
 
        // try to find an inset that knows better then we
        while (1) {
-               // we found a cell that think something "below" us.
-               if (up) {
-                       if (par()->idxUp(idx()))
-                               break;
-               } else {
-                       if (par()->idxDown(idx()))
-                               break;
+               ///lyxerr << "updown: We are in " << *par() << " idx: " << idx() << '\n';
+               // ask inset first
+               if (par()->idxUpDown(idx(), up)) {
+                       // we found a cell that thinks it has something "below" us.
+                       ///lyxerr << "updown: found inset that handles UpDown\n";
+                       xarray().boundingBox(xlow, xhigh, ylow, yhigh);
+                       // project (xo,yo) onto proper box
+                       ///lyxerr << "\n   xo: " << xo << " yo: " << yo
+                       ///       << "\n   xlow: " << xlow << " ylow: " << ylow
+                       ///       << "\n   xhigh: " << xhigh << " yhigh: " << yhigh;
+                       xo = min(max(xo, xlow), xhigh);
+                       yo = min(max(yo, ylow), yhigh);
+                       ///lyxerr << "\n   xo2: " << xo << " yo2: " << yo << "\n";
+                       bruteFind(xo, yo, xlow, xhigh, ylow, yhigh);
+                       ///lyxerr << "updown: handled by final brute find\n";
+                       return true;
                }
 
+               // leave inset
                if (!popLeft()) {
                        // no such inset found, just take something "above"
+                       ///lyxerr << "updown: handled by strange case\n";
                        return
                                bruteFind(xo, yo,
                                        formula()->xlow(),
@@ -1178,14 +1268,18 @@ bool MathCursor::goUpDown(bool up)
                                        up ? yo - 4 : formula()->yhigh()
                                );
                }
+
+               // any improvement so far?
+               int xnew, ynew;
+               getPos(xnew, ynew);
+               if (up ? ynew < yo : ynew > yo)
+                       return true;
        }
-       xarray().boundingBox(xlow, xhigh, ylow, yhigh);
-       bruteFind(xo, yo, xlow, xhigh, ylow, yhigh);
-       return true;
 }
 
 
-bool MathCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh)
+bool MathCursor::bruteFind
+       (int x, int y, int xlow, int xhigh, int ylow, int yhigh)
 {
        cursor_type best_cursor;
        double best_dist = 1e10;
@@ -1195,13 +1289,14 @@ bool MathCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhig
        while (1) {
                // avoid invalid nesting when selecting
                if (!selection_ || positionable(it.cursor(), Anchor_)) {
-                       int xo = it.position().xpos();
-                       int yo = it.position().ypos();
-                       if (xlow - 2 <= xo && xo <= xhigh + 2 &&
-                                       ylow - 2 <= yo && yo <= yhigh + 2)
-                       {
+                       MathCursorPos const & top = it.position();
+                       int xo = top.xpos();
+                       int yo = top.ypos();
+                       if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
                                double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
-                               if (d < best_dist) {
+                               // '<=' in order to take the last possible position
+                               // this is important for clicking behind \sum in e.g. '\sum_i a'
+                               if (d <= best_dist) {
                                        best_dist   = d;
                                        best_cursor = it.cursor();
                                }
@@ -1237,9 +1332,6 @@ bool MathCursor::interpret(string const & s)
        if (s.empty())
                return true;
 
-       if (s.size() == 1)
-               return interpret(s[0]);
-
        //lyxerr << "char: '" << s[0] << "'  int: " << int(s[0]) << endl;
        //owner_->getIntl()->getTrans().TranslateAndInsert(s[0], lt);
        //lyxerr << "trans: '" << s[0] << "'  int: " << int(s[0]) << endl;
@@ -1248,7 +1340,7 @@ bool MathCursor::interpret(string const & s)
                unsigned int n = 1;
                istringstream is(s.substr(5).c_str());
                is >> n;
-               n = std::max(1u, n);
+               n = max(1u, n);
                niceInsert(MathAtom(new MathCasesInset(n)));
                return true;
        }
@@ -1260,10 +1352,10 @@ bool MathCursor::interpret(string const & s)
                string h_align;
                istringstream is(s.substr(6).c_str());
                is >> m >> n >> v_align >> h_align;
-               m = std::max(1u, m);
-               n = std::max(1u, n);
+               m = max(1u, m);
+               n = max(1u, n);
                v_align += 'c';
-               niceInsert(MathAtom(new MathArrayInset(m, n, v_align[0], h_align)));
+               niceInsert(MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
                return true;
        }
 
@@ -1279,9 +1371,11 @@ bool MathCursor::interpret(string const & s)
                return true;
        }
 
-       if (s == "\\over" || s == "\\choose" || s == "\\atop") {
+       string name = s.substr(1);
+
+       if (name == "over" || name == "choose" || name == "atop") {
                MathArray ar = array();
-               MathAtom t(createMathInset(s.substr(1)));
+               MathAtom t(createMathInset(name));
                t->asNestInset()->cell(0).swap(array());
                pos() = 0;
                niceInsert(t);
@@ -1290,27 +1384,36 @@ bool MathCursor::interpret(string const & s)
                return true;
        }
 
-       latexkeys const * l = in_word_set(s.substr(1));
+       latexkeys const * l = in_word_set(name);
        if (l && (l->token == LM_TK_FONT || l->token == LM_TK_OLDFONT)) {
                lastcode_ = static_cast<MathTextCodes>(l->id);
                return true;
        }
 
        // prevent entering of recursive macros
-       if (formula()->lyxCode() == Inset::MATHMACRO_CODE 
-               && formula()->getInsetName() == s.substr(1))
+       if (formula()->lyxCode() == Inset::MATHMACRO_CODE
+               && formula()->getInsetName() == name)
        {
                lyxerr << "can't enter recursive macro\n";
                return true;
        }
 
-       niceInsert(createMathInset(s.substr(1)));
+       niceInsert(createMathInset(name));
        return true;
 }
 
 
 bool MathCursor::script(bool up)
 {
+       // Hack to get \\^ and \\_ working
+       if (inMacroMode() && macroName() == "\\") {
+               if (up)
+                       interpret("\\mathcircumflex");
+               else
+                       interpret('_');
+               return true;
+       }
+
        macroModeClose();
        selCut();
        if (hasPrevAtom() && prevAtom()->asScriptInset()) {
@@ -1338,11 +1441,14 @@ bool MathCursor::script(bool up)
 
 bool MathCursor::interpret(char c)
 {
+       //lyxerr << "interpret 2: '" << c << "'\n";
        if (inMacroArgMode()) {
                --pos();
                plainErase();
-               if ('1' <= c && c <= '9')
-                       insert(MathAtom(new MathMacroArgument(c - '0')));
+               int n = c - '0';
+               MathMacroTemplate * p = formula()->par()->asMacroTemplate();
+               if (p && 1 <= n && n <= p->numargs())
+                       insert(MathAtom(new MathMacroArgument(c - '0', lastcode_)));
                else {
                        insert(MathAtom(new MathSpecialCharInset('#')));
                        interpret(c); // try again
@@ -1353,39 +1459,45 @@ bool MathCursor::interpret(char c)
        // handle macroMode
        if (inMacroMode()) {
                string name = macroName();
+               //lyxerr << "interpret name: '" << name << "'\n";
 
-               if (name == "\\" && c == '\\') {
-                       backspace();
-                       interpret("\\backslash");
+               // extend macro name if possible
+               if (isalpha(c)) {
+                       insert(c, LM_TC_TEX);
                        return true;
                }
 
-               if (isalpha(c)) {
-                       insert(c, LM_TC_TEX);
+               // leave macro mode if explicitly requested
+               if (c == ' ') {
+                       macroModeClose();
                        return true;
                }
 
+               // handle 'special char' macros
                if (name == "\\") {
-                       insert(c, LM_TC_TEX);
-                       macroModeClose();
+                       // remove the '\\'
+                       backspace();
+                       if (c == '\\')
+                               interpret("\\backslash");
+                       else
+                               interpret(string("\\") + c);
                        return true;
                }
 
+               // leave macro mode and try again
                macroModeClose();
-
-               if (c == '\\')
-                       insert(c, LM_TC_TEX);
-
+               interpret(c);
                return true;
        }
 
-       if (selection_) {
+       // just clear selection on pressing the space par
+       if (selection_ && c == ' ') {
                selClear();
-               if (c == ' ')
-                       return true;
-               // fall through in the other cases
+               return true;
        }
 
+       selClearOrDel();
+
        if (lastcode_ == LM_TC_TEXTRM || par()->asBoxInset()) {
                // suppress direct insertion of two spaces in a row
                // the still allows typing  '<space>a<space>' and deleting the 'a', but
@@ -1413,7 +1525,7 @@ bool MathCursor::interpret(char c)
        }
 
 /*
-       if (strchr("{}", c)) {
+       if (c == '{' || c == '}', c)) {
                insert(c, LM_TC_TEX);
                return true;
        }
@@ -1428,7 +1540,7 @@ bool MathCursor::interpret(char c)
                return true;
        }
 
-       if (strchr("$%", c)) {
+       if (c == '$' || c == '%') {
                insert(MathAtom(new MathSpecialCharInset(c)));
                lastcode_ = LM_TC_VAR;
                return true;
@@ -1503,8 +1615,8 @@ void MathCursor::setSelection(cursor_type const & where, size_type n)
 
 string MathCursor::info() const
 {
-       std::ostringstream os;
+       ostringstream os;
        if (pos() > 0)
                prevAtom()->infoize(os);
-       return os.str();
+       return os.str().c_str(); // .c_str() needed for lyxstring
 }