]> git.lyx.org Git - lyx.git/blob - src/insets/insetert.C
fix crash when collapsing ert with cursor inside
[lyx.git] / src / insets / insetert.C
1 /**
2  * \file insetert.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  * \author Lars Gullik Bjønnes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "insetert.h"
15
16 #include "buffer.h"
17 #include "bufferparams.h"
18 #include "BufferView.h"
19 #include "cursor.h"
20 #include "debug.h"
21 #include "dispatchresult.h"
22 #include "funcrequest.h"
23 #include "FuncStatus.h"
24 #include "gettext.h"
25 #include "language.h"
26 #include "LColor.h"
27 #include "LyXAction.h"
28 #include "lyxlex.h"
29 #include "lyxtextclass.h"
30 #include "metricsinfo.h"
31 #include "ParagraphParameters.h"
32 #include "paragraph.h"
33
34 #include "frontends/Alert.h"
35 #include "frontends/LyXView.h"
36
37 #include <sstream>
38
39 using lyx::pos_type;
40 using lyx::support::token;
41
42 using std::endl;
43 using std::min;
44
45 using std::auto_ptr;
46 using std::istringstream;
47 using std::ostream;
48 using std::ostringstream;
49 using std::string;
50
51
52 void InsetERT::init()
53 {
54         setButtonLabel();
55
56         LyXFont font(LyXFont::ALL_SANE);
57         font.decSize();
58         font.decSize();
59         font.setColor(LColor::latex);
60         setLabelFont(font);
61
62         setInsetName("ERT");
63 }
64
65
66 InsetERT::InsetERT(BufferParams const & bp, CollapseStatus status)
67         : InsetCollapsable(bp, status)
68 {
69         init();
70 }
71
72
73 InsetERT::InsetERT(InsetERT const & in)
74         : InsetCollapsable(in)
75 {
76         init();
77 }
78
79
80 auto_ptr<InsetBase> InsetERT::doClone() const
81 {
82         return auto_ptr<InsetBase>(new InsetERT(*this));
83 }
84
85
86 InsetERT::InsetERT(BufferParams const & bp,
87                    Language const *, string const & contents, CollapseStatus status)
88         : InsetCollapsable(bp, status)
89 {
90         //LyXFont font(LyXFont::ALL_INHERIT, lang);
91         LyXFont font;
92         getDrawFont(font);
93         string::const_iterator cit = contents.begin();
94         string::const_iterator end = contents.end();
95         pos_type pos = 0;
96         for (; cit != end; ++cit)
97                 paragraphs().begin()->insertChar(pos++, *cit, font);
98
99         // the init has to be after the initialization of the paragraph
100         // because of the label settings (draw_label for ert insets).
101         init();
102 }
103
104
105 InsetERT::~InsetERT()
106 {
107         InsetERTMailer(*this).hideDialog();
108 }
109
110
111 void InsetERT::write(Buffer const & buf, ostream & os) const
112 {
113         os << "ERT" << "\n";
114         InsetCollapsable::write(buf, os);
115 }
116
117
118 string const InsetERT::editMessage() const
119 {
120         return _("Opened ERT Inset");
121 }
122
123
124 int InsetERT::latex(Buffer const &, ostream & os,
125                     OutputParams const &) const
126 {
127         ParagraphList::const_iterator par = paragraphs().begin();
128         ParagraphList::const_iterator end = paragraphs().end();
129
130         int lines = 0;
131         while (par != end) {
132                 pos_type siz = par->size();
133                 for (pos_type i = 0; i < siz; ++i) {
134                         // ignore all struck out text
135                         if (isDeletedText(*par, i))
136                                 continue;
137
138                         os << par->getChar(i);
139                 }
140                 ++par;
141                 if (par != end) {
142                         os << "\n";
143                         ++lines;
144                 }
145         }
146
147         return lines;
148 }
149
150
151 int InsetERT::plaintext(Buffer const &, ostream &,
152                     OutputParams const & /*runparams*/) const
153 {
154         return 0;
155 }
156
157
158 int InsetERT::linuxdoc(Buffer const &, ostream & os,
159                        OutputParams const &) const
160 {
161         ParagraphList::const_iterator par = paragraphs().begin();
162         ParagraphList::const_iterator end = paragraphs().end();
163
164         int lines = 0;
165         while (par != end) {
166                 pos_type siz = par->size();
167                 for (pos_type i = 0; i < siz; ++i)
168                         os << par->getChar(i);
169                 ++par;
170                 if (par != end) {
171                         os << "\n";
172                         lines ++;
173                 }
174         }
175
176         return lines;
177 }
178
179
180 int InsetERT::docbook(Buffer const &, ostream & os,
181                       OutputParams const &) const
182 {
183         ParagraphList::const_iterator par = paragraphs().begin();
184         ParagraphList::const_iterator end = paragraphs().end();
185
186         int lines = 0;
187         while (par != end) {
188                 pos_type siz = par->size();
189                 for (pos_type i = 0; i < siz; ++i)
190                         os << par->getChar(i);
191                 ++par;
192                 if (par != end) {
193                         os << "\n";
194                         ++lines;
195                 }
196         }
197
198         return lines;
199 }
200
201
202 void InsetERT::doDispatch(LCursor & cur, FuncRequest & cmd)
203 {
204         //lyxerr << "\nInsetERT::doDispatch (begin): cmd: " << cmd << endl;
205         switch (cmd.action) {
206
207         case LFUN_INSET_MODIFY: {
208                 InsetCollapsable::CollapseStatus st;
209                 InsetERTMailer::string2params(cmd.argument, st);
210                 setStatus(st);
211                 if (status() == Collapsed)
212                         cur.leaveInset(*this);
213                 break;
214         }
215         case LFUN_PASTE:
216         case LFUN_PASTESELECTION: {
217                 InsetCollapsable::doDispatch(cur, cmd);
218
219                 // Since we can only store plain text, we must reset all
220                 // attributes.
221                 // FIXME: Change only the pasted paragraphs
222
223                 BufferParams const & bp = cur.buffer().params();
224                 LyXLayout_ptr const layout =
225                         bp.getLyXTextClass().defaultLayout();
226                 LyXFont font = layout->font;
227                 // We need to set the language for non-english documents
228                 font.setLanguage(bp.language);
229                 ParagraphList::iterator const end = paragraphs().end();
230                 for (ParagraphList::iterator par = paragraphs().begin();
231                      par != end; ++par) {
232                         par->layout(layout);
233                         // in case par had a manual label
234                         par->setBeginOfBody();
235                         pos_type const siz = par->size();
236                         for (pos_type i = 0; i < siz; ++i) {
237                                 par->setFont(i, font);
238                         }
239                         par->params().clear();
240                 }
241                 break;
242         }
243         default:
244                 InsetCollapsable::doDispatch(cur, cmd);
245                 break;
246         }
247 }
248
249
250 bool InsetERT::getStatus(LCursor & cur, FuncRequest const & cmd,
251         FuncStatus & status) const
252 {
253         switch (cmd.action) {
254                 // suppress these
255                 case LFUN_ACUTE:
256                 case LFUN_BREVE:
257                 case LFUN_CARON:
258                 case LFUN_CEDILLA:
259                 case LFUN_CIRCLE:
260                 case LFUN_CIRCUMFLEX:
261                 case LFUN_DOT:
262                 case LFUN_GRAVE:
263                 case LFUN_HUNG_UMLAUT:
264                 case LFUN_MACRON:
265                 case LFUN_OGONEK:
266                 case LFUN_SPECIAL_CARON:
267                 case LFUN_TIE:
268                 case LFUN_TILDE:
269                 case LFUN_UMLAUT:
270                 case LFUN_UNDERBAR:
271                 case LFUN_UNDERDOT:
272                 case LFUN_APPENDIX:
273                 case LFUN_BREAKLINE:
274                 case LFUN_INSET_CAPTION:
275                 case LFUN_DEPTH_MIN:
276                 case LFUN_DEPTH_PLUS:
277                 case LFUN_LDOTS:
278                 case LFUN_END_OF_SENTENCE:
279                 case LFUN_ENVIRONMENT_INSERT:
280                 case LFUN_INSET_ERT:
281                 case LFUN_FILE_INSERT:
282                 case LFUN_INSET_FLOAT:
283                 case LFUN_INSET_WIDE_FLOAT:
284                 case LFUN_INSET_WRAP:
285                 case LFUN_BOLD:
286                 case LFUN_CODE:
287                 case LFUN_DEFAULT:
288                 case LFUN_EMPH:
289                 case LFUN_FREEFONT_APPLY:
290                 case LFUN_FREEFONT_UPDATE:
291                 case LFUN_NOUN:
292                 case LFUN_ROMAN:
293                 case LFUN_SANS:
294                 case LFUN_FRAK:
295                 case LFUN_ITAL:
296                 case LFUN_FONT_SIZE:
297                 case LFUN_FONT_STATE:
298                 case LFUN_UNDERLINE:
299                 case LFUN_INSET_FOOTNOTE:
300                 case LFUN_HFILL:
301                 case LFUN_HTMLURL:
302                 case LFUN_HYPHENATION:
303                 case LFUN_LIGATURE_BREAK:
304                 case LFUN_INDEX_INSERT:
305                 case LFUN_INDEX_PRINT:
306                 case LFUN_INSERT_LABEL:
307                 case LFUN_INSET_OPTARG:
308                 case LFUN_INSERT_BIBITEM:
309                 case LFUN_INSERT_LINE:
310                 case LFUN_INSERT_PAGEBREAK:
311                 case LFUN_LANGUAGE:
312                 case LFUN_LAYOUT:
313                 case LFUN_LAYOUT_PARAGRAPH:
314                 case LFUN_LAYOUT_TABULAR:
315                 case LFUN_INSET_MARGINAL:
316                 case LFUN_MATH_DISPLAY:
317                 case LFUN_INSERT_MATH:
318                 case LFUN_INSERT_MATRIX:
319                 case LFUN_MATH_MODE:
320                 case LFUN_MENU_OPEN_BY_NAME:
321                 case LFUN_MENU_SEPARATOR:
322                 case LFUN_INSERT_BRANCH:
323                 case LFUN_INSERT_CHARSTYLE:
324                 case LFUN_INSERT_NOTE:
325                 case LFUN_INSERT_BOX:
326                 case LFUN_GOTONOTE:
327                 case LFUN_PARAGRAPH_SPACING:
328                 case LFUN_QUOTE:
329                 case LFUN_REF_GOTO:
330                 case LFUN_REFERENCE_GOTO:
331                 case LFUN_SPACE_INSERT:
332                 case LFUN_GOTOFILEROW:
333                 case LFUN_NOTIFY:
334                 case LFUN_SETXY:
335                 case LFUN_TABULAR_INSERT:
336                 case LFUN_TOC_INSERT:
337                 case LFUN_URL:
338                 case LFUN_FLOAT_LIST:
339                 case LFUN_INSET_INSERT:
340                 case LFUN_PARAGRAPH_APPLY:
341                 case LFUN_PARAGRAPH_UPDATE:
342                 case LFUN_NOACTION:
343                         status.enabled(false);
344                         return true;
345
346                 case LFUN_INSET_MODIFY:
347                 case LFUN_PASTE:
348                 case LFUN_PASTESELECTION:
349                         status.enabled(true);
350                         return true;
351
352                 // this one is difficult to get right. As a half-baked
353                 // solution, we consider only the first action of the sequence
354                 case LFUN_SEQUENCE: {
355                         // argument contains ';'-terminated commands
356                         string const firstcmd = token(cmd.argument, ';', 0);
357                         FuncRequest func(lyxaction.lookupFunc(firstcmd));
358                         func.origin = cmd.origin;
359                         return getStatus(cur, func, status);
360                 }
361
362                 default:
363                         return InsetCollapsable::getStatus(cur, cmd, status);
364         }
365 }
366
367
368 void InsetERT::setButtonLabel()
369 {
370         setLabel(status() == Collapsed ? getNewLabel(_("ERT")) : _("ERT"));
371 }
372
373
374 bool InsetERT::insetAllowed(InsetBase::Code /* code */) const
375 {
376         return false;
377 }
378
379
380 void InsetERT::metrics(MetricsInfo & mi, Dimension & dim) const
381 {
382         LyXFont tmpfont = mi.base.font;
383         getDrawFont(mi.base.font);
384         mi.base.font.realize(tmpfont);
385         InsetCollapsable::metrics(mi, dim);
386         mi.base.font = tmpfont;
387         dim_ = dim;
388 }
389
390
391 void InsetERT::draw(PainterInfo & pi, int x, int y) const
392 {
393         LyXFont tmpfont = pi.base.font;
394         getDrawFont(pi.base.font);
395         // I don't understand why the above .realize isn't needed, or
396         // even wanted, here. It just works. -- MV 10.04.2005
397         InsetCollapsable::draw(pi, x, y);
398         pi.base.font = tmpfont;
399 }
400
401
402 bool InsetERT::showInsetDialog(BufferView * bv) const
403 {
404         InsetERTMailer(const_cast<InsetERT &>(*this)).showDialog(bv);
405         return true;
406 }
407
408
409 void InsetERT::getDrawFont(LyXFont & font) const
410 {
411         font = LyXFont(LyXFont::ALL_INHERIT, latex_language);
412         font.setFamily(LyXFont::TYPEWRITER_FAMILY);
413         font.setColor(LColor::latex);
414 }
415
416
417 string const InsetERTMailer::name_("ert");
418
419 InsetERTMailer::InsetERTMailer(InsetERT & inset)
420         : inset_(inset)
421 {}
422
423
424 string const InsetERTMailer::inset2string(Buffer const &) const
425 {
426         return params2string(inset_.status());
427 }
428
429
430 void InsetERTMailer::string2params(string const & in,
431                                    InsetCollapsable::CollapseStatus & status)
432 {
433         status = InsetCollapsable::Collapsed;
434         if (in.empty())
435                 return;
436
437         istringstream data(in);
438         LyXLex lex(0,0);
439         lex.setStream(data);
440
441         string name;
442         lex >> name;
443         if (name != name_)
444                 return print_mailer_error("InsetERTMailer", in, 1, name_);
445
446         int s;
447         lex >> s;
448         if (lex)
449                 status = static_cast<InsetCollapsable::CollapseStatus>(s);
450 }
451
452
453 string const
454 InsetERTMailer::params2string(InsetCollapsable::CollapseStatus status)
455 {
456         ostringstream data;
457         data << name_ << ' ' << status;
458         return data.str();
459 }