3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
16 #include "BufferParams.h"
17 #include "FloatList.h"
18 #include "FuncRequest.h"
21 #include "TextClass.h"
23 #include "insets/InsetBibitem.h"
24 #include "insets/InsetBibtex.h"
25 #include "insets/InsetCaption.h"
26 #include "insets/InsetCitation.h"
27 #include "insets/InsetFlex.h"
28 #include "insets/InsetERT.h"
29 #include "insets/InsetListings.h"
30 #include "insets/InsetExternal.h"
31 #include "insets/InsetFloat.h"
32 #include "insets/InsetFloatList.h"
33 #include "insets/InsetFoot.h"
34 #include "insets/InsetGraphics.h"
35 #include "insets/InsetInclude.h"
36 #include "insets/InsetIndex.h"
37 #include "insets/InsetInfo.h"
38 #include "insets/InsetNomencl.h"
39 #include "insets/InsetLabel.h"
40 #include "insets/InsetLine.h"
41 #include "insets/InsetMarginal.h"
42 #include "insets/InsetNewline.h"
43 #include "insets/InsetNewpage.h"
44 #include "insets/InsetNote.h"
45 #include "insets/InsetBox.h"
46 #include "insets/InsetBranch.h"
47 #include "insets/InsetPhantom.h"
48 #include "insets/InsetOptArg.h"
49 #include "insets/InsetNewpage.h"
50 #include "insets/InsetRef.h"
51 #include "insets/InsetSpace.h"
52 #include "insets/InsetTabular.h"
53 #include "insets/InsetTOC.h"
54 #include "insets/InsetHyperlink.h"
55 #include "insets/InsetVSpace.h"
56 #include "insets/InsetWrap.h"
58 #include "mathed/MathMacroTemplate.h"
59 #include "mathed/InsetMathHull.h"
61 #include "frontends/alert.h"
63 #include "support/debug.h"
64 #include "support/lstrings.h"
65 #include "support/ExceptionMessage.h"
67 #include "support/lassert.h"
72 using namespace lyx::support
;
76 namespace Alert
= frontend::Alert
;
79 Inset
* createInsetHelper(Buffer
& buf
, FuncRequest
const & cmd
)
81 BufferParams
const & params
= buf
.params();
87 case LFUN_LINE_INSERT
:
90 case LFUN_NEWPAGE_INSERT
: {
91 string
const name
= cmd
.getArg(0);
92 InsetNewpageParams inp
;
93 if (name
.empty() || name
== "newpage")
94 inp
.kind
= InsetNewpageParams::NEWPAGE
;
95 else if (name
== "pagebreak")
96 inp
.kind
= InsetNewpageParams::PAGEBREAK
;
97 else if (name
== "clearpage")
98 inp
.kind
= InsetNewpageParams::CLEARPAGE
;
99 else if (name
== "cleardoublepage")
100 inp
.kind
= InsetNewpageParams::CLEARDOUBLEPAGE
;
101 return new InsetNewpage(inp
);
104 case LFUN_FLEX_INSERT
: {
105 string s
= cmd
.getArg(0);
106 return new InsetFlex(buf
, s
);
109 case LFUN_NOTE_INSERT
: {
110 string arg
= cmd
.getArg(0);
113 return new InsetNote(buf
, arg
);
116 case LFUN_BOX_INSERT
: {
117 string arg
= cmd
.getArg(0);
120 return new InsetBox(buf
, arg
);
123 case LFUN_BRANCH_INSERT
: {
124 docstring arg
= cmd
.argument();
126 arg
= from_ascii("none");
127 return new InsetBranch(buf
, InsetBranchParams(arg
));
130 case LFUN_PHANTOM_INSERT
: {
131 string arg
= cmd
.getArg(0);
134 return new InsetPhantom(buf
, arg
);
137 case LFUN_ERT_INSERT
:
138 return new InsetERT(buf
);
140 case LFUN_LISTING_INSERT
:
141 return new InsetListings(buf
);
143 case LFUN_FOOTNOTE_INSERT
:
144 return new InsetFoot(buf
);
146 case LFUN_MARGINALNOTE_INSERT
:
147 return new InsetMarginal(buf
);
149 case LFUN_OPTIONAL_INSERT
:
150 return new InsetOptArg(buf
);
152 case LFUN_FLOAT_INSERT
: {
153 // check if the float type exists
154 string
const argument
= to_utf8(cmd
.argument());
155 if (buf
.params().documentClass().floats().typeExist(argument
))
156 return new InsetFloat(buf
, argument
);
157 lyxerr
<< "Non-existent float type: " << argument
<< endl
;
160 case LFUN_FLOAT_WIDE_INSERT
: {
161 // check if the float type exists
162 string
const argument
= to_utf8(cmd
.argument());
163 if (params
.documentClass().floats().typeExist(argument
)) {
164 auto_ptr
<InsetFloat
> p(new InsetFloat(buf
, argument
));
165 p
->setWide(true, params
);
168 lyxerr
<< "Non-existent float type: " << argument
<< endl
;
172 case LFUN_WRAP_INSERT
: {
173 string
const argument
= to_utf8(cmd
.argument());
174 if (argument
== "figure" || argument
== "table")
175 return new InsetWrap(buf
, argument
);
176 lyxerr
<< "Non-existent wrapfig type: " << argument
<< endl
;
180 case LFUN_INDEX_INSERT
:
181 return new InsetIndex(buf
);
183 case LFUN_NOMENCL_INSERT
: {
184 InsetCommandParams
icp(NOMENCL_CODE
);
185 icp
["symbol"] = cmd
.argument();
186 return new InsetNomencl(icp
);
189 case LFUN_TABULAR_INSERT
: {
190 if (cmd
.argument().empty())
192 istringstream
ss(to_utf8(cmd
.argument()));
199 return new InsetTabular(buf
, r
, c
);
202 case LFUN_CAPTION_INSERT
:
203 return new InsetCaption(buf
);
205 case LFUN_INDEX_PRINT
:
206 return new InsetPrintIndex(InsetCommandParams(INDEX_PRINT_CODE
));
208 case LFUN_NOMENCL_PRINT
:
209 return new InsetPrintNomencl(InsetCommandParams(NOMENCL_PRINT_CODE
));
211 case LFUN_TOC_INSERT
:
212 return new InsetTOC(InsetCommandParams(TOC_CODE
));
214 case LFUN_INFO_INSERT
: {
215 InsetInfo
* inset
= new InsetInfo(buf
, to_utf8(cmd
.argument()));
220 case LFUN_INSET_INSERT
: {
221 string
const name
= cmd
.getArg(0);
222 InsetCode code
= insetCode(name
);
225 lyxerr
<< "No such inset '" << name
<< "'.";
229 InsetCommandParams
icp(code
);
230 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
231 return new InsetBibitem(buf
, icp
);
235 InsetCommandParams
icp(code
);
236 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
237 return new InsetBibtex(buf
, icp
);
241 InsetCommandParams
icp(code
);
242 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
243 return new InsetCitation(icp
);
247 return new InsetERT(buf
,
248 InsetERT::string2params(to_utf8(cmd
.argument())));
251 case LISTINGS_CODE
: {
252 InsetListingsParams par
;
253 InsetListings::string2params(to_utf8(cmd
.argument()), par
);
254 return new InsetListings(buf
, par
);
257 case EXTERNAL_CODE
: {
258 InsetExternalParams iep
;
259 InsetExternal::string2params(to_utf8(cmd
.argument()), buf
, iep
);
260 auto_ptr
<InsetExternal
> inset(new InsetExternal(buf
));
261 inset
->setBuffer(buf
);
262 inset
->setParams(iep
);
263 return inset
.release();
266 case GRAPHICS_CODE
: {
267 InsetGraphicsParams igp
;
268 InsetGraphics::string2params(to_utf8(cmd
.argument()), buf
, igp
);
269 auto_ptr
<InsetGraphics
> inset(new InsetGraphics(buf
));
270 inset
->setParams(igp
);
271 return inset
.release();
274 case HYPERLINK_CODE
: {
275 InsetCommandParams
icp(code
);
276 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
277 return new InsetHyperlink(icp
);
281 InsetCommandParams
icp(code
);
282 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
283 return new InsetInclude(icp
);
287 return new InsetIndex(buf
);
290 InsetCommandParams
icp(code
);
291 InsetCommand::string2params(name
, lyx::to_utf8(cmd
.argument()), icp
);
292 return new InsetNomencl(icp
);
296 InsetCommandParams
icp(code
);
297 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
298 return new InsetLabel(icp
);
302 InsetCommandParams
icp(code
);
303 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
304 return new InsetRef(buf
, icp
);
308 InsetSpaceParams isp
;
309 InsetSpace::string2params(to_utf8(cmd
.argument()), isp
);
310 return new InsetSpace(isp
);
314 InsetCommandParams
icp(code
);
315 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
316 return new InsetTOC(icp
);
321 InsetVSpace::string2params(to_utf8(cmd
.argument()), vspace
);
322 return new InsetVSpace(vspace
);
326 lyxerr
<< "Inset '" << name
<< "' not permitted with LFUN_INSET_INSERT."
331 } //end LFUN_INSET_INSERT
333 case LFUN_SPACE_INSERT
: {
334 string
const name
= cmd
.getArg(0);
335 string
const len
= cmd
.getArg(1);
337 lyxerr
<< "LyX function 'space-insert' needs an argument." << endl
;
340 InsetSpaceParams isp
;
341 // The tests for isp.math might be disabled after a file format change
342 if (name
== "normal")
343 isp
.kind
= InsetSpaceParams::NORMAL
;
344 else if (name
== "protected")
345 isp
.kind
= InsetSpaceParams::PROTECTED
;
346 else if (name
== "thin")
347 isp
.kind
= InsetSpaceParams::THIN
;
348 else if (isp
.math
&& name
== "med")
349 isp
.kind
= InsetSpaceParams::MEDIUM
;
350 else if (isp
.math
&& name
== "thick")
351 isp
.kind
= InsetSpaceParams::THICK
;
352 else if (name
== "quad")
353 isp
.kind
= InsetSpaceParams::QUAD
;
354 else if (name
== "qquad")
355 isp
.kind
= InsetSpaceParams::QQUAD
;
356 else if (name
== "enspace")
357 isp
.kind
= InsetSpaceParams::ENSPACE
;
358 else if (name
== "enskip")
359 isp
.kind
= InsetSpaceParams::ENSKIP
;
360 else if (name
== "negthinspace")
361 isp
.kind
= InsetSpaceParams::NEGTHIN
;
362 else if (isp
.math
&& name
== "negmedspace")
363 isp
.kind
= InsetSpaceParams::NEGMEDIUM
;
364 else if (isp
.math
&& name
== "negthickspace")
365 isp
.kind
= InsetSpaceParams::NEGTHICK
;
366 else if (name
== "hfill")
367 isp
.kind
= InsetSpaceParams::HFILL
;
368 else if (name
== "hfill*")
369 isp
.kind
= InsetSpaceParams::HFILL_PROTECTED
;
370 else if (name
== "dotfill")
371 isp
.kind
= InsetSpaceParams::DOTFILL
;
372 else if (name
== "hrulefill")
373 isp
.kind
= InsetSpaceParams::HRULEFILL
;
374 else if (name
== "hspace") {
375 if (len
.empty() || !isValidLength(len
)) {
376 lyxerr
<< "LyX function 'space-insert hspace' "
377 << "needs a valid length argument." << endl
;
380 isp
.kind
= InsetSpaceParams::CUSTOM
;
381 isp
.length
= Length(len
);
383 else if (name
== "hspace*") {
384 if (len
.empty() || !isValidLength(len
)) {
385 lyxerr
<< "LyX function 'space-insert hspace*' "
386 << "needs a valid length argument." << endl
;
389 isp
.kind
= InsetSpaceParams::CUSTOM_PROTECTED
;
390 isp
.length
= Length(len
);
393 lyxerr
<< "Wrong argument for LyX function 'space-insert'." << endl
;
396 return new InsetSpace(isp
);
404 } catch (ExceptionMessage
const & message
) {
405 if (message
.type_
== ErrorException
) {
406 // This should never happen!
407 Alert::error(message
.title_
, message
.details_
);
409 } else if (message
.type_
== WarningException
) {
410 Alert::warning(message
.title_
, message
.details_
);
419 Inset
* createInset(Buffer
& buf
, FuncRequest
const & cmd
)
421 Inset
* inset
= createInsetHelper(buf
, cmd
);
423 inset
->setBuffer(buf
);
428 Inset
* readInset(Lexer
& lex
, Buffer
const & buf
)
431 if (lex
.getString() != "\\begin_inset")
432 LYXERR0("Buffer::readInset: Consistency check failed.");
434 auto_ptr
<Inset
> inset
;
439 // test the different insets
441 // FIXME It would be better if we did not have this branch and could
442 // just do one massive switch for all insets. But at present, it's
443 // easier to do it this way, and we can't do the massive switch until
444 // the conversion mentioned below. Note that if we do want to do a
445 // single switch, we need to remove this "CommandInset" line---or
446 // replace it with a single "InsetType" line that would be used in all
448 if (tmptok
== "CommandInset") {
450 string
const insetType
= lex
.getString();
451 lex
.pushToken(insetType
);
453 InsetCode
const code
= insetCode(insetType
);
455 //FIXME If we do the one massive switch, we cannot do this here, since
456 //we do not know in advance that we're dealing with a command inset.
457 //Worst case, we could put it in each case below. Better, we could
458 //pass the lexer to the constructor and let the params be built there.
459 InsetCommandParams
inscmd(code
);
464 inset
.reset(new InsetBibitem(buf
, inscmd
));
467 inset
.reset(new InsetBibtex(buf
, inscmd
));
470 inset
.reset(new InsetCitation(inscmd
));
473 inset
.reset(new InsetHyperlink(inscmd
));
476 inset
.reset(new InsetInclude(inscmd
));
478 case INDEX_PRINT_CODE
:
479 inset
.reset(new InsetPrintIndex(inscmd
));
482 inset
.reset(new InsetLabel(inscmd
));
485 inset
.reset(new InsetNomencl(inscmd
));
487 case NOMENCL_PRINT_CODE
:
488 inset
.reset(new InsetPrintNomencl(inscmd
));
491 if (inscmd
["name"].empty() && inscmd
["reference"].empty())
493 inset
.reset(new InsetRef(buf
, inscmd
));
496 inset
.reset(new InsetTOC(inscmd
));
500 lyxerr
<< "unknown CommandInset '" << insetType
502 while (lex
.isOK() && lex
.getString() != "\\end_inset")
506 inset
->setBuffer(const_cast<Buffer
&>(buf
));
508 // FIXME This branch should be made to use inset codes as the preceding
509 // branch does. Unfortunately, that will take some doing. It requires
510 // converting the representation of the insets in LyX files so that they
511 // use the inset names listed in Inset.cpp. Then, as above, the inset names
512 // can be translated to inset codes using insetCode(). And the insets'
513 // write() routines should use insetName() rather than hardcoding it.
514 if (tmptok
== "Quotes") {
515 inset
.reset(new InsetQuotes(buf
));
516 } else if (tmptok
== "External") {
517 inset
.reset(new InsetExternal(const_cast<Buffer
&>(buf
)));
518 } else if (tmptok
== "FormulaMacro") {
519 inset
.reset(new MathMacroTemplate
);
520 } else if (tmptok
== "Formula") {
521 inset
.reset(new InsetMathHull
);
522 } else if (tmptok
== "Graphics") {
523 inset
.reset(new InsetGraphics(const_cast<Buffer
&>(buf
)));
524 } else if (tmptok
== "Note") {
525 inset
.reset(new InsetNote(buf
, tmptok
));
526 } else if (tmptok
== "Box") {
527 inset
.reset(new InsetBox(buf
, tmptok
));
528 } else if (tmptok
== "Flex") {
530 string s
= lex
.getString();
531 inset
.reset(new InsetFlex(buf
, s
));
532 } else if (tmptok
== "Branch") {
533 inset
.reset(new InsetBranch(buf
, InsetBranchParams()));
534 } else if (tmptok
== "Phantom") {
535 inset
.reset(new InsetPhantom(buf
, tmptok
));
536 } else if (tmptok
== "ERT") {
537 inset
.reset(new InsetERT(buf
));
538 } else if (tmptok
== "listings") {
539 inset
.reset(new InsetListings(buf
));
540 } else if (tmptok
== "space") {
541 inset
.reset(new InsetSpace
);
542 } else if (tmptok
== "Tabular") {
543 inset
.reset(new InsetTabular(const_cast<Buffer
&>(buf
)));
544 } else if (tmptok
== "Text") {
545 inset
.reset(new InsetText(buf
));
546 } else if (tmptok
== "VSpace") {
547 inset
.reset(new InsetVSpace
);
548 } else if (tmptok
== "Foot") {
549 inset
.reset(new InsetFoot(buf
));
550 } else if (tmptok
== "Marginal") {
551 inset
.reset(new InsetMarginal(buf
));
552 } else if (tmptok
== "Newpage") {
553 inset
.reset(new InsetNewpage
);
554 } else if (tmptok
== "Newline") {
555 inset
.reset(new InsetNewline
);
556 } else if (tmptok
== "OptArg") {
557 inset
.reset(new InsetOptArg(buf
));
558 } else if (tmptok
== "Float") {
560 string tmptok
= lex
.getString();
561 inset
.reset(new InsetFloat(buf
, tmptok
));
562 } else if (tmptok
== "Wrap") {
564 string tmptok
= lex
.getString();
565 inset
.reset(new InsetWrap(buf
, tmptok
));
566 } else if (tmptok
== "Caption") {
567 inset
.reset(new InsetCaption(buf
));
568 } else if (tmptok
== "Index") {
569 inset
.reset(new InsetIndex(buf
));
570 } else if (tmptok
== "FloatList") {
571 inset
.reset(new InsetFloatList
);
572 } else if (tmptok
== "Info") {
573 inset
.reset(new InsetInfo(buf
));
575 lyxerr
<< "unknown Inset type '" << tmptok
577 while (lex
.isOK() && lex
.getString() != "\\end_inset")
582 // Set the buffer reference for proper parsing of some insets
583 // (InsetCollapsable for example)
584 inset
->setBuffer(const_cast<Buffer
&>(buf
));
586 // Set again the buffer for insets that are created inside this inset
587 // (InsetMathHull for example).
588 inset
->setBuffer(const_cast<Buffer
&>(buf
));
590 return inset
.release();