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/InsetBox.h"
26 #include "insets/InsetBranch.h"
27 #include "insets/InsetCaption.h"
28 #include "insets/InsetCitation.h"
29 #include "insets/InsetFlex.h"
30 #include "insets/InsetERT.h"
31 #include "insets/InsetListings.h"
32 #include "insets/InsetExternal.h"
33 #include "insets/InsetFloat.h"
34 #include "insets/InsetFloatList.h"
35 #include "insets/InsetFoot.h"
36 #include "insets/InsetGraphics.h"
37 #include "insets/InsetHyperlink.h"
38 #include "insets/InsetInclude.h"
39 #include "insets/InsetIndex.h"
40 #include "insets/InsetInfo.h"
41 #include "insets/InsetLabel.h"
42 #include "insets/InsetLine.h"
43 #include "insets/InsetMarginal.h"
44 #include "insets/InsetNewline.h"
45 #include "insets/InsetNewpage.h"
46 #include "insets/InsetNomencl.h"
47 #include "insets/InsetNote.h"
48 #include "insets/InsetOptArg.h"
49 #include "insets/InsetPhantom.h"
50 #include "insets/InsetRef.h"
51 #include "insets/InsetSpace.h"
52 #include "insets/InsetTabular.h"
53 #include "insets/InsetTOC.h"
54 #include "insets/InsetVSpace.h"
55 #include "insets/InsetWrap.h"
57 #include "mathed/MathMacroTemplate.h"
58 #include "mathed/InsetMathHull.h"
60 #include "frontends/alert.h"
62 #include "support/debug.h"
63 #include "support/lstrings.h"
64 #include "support/ExceptionMessage.h"
66 #include "support/lassert.h"
71 using namespace lyx::support
;
75 namespace Alert
= frontend::Alert
;
78 Inset
* createInsetHelper(Buffer
& buf
, FuncRequest
const & cmd
)
80 BufferParams
const & params
= buf
.params();
86 case LFUN_LINE_INSERT
:
89 case LFUN_NEWPAGE_INSERT
: {
90 string
const name
= cmd
.getArg(0);
91 InsetNewpageParams inp
;
92 if (name
.empty() || name
== "newpage")
93 inp
.kind
= InsetNewpageParams::NEWPAGE
;
94 else if (name
== "pagebreak")
95 inp
.kind
= InsetNewpageParams::PAGEBREAK
;
96 else if (name
== "clearpage")
97 inp
.kind
= InsetNewpageParams::CLEARPAGE
;
98 else if (name
== "cleardoublepage")
99 inp
.kind
= InsetNewpageParams::CLEARDOUBLEPAGE
;
100 return new InsetNewpage(inp
);
103 case LFUN_FLEX_INSERT
: {
104 string s
= cmd
.getArg(0);
105 return new InsetFlex(buf
, s
);
108 case LFUN_NOTE_INSERT
: {
109 string arg
= cmd
.getArg(0);
112 return new InsetNote(buf
, arg
);
115 case LFUN_BOX_INSERT
: {
116 string arg
= cmd
.getArg(0);
119 return new InsetBox(buf
, arg
);
122 case LFUN_BRANCH_INSERT
: {
123 docstring arg
= cmd
.argument();
125 arg
= from_ascii("none");
126 return new InsetBranch(buf
, InsetBranchParams(arg
));
129 case LFUN_PHANTOM_INSERT
: {
130 string arg
= cmd
.getArg(0);
133 return new InsetPhantom(buf
, arg
);
136 case LFUN_ERT_INSERT
:
137 return new InsetERT(buf
);
139 case LFUN_LISTING_INSERT
:
140 return new InsetListings(buf
);
142 case LFUN_FOOTNOTE_INSERT
:
143 return new InsetFoot(buf
);
145 case LFUN_MARGINALNOTE_INSERT
:
146 return new InsetMarginal(buf
);
148 case LFUN_OPTIONAL_INSERT
:
149 return new InsetOptArg(buf
);
151 case LFUN_FLOAT_INSERT
: {
152 // check if the float type exists
153 string
const argument
= to_utf8(cmd
.argument());
154 if (buf
.params().documentClass().floats().typeExist(argument
))
155 return new InsetFloat(buf
, argument
);
156 lyxerr
<< "Non-existent float type: " << argument
<< endl
;
159 case LFUN_FLOAT_WIDE_INSERT
: {
160 // check if the float type exists
161 string
const argument
= to_utf8(cmd
.argument());
162 if (params
.documentClass().floats().typeExist(argument
)) {
163 auto_ptr
<InsetFloat
> p(new InsetFloat(buf
, argument
));
167 lyxerr
<< "Non-existent float type: " << argument
<< endl
;
171 case LFUN_WRAP_INSERT
: {
172 string
const argument
= to_utf8(cmd
.argument());
173 if (argument
== "figure" || argument
== "table")
174 return new InsetWrap(buf
, argument
);
175 lyxerr
<< "Non-existent wrapfig type: " << argument
<< endl
;
179 case LFUN_INDEX_INSERT
: {
180 docstring arg
= cmd
.argument();
181 return new InsetIndex(buf
, InsetIndexParams(arg
));
184 case LFUN_NOMENCL_INSERT
: {
185 InsetCommandParams
icp(NOMENCL_CODE
);
186 icp
["symbol"] = cmd
.argument();
187 return new InsetNomencl(icp
);
190 case LFUN_TABULAR_INSERT
: {
191 if (cmd
.argument().empty())
193 istringstream
ss(to_utf8(cmd
.argument()));
200 return new InsetTabular(buf
, r
, c
);
203 case LFUN_CAPTION_INSERT
:
204 return new InsetCaption(buf
);
206 case LFUN_INDEX_PRINT
: {
207 InsetCommandParams
icp(INDEX_PRINT_CODE
);
208 icp
["type"] = cmd
.argument();
209 return new InsetPrintIndex(icp
);
212 case LFUN_NOMENCL_PRINT
: {
213 InsetCommandParams
icp(NOMENCL_PRINT_CODE
);
214 icp
["set_width"] = from_ascii("auto");
215 return new InsetPrintNomencl(icp
);
218 case LFUN_TOC_INSERT
:
219 return new InsetTOC(InsetCommandParams(TOC_CODE
));
221 case LFUN_INFO_INSERT
: {
222 InsetInfo
* inset
= new InsetInfo(buf
, to_utf8(cmd
.argument()));
227 case LFUN_INSET_INSERT
: {
228 string
const name
= cmd
.getArg(0);
229 InsetCode code
= insetCode(name
);
232 lyxerr
<< "No such inset '" << name
<< "'.";
236 InsetCommandParams
icp(code
);
237 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
238 return new InsetBibitem(buf
, icp
);
242 InsetCommandParams
icp(code
);
243 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
244 return new InsetBibtex(buf
, icp
);
248 InsetCommandParams
icp(code
);
249 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
250 return new InsetCitation(icp
);
254 return new InsetERT(buf
,
255 InsetERT::string2params(to_utf8(cmd
.argument())));
258 case LISTINGS_CODE
: {
259 InsetListingsParams par
;
260 InsetListings::string2params(to_utf8(cmd
.argument()), par
);
261 return new InsetListings(buf
, par
);
264 case EXTERNAL_CODE
: {
265 InsetExternalParams iep
;
266 InsetExternal::string2params(to_utf8(cmd
.argument()), buf
, iep
);
267 auto_ptr
<InsetExternal
> inset(new InsetExternal(buf
));
268 inset
->setBuffer(buf
);
269 inset
->setParams(iep
);
270 return inset
.release();
273 case GRAPHICS_CODE
: {
274 InsetGraphicsParams igp
;
275 InsetGraphics::string2params(to_utf8(cmd
.argument()), buf
, igp
);
276 auto_ptr
<InsetGraphics
> inset(new InsetGraphics(buf
));
277 inset
->setParams(igp
);
278 return inset
.release();
281 case HYPERLINK_CODE
: {
282 InsetCommandParams
icp(code
);
283 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
284 return new InsetHyperlink(icp
);
288 InsetCommandParams
icp(code
);
289 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
290 return new InsetInclude(icp
);
294 docstring arg
= cmd
.argument();
295 return new InsetIndex(buf
, InsetIndexParams(arg
));
298 case INDEX_PRINT_CODE
: {
299 InsetCommandParams
icp(code
);
300 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
301 return new InsetPrintIndex(icp
);
305 InsetCommandParams
icp(code
);
306 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
307 return new InsetNomencl(icp
);
311 InsetCommandParams
icp(code
);
312 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
313 return new InsetLabel(icp
);
317 InsetCommandParams
icp(code
);
318 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
319 return new InsetRef(buf
, icp
);
323 InsetSpaceParams isp
;
324 InsetSpace::string2params(to_utf8(cmd
.argument()), isp
);
325 return new InsetSpace(isp
);
329 InsetCommandParams
icp(code
);
330 InsetCommand::string2params(name
, to_utf8(cmd
.argument()), icp
);
331 return new InsetTOC(icp
);
336 InsetVSpace::string2params(to_utf8(cmd
.argument()), vspace
);
337 return new InsetVSpace(vspace
);
341 lyxerr
<< "Inset '" << name
<< "' not permitted with LFUN_INSET_INSERT."
346 } //end LFUN_INSET_INSERT
348 case LFUN_SPACE_INSERT
: {
349 string
const name
= cmd
.getArg(0);
350 string
const len
= cmd
.getArg(1);
352 lyxerr
<< "LyX function 'space-insert' needs an argument." << endl
;
355 InsetSpaceParams isp
;
356 // The tests for isp.math might be disabled after a file format change
357 if (name
== "normal")
358 isp
.kind
= InsetSpaceParams::NORMAL
;
359 else if (name
== "protected")
360 isp
.kind
= InsetSpaceParams::PROTECTED
;
361 else if (name
== "thin")
362 isp
.kind
= InsetSpaceParams::THIN
;
363 else if (isp
.math
&& name
== "med")
364 isp
.kind
= InsetSpaceParams::MEDIUM
;
365 else if (isp
.math
&& name
== "thick")
366 isp
.kind
= InsetSpaceParams::THICK
;
367 else if (name
== "quad")
368 isp
.kind
= InsetSpaceParams::QUAD
;
369 else if (name
== "qquad")
370 isp
.kind
= InsetSpaceParams::QQUAD
;
371 else if (name
== "enspace")
372 isp
.kind
= InsetSpaceParams::ENSPACE
;
373 else if (name
== "enskip")
374 isp
.kind
= InsetSpaceParams::ENSKIP
;
375 else if (name
== "negthinspace")
376 isp
.kind
= InsetSpaceParams::NEGTHIN
;
377 else if (isp
.math
&& name
== "negmedspace")
378 isp
.kind
= InsetSpaceParams::NEGMEDIUM
;
379 else if (isp
.math
&& name
== "negthickspace")
380 isp
.kind
= InsetSpaceParams::NEGTHICK
;
381 else if (name
== "hfill")
382 isp
.kind
= InsetSpaceParams::HFILL
;
383 else if (name
== "hfill*")
384 isp
.kind
= InsetSpaceParams::HFILL_PROTECTED
;
385 else if (name
== "dotfill")
386 isp
.kind
= InsetSpaceParams::DOTFILL
;
387 else if (name
== "hrulefill")
388 isp
.kind
= InsetSpaceParams::HRULEFILL
;
389 else if (name
== "hspace") {
390 if (len
.empty() || !isValidGlueLength(len
)) {
391 lyxerr
<< "LyX function 'space-insert hspace' "
392 << "needs a valid length argument." << endl
;
395 isp
.kind
= InsetSpaceParams::CUSTOM
;
396 isp
.length
= GlueLength(len
);
398 else if (name
== "hspace*") {
399 if (len
.empty() || !isValidGlueLength(len
)) {
400 lyxerr
<< "LyX function 'space-insert hspace*' "
401 << "needs a valid length argument." << endl
;
404 isp
.kind
= InsetSpaceParams::CUSTOM_PROTECTED
;
405 isp
.length
= GlueLength(len
);
408 lyxerr
<< "Wrong argument for LyX function 'space-insert'." << endl
;
411 return new InsetSpace(isp
);
419 } catch (ExceptionMessage
const & message
) {
420 if (message
.type_
== ErrorException
) {
421 // This should never happen!
422 Alert::error(message
.title_
, message
.details_
);
424 } else if (message
.type_
== WarningException
) {
425 Alert::warning(message
.title_
, message
.details_
);
434 Inset
* createInset(Buffer
& buf
, FuncRequest
const & cmd
)
436 Inset
* inset
= createInsetHelper(buf
, cmd
);
438 inset
->setBuffer(buf
);
443 Inset
* readInset(Lexer
& lex
, Buffer
const & buf
)
446 if (lex
.getString() != "\\begin_inset")
447 LYXERR0("Buffer::readInset: Consistency check failed.");
449 auto_ptr
<Inset
> inset
;
454 // test the different insets
456 // FIXME It would be better if we did not have this branch and could
457 // just do one massive switch for all insets. But at present, it's
458 // easier to do it this way, and we can't do the massive switch until
459 // the conversion mentioned below. Note that if we do want to do a
460 // single switch, we need to remove this "CommandInset" line---or
461 // replace it with a single "InsetType" line that would be used in all
463 if (tmptok
== "CommandInset") {
465 string
const insetType
= lex
.getString();
466 lex
.pushToken(insetType
);
468 InsetCode
const code
= insetCode(insetType
);
470 //FIXME If we do the one massive switch, we cannot do this here, since
471 //we do not know in advance that we're dealing with a command inset.
472 //Worst case, we could put it in each case below. Better, we could
473 //pass the lexer to the constructor and let the params be built there.
474 InsetCommandParams
inscmd(code
);
479 inset
.reset(new InsetBibitem(buf
, inscmd
));
482 inset
.reset(new InsetBibtex(buf
, inscmd
));
485 inset
.reset(new InsetCitation(inscmd
));
488 inset
.reset(new InsetHyperlink(inscmd
));
491 inset
.reset(new InsetInclude(inscmd
));
493 case INDEX_PRINT_CODE
:
494 inset
.reset(new InsetPrintIndex(inscmd
));
497 inset
.reset(new InsetLabel(inscmd
));
500 inset
.reset(new InsetNomencl(inscmd
));
502 case NOMENCL_PRINT_CODE
:
503 inset
.reset(new InsetPrintNomencl(inscmd
));
506 if (inscmd
["name"].empty() && inscmd
["reference"].empty())
508 inset
.reset(new InsetRef(buf
, inscmd
));
511 inset
.reset(new InsetTOC(inscmd
));
515 lyxerr
<< "unknown CommandInset '" << insetType
517 while (lex
.isOK() && lex
.getString() != "\\end_inset")
521 inset
->setBuffer(const_cast<Buffer
&>(buf
));
523 // FIXME This branch should be made to use inset codes as the preceding
524 // branch does. Unfortunately, that will take some doing. It requires
525 // converting the representation of the insets in LyX files so that they
526 // use the inset names listed in Inset.cpp. Then, as above, the inset names
527 // can be translated to inset codes using insetCode(). And the insets'
528 // write() routines should use insetName() rather than hardcoding it.
529 if (tmptok
== "Quotes") {
530 inset
.reset(new InsetQuotes(buf
));
531 } else if (tmptok
== "External") {
532 inset
.reset(new InsetExternal(const_cast<Buffer
&>(buf
)));
533 } else if (tmptok
== "FormulaMacro") {
534 inset
.reset(new MathMacroTemplate
);
535 } else if (tmptok
== "Formula") {
536 inset
.reset(new InsetMathHull
);
537 } else if (tmptok
== "Graphics") {
538 inset
.reset(new InsetGraphics(const_cast<Buffer
&>(buf
)));
539 } else if (tmptok
== "Note") {
540 inset
.reset(new InsetNote(buf
, tmptok
));
541 } else if (tmptok
== "Box") {
542 inset
.reset(new InsetBox(buf
, tmptok
));
543 } else if (tmptok
== "Flex") {
545 string s
= lex
.getString();
546 inset
.reset(new InsetFlex(buf
, s
));
547 } else if (tmptok
== "Branch") {
548 inset
.reset(new InsetBranch(buf
, InsetBranchParams()));
549 } else if (tmptok
== "Phantom") {
550 inset
.reset(new InsetPhantom(buf
, tmptok
));
551 } else if (tmptok
== "ERT") {
552 inset
.reset(new InsetERT(buf
));
553 } else if (tmptok
== "listings") {
554 inset
.reset(new InsetListings(buf
));
555 } else if (tmptok
== "space") {
556 inset
.reset(new InsetSpace
);
557 } else if (tmptok
== "Tabular") {
558 inset
.reset(new InsetTabular(const_cast<Buffer
&>(buf
)));
559 } else if (tmptok
== "Text") {
560 inset
.reset(new InsetText(buf
));
561 } else if (tmptok
== "VSpace") {
562 inset
.reset(new InsetVSpace
);
563 } else if (tmptok
== "Foot") {
564 inset
.reset(new InsetFoot(buf
));
565 } else if (tmptok
== "Marginal") {
566 inset
.reset(new InsetMarginal(buf
));
567 } else if (tmptok
== "Newpage") {
568 inset
.reset(new InsetNewpage
);
569 } else if (tmptok
== "Newline") {
570 inset
.reset(new InsetNewline
);
571 } else if (tmptok
== "OptArg") {
572 inset
.reset(new InsetOptArg(buf
));
573 } else if (tmptok
== "Float") {
575 string tmptok
= lex
.getString();
576 inset
.reset(new InsetFloat(buf
, tmptok
));
577 } else if (tmptok
== "Wrap") {
579 string tmptok
= lex
.getString();
580 inset
.reset(new InsetWrap(buf
, tmptok
));
581 } else if (tmptok
== "Caption") {
582 inset
.reset(new InsetCaption(buf
));
583 } else if (tmptok
== "Index") {
584 inset
.reset(new InsetIndex(buf
, InsetIndexParams()));
585 } else if (tmptok
== "FloatList") {
586 inset
.reset(new InsetFloatList
);
587 } else if (tmptok
== "Info") {
588 inset
.reset(new InsetInfo(buf
));
590 lyxerr
<< "unknown Inset type '" << tmptok
592 while (lex
.isOK() && lex
.getString() != "\\end_inset")
597 // Set the buffer reference for proper parsing of some insets
598 // (InsetCollapsable for example)
599 inset
->setBuffer(const_cast<Buffer
&>(buf
));
601 // Set again the buffer for insets that are created inside this inset
602 // (InsetMathHull for example).
603 inset
->setBuffer(const_cast<Buffer
&>(buf
));
605 return inset
.release();