]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathNest.C
delete unneeded BufferView.h declaration.
[lyx.git] / src / mathed / InsetMathNest.C
1 /**
2  * \file InsetMathNest.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetMathNest.h"
14
15 #include "InsetMathArray.h"
16 #include "InsetMathBig.h"
17 #include "InsetMathBox.h"
18 #include "InsetMathBrace.h"
19 #include "InsetMathColor.h"
20 #include "InsetMathComment.h"
21 #include "MathData.h"
22 #include "InsetMathDelim.h"
23 #include "MathFactory.h"
24 #include "InsetMathHull.h"
25 #include "MathMLStream.h"
26 #include "MathMacroArgument.h"
27 //#include "InsetMathMBox.h"
28 #include "MathParser.h"
29 #include "InsetMathScript.h"
30 #include "InsetMathSpace.h"
31 #include "InsetMathSymbol.h"
32 #include "MathSupport.h"
33 #include "InsetMathUnknown.h"
34 #include "InsetMathRef.h"
35
36 #include "BufferView.h"
37 #include "CutAndPaste.h"
38 #include "FuncStatus.h"
39 #include "LColor.h"
40 #include "bufferview_funcs.h"
41 #include "coordcache.h"
42 #include "cursor.h"
43 #include "debug.h"
44 #include "dispatchresult.h"
45 #include "funcrequest.h"
46 #include "gettext.h"
47 #include "outputparams.h"
48 #include "undo.h"
49
50 #include "support/lstrings.h"
51
52 #include "frontends/Application.h"
53 #include "frontends/Painter.h"
54 #include "frontends/Selection.h"
55 #include "frontends/nullpainter.h"
56
57 #include <sstream>
58
59 using lyx::cap::copySelection;
60 using lyx::cap::grabAndEraseSelection;
61 using lyx::cap::cutSelection;
62 using lyx::cap::replaceSelection;
63 using lyx::cap::selClearOrDel;
64
65 using lyx::frontend::Clipboard;
66
67 using std::endl;
68 using std::string;
69 using std::istringstream;
70
71
72 InsetMathNest::InsetMathNest(idx_type nargs)
73         : cells_(nargs), lock_(false)
74 {}
75
76
77 InsetMath::idx_type InsetMathNest::nargs() const
78 {
79         return cells_.size();
80 }
81
82
83 MathArray & InsetMathNest::cell(idx_type i)
84 {
85         return cells_[i];
86 }
87
88
89 MathArray const & InsetMathNest::cell(idx_type i) const
90 {
91         return cells_[i];
92 }
93
94
95 void InsetMathNest::cursorPos(CursorSlice const & sl, bool /*boundary*/,
96         int & x, int & y) const
97 {
98 // FIXME: This is a hack. Ideally, the coord cache should not store
99 // absolute positions, but relative ones. This would mean to call
100 // setXY() not in MathArray::draw(), but in the parent insets' draw()
101 // with the correctly adjusted x,y values. But this means that we'd have
102 // to touch all (math)inset's draw() methods. Right now, we'll store
103 // absolute value, and make them here relative, only to make them
104 // absolute again when actually drawing the cursor. What a mess.
105         BOOST_ASSERT(ptr_cmp(&sl.inset(), this));
106         MathArray const & ar = sl.cell();
107         if (!theCoords.getArrays().has(&ar)) {
108                 // this can (semi-)legally happen if we just created this cell
109                 // and it never has been drawn before. So don't ASSERT.
110                 //lyxerr << "no cached data for array " << &ar << endl;
111                 x = 0;
112                 y = 0;
113                 return;
114         }
115         Point const pt = theCoords.getArrays().xy(&ar);
116         if (!theCoords.getInsets().has(this)) {
117                 // same as above
118                 //lyxerr << "no cached data for inset " << this << endl;
119                 x = 0;
120                 y = 0;
121                 return;
122         }
123         Point const pt2 = theCoords.getInsets().xy(this);
124         //lyxerr << "retrieving position cache for MathArray "
125         //      << pt.x_ << ' ' << pt.y_ << std::endl;
126         x = pt.x_ - pt2.x_ + ar.pos2x(sl.pos());
127         y = pt.y_ - pt2.y_;
128 //      lyxerr << "pt.y_ : " << pt.y_ << " pt2_.y_ : " << pt2.y_
129 //              << " asc: " << ascent() << "  des: " << descent()
130 //              << " ar.asc: " << ar.ascent() << " ar.des: " << ar.descent() << endl;
131         // move cursor visually into empty cells ("blue rectangles");
132         if (ar.empty())
133                 x += 2;
134 }
135
136
137 void InsetMathNest::metrics(MetricsInfo const & mi) const
138 {
139         MetricsInfo m = mi;
140         for (idx_type i = 0, n = nargs(); i != n; ++i)
141                 cell(i).metrics(m);
142 }
143
144
145 bool InsetMathNest::idxNext(LCursor & cur) const
146 {
147         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
148         if (cur.idx() == cur.lastidx())
149                 return false;
150         ++cur.idx();
151         cur.pos() = 0;
152         return true;
153 }
154
155
156 bool InsetMathNest::idxRight(LCursor & cur) const
157 {
158         return idxNext(cur);
159 }
160
161
162 bool InsetMathNest::idxPrev(LCursor & cur) const
163 {
164         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
165         if (cur.idx() == 0)
166                 return false;
167         --cur.idx();
168         cur.pos() = cur.lastpos();
169         return true;
170 }
171
172
173 bool InsetMathNest::idxLeft(LCursor & cur) const
174 {
175         return idxPrev(cur);
176 }
177
178
179 bool InsetMathNest::idxFirst(LCursor & cur) const
180 {
181         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
182         if (nargs() == 0)
183                 return false;
184         cur.idx() = 0;
185         cur.pos() = 0;
186         return true;
187 }
188
189
190 bool InsetMathNest::idxLast(LCursor & cur) const
191 {
192         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
193         if (nargs() == 0)
194                 return false;
195         cur.idx() = cur.lastidx();
196         cur.pos() = cur.lastpos();
197         return true;
198 }
199
200
201 void InsetMathNest::dump() const
202 {
203         WriteStream os(lyxerr);
204         os << "---------------------------------------------\n";
205         write(os);
206         os << "\n";
207         for (idx_type i = 0, n = nargs(); i != n; ++i)
208                 os << cell(i) << "\n";
209         os << "---------------------------------------------\n";
210 }
211
212
213 void InsetMathNest::draw(PainterInfo & pi, int x, int y) const
214 {
215 #if 0
216         if (lock_)
217                 pi.pain.fillRectangle(x, y - ascent(), width(), height(),
218                                         LColor::mathlockbg);
219 #endif
220         setPosCache(pi, x, y);
221 }
222
223
224 void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const
225 {
226         // this should use the x/y values given, not the cached values
227         LCursor & cur = pi.base.bv->cursor();
228         if (!cur.selection())
229                 return;
230         if (!ptr_cmp(&cur.inset(), this))
231                 return;
232
233         // FIXME: hack to get position cache warm
234         static lyx::frontend::NullPainter nop;
235         PainterInfo pinop(pi);
236         pinop.pain = nop;
237         draw(pinop, x, y);
238
239         CursorSlice s1 = cur.selBegin();
240         CursorSlice s2 = cur.selEnd();
241         //lyxerr << "InsetMathNest::drawing selection: "
242         //      << " s1: " << s1 << " s2: " << s2 << endl;
243         if (s1.idx() == s2.idx()) {
244                 MathArray const & c = cell(s1.idx());
245                 int x1 = c.xo() + c.pos2x(s1.pos());
246                 int y1 = c.yo() - c.ascent();
247                 int x2 = c.xo() + c.pos2x(s2.pos());
248                 int y2 = c.yo() + c.descent();
249                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
250         //lyxerr << "InsetMathNest::drawing selection 3: "
251         //      << " x1: " << x1 << " x2: " << x2
252         //      << " y1: " << y1 << " y2: " << y2 << endl;
253         } else {
254                 for (idx_type i = 0; i < nargs(); ++i) {
255                         if (idxBetween(i, s1.idx(), s2.idx())) {
256                                 MathArray const & c = cell(i);
257                                 int x1 = c.xo();
258                                 int y1 = c.yo() - c.ascent();
259                                 int x2 = c.xo() + c.width();
260                                 int y2 = c.yo() + c.descent();
261                                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
262                         }
263                 }
264         }
265 }
266
267
268 void InsetMathNest::validate(LaTeXFeatures & features) const
269 {
270         for (idx_type i = 0; i < nargs(); ++i)
271                 cell(i).validate(features);
272 }
273
274
275 void InsetMathNest::replace(ReplaceData & rep)
276 {
277         for (idx_type i = 0; i < nargs(); ++i)
278                 cell(i).replace(rep);
279 }
280
281
282 bool InsetMathNest::contains(MathArray const & ar) const
283 {
284         for (idx_type i = 0; i < nargs(); ++i)
285                 if (cell(i).contains(ar))
286                         return true;
287         return false;
288 }
289
290
291 bool InsetMathNest::lock() const
292 {
293         return lock_;
294 }
295
296
297 void InsetMathNest::lock(bool l)
298 {
299         lock_ = l;
300 }
301
302
303 bool InsetMathNest::isActive() const
304 {
305         return nargs() > 0;
306 }
307
308
309 MathArray InsetMathNest::glue() const
310 {
311         MathArray ar;
312         for (size_t i = 0; i < nargs(); ++i)
313                 ar.append(cell(i));
314         return ar;
315 }
316
317
318 void InsetMathNest::write(WriteStream & os) const
319 {
320         os << '\\' << name().c_str();
321         for (size_t i = 0; i < nargs(); ++i)
322                 os << '{' << cell(i) << '}';
323         if (nargs() == 0)
324                 os.pendingSpace(true);
325         if (lock_ && !os.latex()) {
326                 os << "\\lyxlock";
327                 os.pendingSpace(true);
328         }
329 }
330
331
332 void InsetMathNest::normalize(NormalStream & os) const
333 {
334         os << '[' << name().c_str();
335         for (size_t i = 0; i < nargs(); ++i)
336                 os << ' ' << cell(i);
337         os << ']';
338 }
339
340
341 int InsetMathNest::latex(Buffer const &, std::ostream & os,
342                         OutputParams const & runparams) const
343 {
344         WriteStream wi(os, runparams.moving_arg, true);
345         write(wi);
346         return wi.line();
347 }
348
349
350 bool InsetMathNest::notifyCursorLeaves(LCursor & /*cur*/)
351 {
352 #ifdef WITH_WARNINGS
353 #warning look here
354 #endif
355 #if 0
356         MathArray & ar = cur.cell();
357         // remove base-only "scripts"
358         for (pos_type i = 0; i + 1 < ar.size(); ++i) {
359                 InsetMathScript * p = operator[](i).nucleus()->asScriptInset();
360                 if (p && p->nargs() == 1) {
361                         MathArray ar = p->nuc();
362                         erase(i);
363                         insert(i, ar);
364                         cur.adjust(i, ar.size() - 1);
365                 }
366         }
367
368         // glue adjacent font insets of the same kind
369         for (pos_type i = 0; i + 1 < size(); ++i) {
370                 InsetMathFont * p = operator[](i).nucleus()->asFontInset();
371                 InsetMathFont const * q = operator[](i + 1)->asFontInset();
372                 if (p && q && p->name() == q->name()) {
373                         p->cell(0).append(q->cell(0));
374                         erase(i + 1);
375                         cur.adjust(i, -1);
376                 }
377         }
378 #endif
379         return false;
380 }
381
382
383 void InsetMathNest::handleFont
384         (LCursor & cur, string const & arg, string const & font)
385 {
386         // this whole function is a hack and won't work for incremental font
387         // changes...
388         recordUndo(cur, Undo::ATOMIC);
389
390         if (cur.inset().asInsetMath()->name() == font)
391                 cur.handleFont(font);
392         else {
393                 cur.handleNest(createInsetMath(font));
394                 cur.insert(arg);
395         }
396 }
397
398
399 void InsetMathNest::handleFont2(LCursor & cur, string const & arg)
400 {
401         recordUndo(cur, Undo::ATOMIC);
402         LyXFont font;
403         bool b;
404         bv_funcs::string2font(arg, font, b);
405         if (font.color() != LColor::inherit) {
406                 MathAtom at = MathAtom(new InsetMathColor(true, font.color()));
407                 cur.handleNest(at, 0);
408         }
409 }
410
411
412 void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
413 {
414         //lyxerr << "InsetMathNest: request: " << cmd << std::endl;
415         //CursorSlice sl = cur.current();
416
417         switch (cmd.action) {
418
419         case LFUN_PASTE: {
420                 recordUndo(cur);
421                 cur.message(_("Paste"));
422                 replaceSelection(cur);
423                 size_t n = 0;
424                 istringstream is(lyx::to_utf8(cmd.argument()));
425                 is >> n;
426                 string const selection = lyx::cap::getSelection(cur.buffer(), n);
427                 cur.niceInsert(selection);
428                 cur.clearSelection(); // bug 393
429                 cur.bv().switchKeyMap();
430                 finishUndo();
431                 break;
432         }
433
434         case LFUN_CUT:
435                 recordUndo(cur);
436                 cutSelection(cur, true, true);
437                 cur.message(_("Cut"));
438                 // Prevent stale position >= size crash
439                 // Probably not necessary anymore, see eraseSelection (gb 2005-10-09)
440                 cur.normalize();
441                 break;
442
443         case LFUN_COPY:
444                 copySelection(cur);
445                 // FIXME UNICODE
446                 cur.message(_("Copy"));
447                 break;
448
449         case LFUN_MOUSE_PRESS:
450                 lfunMousePress(cur, cmd);
451                 break;
452
453         case LFUN_MOUSE_MOTION:
454                 lfunMouseMotion(cur, cmd);
455                 break;
456
457         case LFUN_MOUSE_RELEASE:
458                 lfunMouseRelease(cur, cmd);
459                 break;
460
461         case LFUN_FINISHED_LEFT:
462                 cur.bv().cursor() = cur;
463                 break;
464
465         case LFUN_FINISHED_RIGHT:
466                 ++cur.pos();
467                 cur.bv().cursor() = cur;
468                 break;
469
470         case LFUN_FINISHED_UP:
471                 cur.bv().cursor() = cur;
472                 break;
473
474         case LFUN_FINISHED_DOWN:
475                 ++cur.pos();
476                 cur.bv().cursor() = cur;
477                 break;
478
479         case LFUN_CHAR_FORWARD_SELECT:
480         case LFUN_CHAR_FORWARD:
481                 cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT);
482                 cur.autocorrect() = false;
483                 cur.clearTargetX();
484                 cur.macroModeClose();
485                 if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
486                         cur.pushLeft(*cur.nextAtom().nucleus());
487                         cur.inset().idxFirst(cur);
488                 } else if (cur.posRight() || idxRight(cur)
489                         || cur.popRight() || cur.selection())
490                         ;
491                 else {
492                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
493                         cur.undispatched();
494                 }
495                 break;
496
497         case LFUN_CHAR_BACKWARD_SELECT:
498         case LFUN_CHAR_BACKWARD:
499                 cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT);
500                 cur.autocorrect() = false;
501                 cur.clearTargetX();
502                 cur.macroModeClose();
503                 if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
504                         cur.posLeft();
505                         cur.push(*cur.nextAtom().nucleus());
506                         cur.inset().idxLast(cur);
507                 } else if (cur.posLeft() || idxLeft(cur)
508                         || cur.popLeft() || cur.selection())
509                         ;
510                 else {
511                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
512                         cur.undispatched();
513                 }
514                 break;
515
516         case LFUN_UP_SELECT:
517         case LFUN_UP:
518                 // FIXME Tried to use clearTargetX and macroModeClose, crashed on cur.up()
519                 if (cur.inMacroMode()) {
520                         // Make Helge happy
521                         cur.macroModeClose();
522                         break;
523                 }
524                 cur.selHandle(cmd.action == LFUN_UP_SELECT);
525                 if (!cur.up()) {
526                         cmd = FuncRequest(LFUN_FINISHED_UP);
527                         cur.undispatched();
528                 }
529                 // fixes bug 1598. Please check!
530                 cur.normalize();
531                 break;
532
533         case LFUN_DOWN_SELECT:
534         case LFUN_DOWN:
535                 if (cur.inMacroMode()) {
536                         cur.macroModeClose();
537                         break;
538                 }
539                 cur.selHandle(cmd.action == LFUN_DOWN_SELECT);
540                 if (!cur.down()) {
541                         cmd = FuncRequest(LFUN_FINISHED_DOWN);
542                         cur.undispatched();
543                 }
544                 // fixes bug 1598. Please check!
545                 cur.normalize();
546                 break;
547
548         case LFUN_MOUSE_DOUBLE:
549         case LFUN_MOUSE_TRIPLE:
550         case LFUN_WORD_SELECT:
551                 cur.pos() = 0;
552                 cur.idx() = 0;
553                 cur.resetAnchor();
554                 cur.selection() = true;
555                 cur.pos() = cur.lastpos();
556                 cur.idx() = cur.lastidx();
557                 break;
558
559         case LFUN_PARAGRAPH_UP_SELECT:
560         case LFUN_PARAGRAPH_UP:
561         case LFUN_PARAGRAPH_DOWN_SELECT:
562         case LFUN_PARAGRAPH_DOWN:
563                 break;
564
565         case LFUN_LINE_BEGIN_SELECT:
566         case LFUN_LINE_BEGIN:
567         case LFUN_WORD_BACKWARD_SELECT:
568         case LFUN_WORD_BACKWARD:
569                 cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT ||
570                                 cmd.action == LFUN_LINE_BEGIN_SELECT);
571                 cur.macroModeClose();
572                 if (cur.pos() != 0) {
573                         cur.pos() = 0;
574                 } else if (cur.col() != 0) {
575                         cur.idx() -= cur.col();
576                         cur.pos() = 0;
577                 } else if (cur.idx() != 0) {
578                         cur.idx() = 0;
579                         cur.pos() = 0;
580                 } else {
581                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
582                         cur.undispatched();
583                 }
584                 break;
585
586         case LFUN_WORD_FORWARD_SELECT:
587         case LFUN_WORD_FORWARD:
588         case LFUN_LINE_END_SELECT:
589         case LFUN_LINE_END:
590                 cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT ||
591                                 cmd.action == LFUN_LINE_END_SELECT);
592                 cur.macroModeClose();
593                 cur.clearTargetX();
594                 if (cur.pos() != cur.lastpos()) {
595                         cur.pos() = cur.lastpos();
596                 } else if (ncols() && (cur.col() != cur.lastcol())) {
597                         cur.idx() = cur.idx() - cur.col() + cur.lastcol();
598                         cur.pos() = cur.lastpos();
599                 } else if (cur.idx() != cur.lastidx()) {
600                         cur.idx() = cur.lastidx();
601                         cur.pos() = cur.lastpos();
602                 } else {
603                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
604                         cur.undispatched();
605                 }
606                 break;
607
608         case LFUN_SCREEN_UP_SELECT:
609         case LFUN_SCREEN_UP:
610                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
611                 cur.undispatched();
612                 break;
613
614         case LFUN_SCREEN_DOWN_SELECT:
615         case LFUN_SCREEN_DOWN:
616                 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
617                 cur.undispatched();
618                 break;
619
620         case LFUN_CELL_FORWARD:
621                 cur.inset().idxNext(cur);
622                 break;
623
624         case LFUN_CELL_BACKWARD:
625                 cur.inset().idxPrev(cur);
626                 break;
627
628         case LFUN_WORD_DELETE_BACKWARD:
629         case LFUN_CHAR_DELETE_BACKWARD:
630                 if (cur.pos() == 0)
631                         // May affect external cell:
632                         recordUndoInset(cur, Undo::ATOMIC);
633                 else
634                         recordUndo(cur, Undo::ATOMIC);
635                 cur.backspace();
636                 break;
637
638         case LFUN_WORD_DELETE_FORWARD:
639         case LFUN_CHAR_DELETE_FORWARD:
640                 if (cur.pos() == cur.lastpos())
641                         // May affect external cell:
642                         recordUndoInset(cur, Undo::ATOMIC);
643                 else
644                         recordUndo(cur, Undo::ATOMIC);
645                 cur.erase();
646                 break;
647
648         case LFUN_ESCAPE:
649                 if (cur.selection())
650                         cur.clearSelection();
651                 else  {
652                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
653                         cur.undispatched();
654                 }
655                 break;
656
657         case LFUN_INSET_TOGGLE:
658                 recordUndo(cur);
659                 lock(!lock());
660                 cur.popRight();
661                 break;
662
663         case LFUN_SELF_INSERT:
664                 if (cmd.argument().size() != 1) {
665                         recordUndo(cur);
666                         string const arg = lyx::to_utf8(cmd.argument());
667                         if (!interpret(cur, arg))
668                                 cur.insert(arg);
669                         break;
670                 }
671                 // Don't record undo steps if we are in macro mode and
672                 // cmd.argument is the next character of the macro name.
673                 // Otherwise we'll get an invalid cursor if we undo after
674                 // the macro was finished and the macro is a known command,
675                 // e.g. sqrt. LCursor::macroModeClose replaces in this case
676                 // the InsetMathUnknown with name "frac" by an empty
677                 // InsetMathFrac -> a pos value > 0 is invalid.
678                 // A side effect is that an undo before the macro is finished
679                 // undoes the complete macro, not only the last character.
680                 if (!cur.inMacroMode())
681                         recordUndo(cur);
682
683                 // spacial handling of space. If we insert an inset
684                 // via macro mode, we want to put the cursor inside it
685                 // if relevant. Think typing "\frac<space>".
686                 if (cmd.argument()[0] == ' '
687                     && cur.inMacroMode() && cur.macroName() != "\\"
688                     && cur.macroModeClose()) {
689                         MathAtom const atom = cur.prevAtom();
690                         if (atom->asNestInset() && atom->nargs() > 0) {
691                                 cur.posLeft();
692                                 cur.pushLeft(*cur.nextInset());
693                         }
694                 // FIXME: Change to
695                 // } else if (!interpret(cur, cmd.argument()[0])) {
696                 // when interpret accepts UCS4 characters
697                 } else if (!interpret(cur, lyx::to_utf8(cmd.argument()))) {
698                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
699                         cur.undispatched();
700                 }
701                 break;
702
703         //case LFUN_SERVER_GET_XY:
704         //      sprintf(dispatch_buffer, "%d %d",);
705         //      break;
706
707         case LFUN_SERVER_SET_XY: {
708                 lyxerr << "LFUN_SERVER_SET_XY broken!" << endl;
709                 int x = 0;
710                 int y = 0;
711                 istringstream is(lyx::to_utf8(cmd.argument()));
712                 is >> x >> y;
713                 cur.setScreenPos(x, y);
714                 break;
715         }
716
717         // Special casing for superscript in case of LyX handling
718         // dead-keys:
719         case LFUN_ACCENT_CIRCUMFLEX:
720                 if (cmd.argument().empty()) {
721                         // do superscript if LyX handles
722                         // deadkeys
723                         recordUndo(cur, Undo::ATOMIC);
724                         script(cur, true, grabAndEraseSelection(cur));
725                 }
726                 break;
727
728         case LFUN_ACCENT_UMLAUT:
729         case LFUN_ACCENT_ACUTE:
730         case LFUN_ACCENT_GRAVE:
731         case LFUN_ACCENT_BREVE:
732         case LFUN_ACCENT_DOT:
733         case LFUN_ACCENT_MACRON:
734         case LFUN_ACCENT_CARON:
735         case LFUN_ACCENT_TILDE:
736         case LFUN_ACCENT_CEDILLA:
737         case LFUN_ACCENT_CIRCLE:
738         case LFUN_ACCENT_UNDERDOT:
739         case LFUN_ACCENT_TIE:
740         case LFUN_ACCENT_OGONEK:
741         case LFUN_ACCENT_HUNGARIAN_UMLAUT:
742                 break;
743
744         //  Math fonts
745         case LFUN_FONT_FREE_APPLY:
746         case LFUN_FONT_FREE_UPDATE:
747                 handleFont2(cur, lyx::to_utf8(cmd.argument()));
748                 break;
749
750         case LFUN_FONT_BOLD:
751                 if (currentMode() == TEXT_MODE)
752                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textbf");
753                 else
754                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathbf");
755                 break;
756         case LFUN_FONT_SANS:
757                 if (currentMode() == TEXT_MODE)
758                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textsf");
759                 else
760                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathsf");
761                 break;
762         case LFUN_FONT_EMPH:
763                 if (currentMode() == TEXT_MODE)
764                         handleFont(cur, lyx::to_utf8(cmd.argument()), "emph");
765                 else
766                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathcal");
767                 break;
768         case LFUN_FONT_ROMAN:
769                 if (currentMode() == TEXT_MODE)
770                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
771                 else
772                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathrm");
773                 break;
774         case LFUN_FONT_CODE:
775                 if (currentMode() == TEXT_MODE)
776                         handleFont(cur, lyx::to_utf8(cmd.argument()), "texttt");
777                 else
778                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathtt");
779                 break;
780         case LFUN_FONT_FRAK:
781                 handleFont(cur, lyx::to_utf8(cmd.argument()), "mathfrak");
782                 break;
783         case LFUN_FONT_ITAL:
784                 if (currentMode() == TEXT_MODE)
785                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textit");
786                 else
787                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathit");
788                 break;
789         case LFUN_FONT_NOUN:
790                 if (currentMode() == TEXT_MODE)
791                         // FIXME: should be "noun"
792                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textsc");
793                 else
794                         handleFont(cur, lyx::to_utf8(cmd.argument()), "mathbb");
795                 break;
796         //case LFUN_FONT_FREE_APPLY:
797                 handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
798                 break;
799         case LFUN_FONT_DEFAULT:
800                 handleFont(cur, lyx::to_utf8(cmd.argument()), "textnormal");
801                 break;
802
803         case LFUN_MATH_MODE: {
804 #if 1
805                 // ignore math-mode on when already in math mode
806                 if (currentMode() == InsetBase::MATH_MODE && cmd.argument() == "on")
807                         break;
808                 cur.macroModeClose();
809                 string const save_selection = grabAndEraseSelection(cur);
810                 selClearOrDel(cur);
811                 //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv())));
812                 cur.plainInsert(MathAtom(new InsetMathBox("mbox")));
813                 cur.posLeft();
814                 cur.pushLeft(*cur.nextInset());
815                 cur.niceInsert(save_selection);
816 #else
817                 if (currentMode() == InsetBase::TEXT_MODE) {
818                         cur.niceInsert(MathAtom(new InsetMathHull("simple")));
819                         cur.message(_("create new math text environment ($...$)"));
820                 } else {
821                         handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
822                         cur.message(_("entered math text mode (textrm)"));
823                 }
824 #endif
825                 break;
826         }
827
828         case LFUN_MATH_SIZE:
829 #if 0
830                 recordUndo(cur);
831                 cur.setSize(arg);
832 #endif
833                 break;
834
835         case LFUN_MATH_MATRIX: {
836                 recordUndo(cur, Undo::ATOMIC);
837                 unsigned int m = 1;
838                 unsigned int n = 1;
839                 string v_align;
840                 string h_align;
841                 istringstream is(lyx::to_utf8(cmd.argument()));
842                 is >> m >> n >> v_align >> h_align;
843                 if (m < 1)
844                         m = 1;
845                 if (n < 1)
846                         n = 1;
847                 v_align += 'c';
848                 cur.niceInsert(
849                         MathAtom(new InsetMathArray("array", m, n, v_align[0], h_align)));
850                 break;
851         }
852
853         case LFUN_MATH_DELIM: {
854                 string ls;
855                 string rs = lyx::support::split(lyx::to_utf8(cmd.argument()), ls, ' ');
856                 // Reasonable default values
857                 if (ls.empty())
858                         ls = '(';
859                 if (rs.empty())
860                         rs = ')';
861                 recordUndo(cur, Undo::ATOMIC);
862                 cur.handleNest(MathAtom(new InsetMathDelim(ls, rs)));
863                 break;
864         }
865
866         case LFUN_MATH_BIGDELIM: {
867                 string const lname = cmd.getArg(0);
868                 string const ldelim = cmd.getArg(1);
869                 string const rname = cmd.getArg(2);
870                 string const rdelim = cmd.getArg(3);
871                 latexkeys const * l = in_word_set(lname);
872                 bool const have_l = l && l->inset == "big" &&
873                                     InsetMathBig::isBigInsetDelim(ldelim);
874                 l = in_word_set(rname);
875                 bool const have_r = l && l->inset == "big" &&
876                                     InsetMathBig::isBigInsetDelim(rdelim);
877                 // We mimic LFUN_MATH_DELIM in case we have an empty left
878                 // or right delimiter.
879                 if (have_l || have_r) {
880                         recordUndo(cur, Undo::ATOMIC);
881                         string const selection = grabAndEraseSelection(cur);
882                         selClearOrDel(cur);
883                         if (have_l)
884                                 cur.insert(MathAtom(new InsetMathBig(lname,
885                                                                 ldelim)));
886                         cur.niceInsert(selection);
887                         if (have_r)
888                                 cur.insert(MathAtom(new InsetMathBig(rname,
889                                                                 rdelim)));
890                 }
891                 // Don't call cur.undispatched() if we did nothing, this would
892                 // lead to infinite recursion via LyXText::dispatch().
893                 break;
894         }
895
896         case LFUN_SPACE_INSERT:
897         case LFUN_MATH_SPACE:
898                 recordUndo(cur, Undo::ATOMIC);
899                 cur.insert(MathAtom(new InsetMathSpace(",")));
900                 break;
901
902         case LFUN_ERT_INSERT:
903                 // interpret this as if a backslash was typed
904                 recordUndo(cur, Undo::ATOMIC);
905                 interpret(cur, '\\');
906                 break;
907
908         case LFUN_MATH_SUBSCRIPT:
909                 // interpret this as if a _ was typed
910                 recordUndo(cur, Undo::ATOMIC);
911                 interpret(cur, '_');
912                 break;
913
914         case LFUN_MATH_SUPERSCRIPT:
915                 // interpret this as if a ^ was typed
916                 recordUndo(cur, Undo::ATOMIC);
917                 interpret(cur, '^');
918                 break;
919
920 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
921 // handling such that "self-insert" works on "arbitrary stuff" too, and
922 // math-insert only handles special math things like "matrix".
923         case LFUN_MATH_INSERT: {
924                 recordUndo(cur, Undo::ATOMIC);
925                 if (cmd.argument() == "^" || cmd.argument() == "_")
926                         interpret(cur, cmd.argument()[0]);
927                 else
928                         cur.niceInsert(lyx::to_utf8(cmd.argument()));
929                 break;
930                 }
931
932         case LFUN_DIALOG_SHOW_NEW_INSET: {
933                 string const & name = lyx::to_utf8(cmd.argument());
934                 string data;
935                 if (name == "ref") {
936                         RefInset tmp(name);
937                         data = tmp.createDialogStr(name);
938                 }
939                 cur.bv().showInsetDialog(name, data, 0);
940                 break;
941         }
942
943         default:
944                 InsetMathDim::doDispatch(cur, cmd);
945                 break;
946         }
947 }
948
949
950 bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd,
951                 FuncStatus & flag) const
952 {
953         // the font related toggles
954         //string tc = "mathnormal";
955         bool ret = true;
956         string const arg = lyx::to_utf8(cmd.argument());
957         switch (cmd.action) {
958         case LFUN_TABULAR_FEATURE:
959                 flag.enabled(false);
960                 break;
961 #if 0
962         case LFUN_TABULAR_FEATURE:
963                 // FIXME: check temporarily disabled
964                 // valign code
965                 char align = mathcursor::valign();
966                 if (align == '\0') {
967                         enable = false;
968                         break;
969                 }
970                 if (cmd.argument().empty()) {
971                         flag.clear();
972                         break;
973                 }
974                 if (!contains("tcb", cmd.argument()[0])) {
975                         enable = false;
976                         break;
977                 }
978                 flag.setOnOff(cmd.argument()[0] == align);
979                 break;
980 #endif
981         /// We have to handle them since 1.4 blocks all unhandled actions
982         case LFUN_FONT_ITAL:
983         case LFUN_FONT_BOLD:
984         case LFUN_FONT_SANS:
985         case LFUN_FONT_EMPH:
986         case LFUN_FONT_CODE:
987         case LFUN_FONT_NOUN:
988         case LFUN_FONT_ROMAN:
989         case LFUN_FONT_DEFAULT:
990                 flag.enabled(true);
991                 break;
992         case LFUN_MATH_MUTATE:
993                 //flag.setOnOff(mathcursor::formula()->hullType() == lyx::to_utf8(cmd.argument()));
994                 flag.setOnOff(false);
995                 break;
996
997         // we just need to be in math mode to enable that
998         case LFUN_MATH_SIZE:
999         case LFUN_MATH_SPACE:
1000         case LFUN_MATH_LIMITS:
1001         case LFUN_MATH_NONUMBER:
1002         case LFUN_MATH_NUMBER:
1003         case LFUN_MATH_EXTERN:
1004                 flag.enabled(true);
1005                 break;
1006
1007         case LFUN_FONT_FRAK:
1008                 flag.enabled(currentMode() != TEXT_MODE);
1009                 break;
1010
1011         case LFUN_MATH_INSERT: {
1012                 bool const textarg =
1013                         arg == "\\textbf"   || arg == "\\textsf" ||
1014                         arg == "\\textrm"   || arg == "\\textmd" ||
1015                         arg == "\\textit"   || arg == "\\textsc" ||
1016                         arg == "\\textsl"   || arg == "\\textup" ||
1017                         arg == "\\texttt"   || arg == "\\textbb" ||
1018                         arg == "\\textnormal";
1019                 flag.enabled(currentMode() != TEXT_MODE || textarg);
1020                 break;
1021         }
1022
1023         case LFUN_MATH_MATRIX:
1024                 flag.enabled(currentMode() == MATH_MODE);
1025                 break;
1026
1027         case LFUN_MATH_DELIM:
1028         case LFUN_MATH_BIGDELIM:
1029                 // Don't do this with multi-cell selections
1030                 flag.enabled(cur.selBegin().idx() == cur.selEnd().idx());
1031                 break;
1032
1033         default:
1034                 ret = false;
1035                 break;
1036         }
1037         return ret;
1038 }
1039
1040
1041 void InsetMathNest::edit(LCursor & cur, bool left)
1042 {
1043         cur.push(*this);
1044         cur.idx() = left ? 0 : cur.lastidx();
1045         cur.pos() = left ? 0 : cur.lastpos();
1046         cur.resetAnchor();
1047         //lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl;
1048 }
1049
1050
1051 InsetBase * InsetMathNest::editXY(LCursor & cur, int x, int y)
1052 {
1053         int idx_min = 0;
1054         int dist_min = 1000000;
1055         for (idx_type i = 0, n = nargs(); i != n; ++i) {
1056                 int const d = cell(i).dist(x, y);
1057                 if (d < dist_min) {
1058                         dist_min = d;
1059                         idx_min = i;
1060                 }
1061         }
1062         MathArray & ar = cell(idx_min);
1063         cur.push(*this);
1064         cur.idx() = idx_min;
1065         cur.pos() = ar.x2pos(x - ar.xo());
1066         //lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
1067         if (dist_min == 0) {
1068                 // hit inside cell
1069                 for (pos_type i = 0, n = ar.size(); i < n; ++i)
1070                         if (ar[i]->covers(x, y))
1071                                 return ar[i].nucleus()->editXY(cur, x, y);
1072         }
1073         return this;
1074 }
1075
1076
1077 void InsetMathNest::lfunMousePress(LCursor & cur, FuncRequest & cmd)
1078 {
1079         //lyxerr << "## lfunMousePress: buttons: " << cmd.button() << endl;
1080         BufferView & bv = cur.bv();
1081         if (cmd.button() == mouse_button::button1) {
1082                 //lyxerr << "## lfunMousePress: setting cursor to: " << cur << endl;
1083                 bv.mouseSetCursor(cur);
1084         } else if (cmd.button() == mouse_button::button2) {
1085                 MathArray ar;
1086                 if (cur.selection())
1087                         asArray(lyx::to_utf8(bv.cursor().selectionAsString(false)), ar);
1088                 else
1089                         asArray(lyx::to_utf8(theApp->selection().get()), ar);
1090
1091                 cur.insert(ar);
1092                 bv.mouseSetCursor(cur);
1093         }
1094 }
1095
1096
1097 void InsetMathNest::lfunMouseMotion(LCursor & cur, FuncRequest & cmd)
1098 {
1099         // only select with button 1
1100         if (cmd.button() == mouse_button::button1) {
1101                 LCursor & bvcur = cur.bv().cursor();
1102                 if (bvcur.anchor_.hasPart(cur)) {
1103                         //lyxerr << "## lfunMouseMotion: cursor: " << cur << endl;
1104                         bvcur.setCursor(cur);
1105                         bvcur.selection() = true;
1106                         //lyxerr << "MOTION " << bvcur << endl;
1107                 }
1108                 else {
1109                         cur.undispatched();
1110                 }
1111         }
1112 }
1113
1114
1115 void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
1116 {
1117         //lyxerr << "## lfunMouseRelease: buttons: " << cmd.button() << endl;
1118
1119         if (cmd.button() == mouse_button::button1) {
1120                 //theApp->selection().put(cur.grabSelection());
1121                 return;
1122         }
1123
1124         if (cmd.button() == mouse_button::button3) {
1125                 // try to dispatch to enclosed insets first
1126                 cur.bv().showDialog("mathpanel");
1127                 return;
1128         }
1129
1130         cur.undispatched();
1131 }
1132
1133
1134 bool InsetMathNest::interpret(LCursor & cur, char c)
1135 {
1136         //lyxerr << "interpret 2: '" << c << "'" << endl;
1137         string save_selection;
1138         if (c == '^' || c == '_')
1139                 save_selection = grabAndEraseSelection(cur);
1140
1141         cur.clearTargetX();
1142
1143         // handle macroMode
1144         if (cur.inMacroMode()) {
1145                 string name = cur.macroName();
1146
1147                 /// are we currently typing '#1' or '#2' or...?
1148                 if (name == "\\#") {
1149                         cur.backspace();
1150                         int n = c - '0';
1151                         if (n >= 1 && n <= 9)
1152                                 cur.insert(new MathMacroArgument(n));
1153                         return true;
1154                 }
1155
1156                 if (isalpha(c)) {
1157                         cur.activeMacro()->setName(name + c);
1158                         return true;
1159                 }
1160
1161                 // handle 'special char' macros
1162                 if (name == "\\") {
1163                         // remove the '\\'
1164                         if (c == '\\') {
1165                                 cur.backspace();
1166                                 if (currentMode() == InsetMath::TEXT_MODE)
1167                                         cur.niceInsert(createInsetMath("textbackslash"));
1168                                 else
1169                                         cur.niceInsert(createInsetMath("backslash"));
1170                         } else if (c == '{') {
1171                                 cur.backspace();
1172                                 cur.niceInsert(MathAtom(new InsetMathBrace));
1173                         } else if (c == '%') {
1174                                 cur.backspace();
1175                                 cur.niceInsert(MathAtom(new InsetMathComment));
1176                         } else if (c == '#') {
1177                                 BOOST_ASSERT(cur.activeMacro());
1178                                 cur.activeMacro()->setName(name + c);
1179                         } else {
1180                                 cur.backspace();
1181                                 cur.niceInsert(createInsetMath(string(1, c)));
1182                         }
1183                         return true;
1184                 }
1185
1186                 // One character big delimiters. The others are handled in
1187                 // the other interpret() method.
1188                 latexkeys const * l = in_word_set(name.substr(1));
1189                 if (name[0] == '\\' && l && l->inset == "big") {
1190                         string delim;
1191                         switch (c) {
1192                         case '{':
1193                                 delim = "\\{";
1194                                 break;
1195                         case '}':
1196                                 delim = "\\}";
1197                                 break;
1198                         default:
1199                                 delim = string(1, c);
1200                                 break;
1201                         }
1202                         if (InsetMathBig::isBigInsetDelim(delim)) {
1203                                 // name + delim ared a valid InsetMathBig.
1204                                 // We can't use cur.macroModeClose() because
1205                                 // it does not handle delim.
1206                                 InsetMathUnknown * p = cur.activeMacro();
1207                                 p->finalize();
1208                                 --cur.pos();
1209                                 cur.cell().erase(cur.pos());
1210                                 cur.plainInsert(MathAtom(
1211                                         new InsetMathBig(name.substr(1), delim)));
1212                                 return true;
1213                         }
1214                 }
1215
1216                 // leave macro mode and try again if necessary
1217                 cur.macroModeClose();
1218                 if (c == '{')
1219                         cur.niceInsert(MathAtom(new InsetMathBrace));
1220                 else if (c != ' ')
1221                         interpret(cur, c);
1222                 return true;
1223         }
1224
1225         // This is annoying as one has to press <space> far too often.
1226         // Disable it.
1227
1228 #if 0
1229                 // leave autocorrect mode if necessary
1230                 if (autocorrect() && c == ' ') {
1231                         autocorrect() = false;
1232                         return true;
1233                 }
1234 #endif
1235
1236         // just clear selection on pressing the space bar
1237         if (cur.selection() && c == ' ') {
1238                 cur.selection() = false;
1239                 return true;
1240         }
1241
1242         selClearOrDel(cur);
1243
1244         if (c == '\\') {
1245                 //lyxerr << "starting with macro" << endl;
1246                 cur.insert(MathAtom(new InsetMathUnknown("\\", false)));
1247                 return true;
1248         }
1249
1250         if (c == '\n') {
1251                 if (currentMode() == InsetMath::TEXT_MODE)
1252                         cur.insert(c);
1253                 return true;
1254         }
1255
1256         if (c == ' ') {
1257                 if (currentMode() == InsetMath::TEXT_MODE) {
1258                         // insert spaces in text mode,
1259                         // but suppress direct insertion of two spaces in a row
1260                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1261                         // it is better than nothing...
1262                         if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
1263                                 cur.insert(c);
1264                         return true;
1265                 }
1266                 if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
1267                         cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
1268                         return true;
1269                 }
1270                 if (cur.popRight())
1271                         return true;
1272                 // if are at the very end, leave the formula
1273                 return cur.pos() != cur.lastpos();
1274         }
1275
1276         // These shouldn't work in text mode:
1277         if (currentMode() != InsetMath::TEXT_MODE) {
1278                 if (c == '_') {
1279                         script(cur, false, save_selection);
1280                         return true;
1281                 }
1282                 if (c == '^') {
1283                         script(cur, true, save_selection);
1284                         return true;
1285                 }
1286                 if (c == '~') {
1287                         cur.niceInsert(createInsetMath("sim"));
1288                         return true;
1289                 }
1290         }
1291
1292         if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' ||
1293             c == '%' || c == '_' || c == '^') {
1294                 cur.niceInsert(createInsetMath(string(1, c)));
1295                 return true;
1296         }
1297
1298
1299         // try auto-correction
1300         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1301         //      return true;
1302
1303         // no special circumstances, so insert the character without any fuss
1304         cur.insert(c);
1305         cur.autocorrect() = true;
1306         return true;
1307 }
1308
1309
1310 bool InsetMathNest::interpret(LCursor & cur, string const & str)
1311 {
1312         // Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if
1313         // possible
1314         if (!cur.empty() && cur.pos() > 0 &&
1315             cur.cell()[cur.pos() - 1]->asUnknownInset()) {
1316                 if (InsetMathBig::isBigInsetDelim(str)) {
1317                         string prev = asString(cur.cell()[cur.pos() - 1]);
1318                         if (prev[0] == '\\') {
1319                                 prev = prev.substr(1);
1320                                 latexkeys const * l = in_word_set(prev);
1321                                 if (l && l->inset == "big") {
1322                                         cur.cell()[cur.pos() - 1] =
1323                                                 MathAtom(new InsetMathBig(prev, str));
1324                                         return true;
1325                                 }
1326                         }
1327                 }
1328         }
1329         return false;
1330 }
1331
1332
1333 bool InsetMathNest::script(LCursor & cur, bool up, string const &
1334                 save_selection)
1335 {
1336         // Hack to get \^ and \_ working
1337         //lyxerr << "handling script: up: " << up << endl;
1338         if (cur.inMacroMode() && cur.macroName() == "\\") {
1339                 if (up)
1340                         cur.niceInsert(createInsetMath("mathcircumflex"));
1341                 else
1342                         interpret(cur, '_');
1343                 return true;
1344         }
1345
1346         cur.macroModeClose();
1347         if (asScriptInset() && cur.idx() == 0) {
1348                 // we are in a nucleus of a script inset, move to _our_ script
1349                 InsetMathScript * inset = asScriptInset();
1350                 //lyxerr << " going to cell " << inset->idxOfScript(up) << endl;
1351                 inset->ensure(up);
1352                 cur.idx() = inset->idxOfScript(up);
1353                 cur.pos() = 0;
1354         } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
1355                 --cur.pos();
1356                 InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset();
1357                 cur.push(*inset);
1358                 inset->ensure(up);
1359                 cur.idx() = inset->idxOfScript(up);
1360                 cur.pos() = cur.lastpos();
1361         } else {
1362                 // convert the thing to our left to a scriptinset or create a new
1363                 // one if in the very first position of the array
1364                 if (cur.pos() == 0) {
1365                         //lyxerr << "new scriptinset" << endl;
1366                         cur.insert(new InsetMathScript(up));
1367                 } else {
1368                         //lyxerr << "converting prev atom " << endl;
1369                         cur.prevAtom() = MathAtom(new InsetMathScript(cur.prevAtom(), up));
1370                 }
1371                 --cur.pos();
1372                 InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset();
1373                 // special handling of {}-bases
1374                 // is this always correct?
1375                 if (inset->nuc().size() == 1
1376                     && inset->nuc().back()->asBraceInset())
1377                         inset->nuc() = inset->nuc().back()->asNestInset()->cell(0);
1378
1379                 cur.push(*inset);
1380                 cur.idx() = 1;
1381                 cur.pos() = 0;
1382         }
1383         //lyxerr << "inserting selection 1:\n" << save_selection << endl;
1384         cur.niceInsert(save_selection);
1385         cur.resetAnchor();
1386         //lyxerr << "inserting selection 2:\n" << save_selection << endl;
1387         return true;
1388 }