1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * This file is Copyright 1996-1999
12 * ======================================================
23 #include <sys/types.h>
33 #pragma implementation "buffer.h"
37 #include "bufferlist.h"
39 #include "lyx_gui_misc.h"
40 #include "LyXAction.h"
43 #include "tex-strings.h"
45 #include "bufferview_funcs.h"
46 #include "minibuffer.h"
49 #include "mathed/formulamacro.h"
50 #include "insets/lyxinset.h"
51 #include "insets/inseterror.h"
52 #include "insets/insetlabel.h"
53 #include "insets/insetref.h"
54 #include "insets/inseturl.h"
55 #include "insets/insetinfo.h"
56 #include "insets/insetquotes.h"
57 #include "insets/insetlatexaccent.h"
58 #include "insets/insetbib.h"
59 #include "insets/insetcite.h"
60 #include "insets/insetexternal.h"
61 #include "insets/insetindex.h"
62 #include "insets/insetinclude.h"
63 #include "insets/insettoc.h"
64 #include "insets/insetparent.h"
65 #include "insets/insetspecialchar.h"
66 #include "insets/figinset.h"
67 #include "insets/insettext.h"
68 #include "insets/insetert.h"
69 #include "insets/insetgraphics.h"
70 #include "insets/insetfoot.h"
71 #include "insets/insetmarginal.h"
72 #include "insets/insetminipage.h"
73 #include "insets/insetfloat.h"
74 #include "insets/insetlist.h"
75 #include "insets/insettabular.h"
76 #include "insets/insettheorem.h"
77 #include "insets/insetcaption.h"
78 #include "support/filetools.h"
79 #include "support/path.h"
84 #include "LaTeXFeatures.h"
85 #include "support/syscall.h"
86 #include "support/lyxlib.h"
87 #include "support/FileInfo.h"
88 #include "support/lyxmanip.h"
92 #include "lyx_gui_misc.h" // WarnReadonly()
93 #include "frontends/Dialogs.h"
97 #include "converter.h"
107 using std::make_pair;
112 // all these externs should eventually be removed.
113 extern BufferList bufferlist;
115 extern LyXAction lyxaction;
118 static const int LYX_FORMAT = 218;
120 extern int tex_code_break_column;
123 Buffer::Buffer(string const & file, bool ronly)
125 lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
127 filepath = OnlyPath(file);
136 if (read_only || (lyxrc.use_tempdir)) {
137 tmppath = CreateBufferTmpDir();
138 } else tmppath.erase();
144 lyxerr[Debug::INFO] << "Buffer::~Buffer()" << endl;
145 // here the buffer should take care that it is
146 // saved properly, before it goes into the void.
148 // make sure that views using this buffer
153 if (!tmppath.empty()) {
154 DestroyBufferTmpDir(tmppath);
157 LyXParagraph * par = paragraph;
158 LyXParagraph * tmppar;
167 tmppar = par->next();
176 string const Buffer::getLatexName(bool no_path) const
179 return OnlyFilename(ChangeExtension(MakeLatexName(filename),
182 return ChangeExtension(MakeLatexName(filename),
186 pair<Buffer::LogType, string> const Buffer::getLogName(void) const
188 string filename, fname, bname, path;
190 filename = getLatexName(false);
192 if (filename.empty())
193 return make_pair(Buffer::latexlog, string());
195 path = OnlyPath(filename);
197 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1))
200 fname = AddName(path, OnlyFilename(ChangeExtension(filename, ".log")));
201 bname = AddName(path, OnlyFilename(ChangeExtension(filename,
202 formats.Extension("literate") + ".out")));
204 // If no Latex log or Build log is newer, show Build log
206 FileInfo f_fi(fname), b_fi(bname);
209 (!f_fi.exist() || f_fi.getModificationTime() < b_fi.getModificationTime())) {
210 lyxerr[Debug::FILES] << "Log name calculated as : " << bname << endl;
211 return make_pair(Buffer::buildlog, bname);
213 lyxerr[Debug::FILES] << "Log name calculated as : " << fname << endl;
214 return make_pair(Buffer::latexlog, fname);
217 void Buffer::setReadonly(bool flag)
219 if (read_only != flag) {
222 users->owner()->getDialogs()->updateBufferDependent(false);
225 WarnReadonly(filename);
230 bool Buffer::saveParamsAsDefaults() // const
232 string const fname = AddName(AddPath(user_lyxdir, "templates/"),
234 Buffer defaults = Buffer(fname);
236 // Use the current buffer's parameters as default
237 defaults.params = params;
239 // add an empty paragraph. Is this enough?
240 defaults.paragraph = new LyXParagraph;
242 return defaults.writeFile(defaults.filename, false);
246 /// Update window titles of all users
247 // Should work on a list
248 void Buffer::updateTitles() const
250 if (users) users->owner()->updateWindowTitle();
254 /// Reset autosave timer of all users
255 // Should work on a list
256 void Buffer::resetAutosaveTimers() const
258 if (users) users->owner()->resetAutosaveTimer();
262 void Buffer::setFileName(string const & newfile)
264 filename = MakeAbsPath(newfile);
265 filepath = OnlyPath(filename);
266 setReadonly(IsFileWriteable(filename) == 0);
271 // candidate for move to BufferView
272 // (at least some parts in the beginning of the func)
275 // changed to be public and have one parameter
276 // if par = 0 normal behavior
277 // else insert behavior
278 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
279 bool Buffer::readLyXformat2(LyXLex & lex, LyXParagraph * par)
282 char depth = 0; // signed or unsigned?
284 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
285 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
287 bool the_end_read = false;
289 LyXParagraph * return_par = 0;
290 LyXFont font(LyXFont::ALL_INHERIT, params.language);
291 if (file_format < 216 && params.language->lang() == "hebrew")
292 font.setLanguage(default_language);
293 // If we are inserting, we cheat and get a token in advance
294 bool has_token = false;
298 par = new LyXParagraph;
300 users->text->BreakParagraph(users);
301 return_par = users->text->FirstParagraph();
304 // We don't want to adopt the parameters from the
305 // document we insert, so we skip until the text begins:
308 pretoken = lex.GetString();
309 if (pretoken == "\\layout") {
321 pretoken = lex.GetString();
324 if (pretoken.empty()) continue;
327 parseSingleLyXformat2Token(lex, par, return_par,
328 pretoken, pos, depth,
340 paragraph = return_par;
346 // We'll remove this later. (Lgb)
347 static string last_inset_read;
351 Buffer::parseSingleLyXformat2Token(LyXLex & lex, LyXParagraph *& par,
352 LyXParagraph *& return_par,
353 string const & token, int & pos,
354 char & depth, LyXFont & font
356 , LyXParagraph::footnote_flag & footnoteflag,
357 LyXParagraph::footnote_kind & footnotekind
361 bool the_end_read = false;
363 if (token[0] != '\\') {
364 for (string::const_iterator cit = token.begin();
365 cit != token.end(); ++cit) {
366 par->InsertChar(pos, (*cit), font);
369 } else if (token == "\\i") {
370 Inset * inset = new InsetLatexAccent;
371 inset->Read(this, lex);
372 par->InsertInset(pos, inset, font);
374 } else if (token == "\\layout") {
379 par = new LyXParagraph(par);
383 string const layoutname = lex.GetString();
384 pair<bool, LyXTextClass::LayoutList::size_type> pp
385 = textclasslist.NumberOfLayout(params.textclass,
388 par->layout = pp.second;
389 } else { // layout not found
390 // use default layout "Standard" (0)
393 // Test whether the layout is obsolete.
394 LyXLayout const & layout =
395 textclasslist.Style(params.textclass,
397 if (!layout.obsoleted_by().empty())
399 textclasslist.NumberOfLayout(params.textclass,
400 layout.obsoleted_by()).second;
402 par->footnoteflag = footnoteflag;
403 par->footnotekind = footnotekind;
405 par->params.depth(depth);
406 font = LyXFont(LyXFont::ALL_INHERIT, params.language);
407 if (file_format < 216 && params.language->lang() == "hebrew")
408 font.setLanguage(default_language);
410 } else if (token == "\\end_float") {
415 par = new LyXParagraph(par);
417 footnotekind = LyXParagraph::FOOTNOTE;
418 footnoteflag = LyXParagraph::NO_FOOTNOTE;
421 par->layout = LYX_DUMMY_LAYOUT;
422 font = LyXFont(LyXFont::ALL_INHERIT, params.language);
423 if (file_format < 216 && params.language->lang() == "hebrew")
424 font.setLanguage(default_language);
425 } else if (token == "\\begin_float") {
426 int tmpret = lex.FindToken(string_footnotekinds);
427 if (tmpret == -1) ++tmpret;
428 if (tmpret != LYX_LAYOUT_DEFAULT)
429 footnotekind = static_cast<LyXParagraph::footnote_kind>(tmpret); // bad
430 if (footnotekind == LyXParagraph::FOOTNOTE
431 || footnotekind == LyXParagraph::MARGIN)
432 footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
434 footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
436 } else if (token == "\\begin_float") {
437 // This is the compability reader, unfinished but tested.
440 string const tmptok = lex.GetString();
441 //lyxerr << "old float: " << tmptok << endl;
446 if (tmptok == "footnote") {
447 inset = new InsetFoot;
448 } else if (tmptok == "margin") {
449 inset = new InsetMarginal;
450 } else if (tmptok == "fig") {
451 inset = new InsetFloat("figure");
452 old_float += "placement htbp\n";
453 } else if (tmptok == "tab") {
454 inset = new InsetFloat("table");
455 old_float += "placement htbp\n";
456 } else if (tmptok == "alg") {
457 inset = new InsetFloat("algorithm");
458 old_float += "placement htbp\n";
459 } else if (tmptok == "wide-fig") {
460 InsetFloat * tmp = new InsetFloat("figure");
463 old_float += "placement htbp\n";
464 } else if (tmptok == "wide-tab") {
465 InsetFloat * tmp = new InsetFloat("table");
468 old_float += "placement htbp\n";
471 if (!inset) return false; // no end read yet
473 old_float += "collapsed true\n";
475 // Here we need to check for \end_deeper and handle that
476 // before we do the footnote parsing.
477 // This _is_ a hack! (Lgb)
480 string const tmp = lex.GetString();
481 if (tmp == "\\end_deeper") {
482 lyxerr << "\\end_deeper caught!" << endl;
484 lex.printError("\\end_deeper: "
485 "depth is already null");
496 old_float += lex.getLongString("\\end_float");
497 old_float += "\n\\end_inset\n";
498 //lyxerr << "float body: " << old_float << endl;
500 istringstream istr(old_float);
503 nylex.setStream(istr);
505 inset->Read(this, nylex);
506 par->InsertInset(pos, inset, font);
509 } else if (token == "\\begin_deeper") {
511 } else if (token == "\\end_deeper") {
513 lex.printError("\\end_deeper: "
514 "depth is already null");
518 } else if (token == "\\begin_preamble") {
519 params.readPreamble(lex);
520 } else if (token == "\\textclass") {
522 pair<bool, LyXTextClassList::size_type> pp =
523 textclasslist.NumberOfClass(lex.GetString());
525 params.textclass = pp.second;
527 WriteAlert(string(_("Textclass error")),
528 string(_("The document uses an unknown textclass \"")) +
529 lex.GetString() + string("\"."),
530 string(_("LyX will not be able to produce output correctly.")));
531 params.textclass = 0;
533 if (!textclasslist.Load(params.textclass)) {
534 // if the textclass wasn't loaded properly
535 // we need to either substitute another
536 // or stop loading the file.
537 // I can substitute but I don't see how I can
538 // stop loading... ideas?? ARRae980418
539 WriteAlert(_("Textclass Loading Error!"),
540 string(_("Can't load textclass ")) +
541 textclasslist.NameOfClass(params.textclass),
542 _("-- substituting default"));
543 params.textclass = 0;
545 } else if (token == "\\options") {
547 params.options = lex.GetString();
548 } else if (token == "\\language") {
549 params.readLanguage(lex);
550 } else if (token == "\\fontencoding") {
552 } else if (token == "\\inputencoding") {
554 params.inputenc = lex.GetString();
555 } else if (token == "\\graphics") {
556 params.readGraphicsDriver(lex);
557 } else if (token == "\\fontscheme") {
559 params.fonts = lex.GetString();
560 } else if (token == "\\noindent") {
561 par->params.noindent(true);
562 } else if (token == "\\fill_top") {
563 par->params.spaceTop(VSpace(VSpace::VFILL));
564 } else if (token == "\\fill_bottom") {
565 par->params.spaceBottom(VSpace(VSpace::VFILL));
566 } else if (token == "\\line_top") {
567 par->params.lineTop(true);
568 } else if (token == "\\line_bottom") {
569 par->params.lineBottom(true);
570 } else if (token == "\\pagebreak_top") {
571 par->params.pagebreakTop(true);
572 } else if (token == "\\pagebreak_bottom") {
573 par->params.pagebreakBottom(true);
574 } else if (token == "\\start_of_appendix") {
575 par->params.startOfAppendix(true);
576 } else if (token == "\\paragraph_separation") {
577 int tmpret = lex.FindToken(string_paragraph_separation);
578 if (tmpret == -1) ++tmpret;
579 if (tmpret != LYX_LAYOUT_DEFAULT)
580 params.paragraph_separation =
581 static_cast<BufferParams::PARSEP>(tmpret);
582 } else if (token == "\\defskip") {
584 params.defskip = VSpace(lex.GetString());
585 } else if (token == "\\epsfig") { // obsolete
586 // Indeed it is obsolete, but we HAVE to be backwards
587 // compatible until 0.14, because otherwise all figures
588 // in existing documents are irretrivably lost. (Asger)
589 params.readGraphicsDriver(lex);
590 } else if (token == "\\quotes_language") {
591 int tmpret = lex.FindToken(string_quotes_language);
592 if (tmpret == -1) ++tmpret;
593 if (tmpret != LYX_LAYOUT_DEFAULT) {
594 InsetQuotes::quote_language tmpl =
595 InsetQuotes::EnglishQ;
598 tmpl = InsetQuotes::EnglishQ;
601 tmpl = InsetQuotes::SwedishQ;
604 tmpl = InsetQuotes::GermanQ;
607 tmpl = InsetQuotes::PolishQ;
610 tmpl = InsetQuotes::FrenchQ;
613 tmpl = InsetQuotes::DanishQ;
616 params.quotes_language = tmpl;
618 } else if (token == "\\quotes_times") {
620 switch (lex.GetInteger()) {
622 params.quotes_times = InsetQuotes::SingleQ;
625 params.quotes_times = InsetQuotes::DoubleQ;
628 } else if (token == "\\papersize") {
629 int tmpret = lex.FindToken(string_papersize);
633 params.papersize2 = tmpret;
634 } else if (token == "\\paperpackage") {
635 int tmpret = lex.FindToken(string_paperpackages);
638 params.paperpackage = BufferParams::PACKAGE_NONE;
640 params.paperpackage = tmpret;
641 } else if (token == "\\use_geometry") {
643 params.use_geometry = lex.GetInteger();
644 } else if (token == "\\use_amsmath") {
646 params.use_amsmath = lex.GetInteger();
647 } else if (token == "\\paperorientation") {
648 int tmpret = lex.FindToken(string_orientation);
649 if (tmpret == -1) ++tmpret;
650 if (tmpret != LYX_LAYOUT_DEFAULT)
651 params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
652 } else if (token == "\\paperwidth") {
654 params.paperwidth = lex.GetString();
655 } else if (token == "\\paperheight") {
657 params.paperheight = lex.GetString();
658 } else if (token == "\\leftmargin") {
660 params.leftmargin = lex.GetString();
661 } else if (token == "\\topmargin") {
663 params.topmargin = lex.GetString();
664 } else if (token == "\\rightmargin") {
666 params.rightmargin = lex.GetString();
667 } else if (token == "\\bottommargin") {
669 params.bottommargin = lex.GetString();
670 } else if (token == "\\headheight") {
672 params.headheight = lex.GetString();
673 } else if (token == "\\headsep") {
675 params.headsep = lex.GetString();
676 } else if (token == "\\footskip") {
678 params.footskip = lex.GetString();
679 } else if (token == "\\paperfontsize") {
681 params.fontsize = strip(lex.GetString());
682 } else if (token == "\\papercolumns") {
684 params.columns = lex.GetInteger();
685 } else if (token == "\\papersides") {
687 switch (lex.GetInteger()) {
689 case 1: params.sides = LyXTextClass::OneSide; break;
690 case 2: params.sides = LyXTextClass::TwoSides; break;
692 } else if (token == "\\paperpagestyle") {
694 params.pagestyle = strip(lex.GetString());
695 } else if (token == "\\bullet") {
697 int const index = lex.GetInteger();
699 int temp_int = lex.GetInteger();
700 params.user_defined_bullets[index].setFont(temp_int);
701 params.temp_bullets[index].setFont(temp_int);
703 temp_int = lex.GetInteger();
704 params.user_defined_bullets[index].setCharacter(temp_int);
705 params.temp_bullets[index].setCharacter(temp_int);
707 temp_int = lex.GetInteger();
708 params.user_defined_bullets[index].setSize(temp_int);
709 params.temp_bullets[index].setSize(temp_int);
711 string const temp_str = lex.GetString();
712 if (temp_str != "\\end_bullet") {
713 // this element isn't really necessary for
714 // parsing but is easier for humans
715 // to understand bullets. Put it back and
716 // set a debug message?
717 lex.printError("\\end_bullet expected, got" + temp_str);
718 //how can I put it back?
720 } else if (token == "\\bulletLaTeX") {
722 int const index = lex.GetInteger();
724 string temp_str = lex.GetString();
726 while (temp_str != "\\end_bullet") {
727 // this loop structure is needed when user
728 // enters an empty string since the first
729 // thing returned will be the \\end_bullet
731 // if the LaTeX entry has spaces. Each element
732 // therefore needs to be read in turn
735 temp_str = lex.GetString();
737 params.user_defined_bullets[index].setText(sum_str);
738 params.temp_bullets[index].setText(sum_str);
739 } else if (token == "\\secnumdepth") {
741 params.secnumdepth = lex.GetInteger();
742 } else if (token == "\\tocdepth") {
744 params.tocdepth = lex.GetInteger();
745 } else if (token == "\\spacing") {
747 string const tmp = strip(lex.GetString());
748 Spacing::Space tmp_space = Spacing::Default;
750 if (tmp == "single") {
751 tmp_space = Spacing::Single;
752 } else if (tmp == "onehalf") {
753 tmp_space = Spacing::Onehalf;
754 } else if (tmp == "double") {
755 tmp_space = Spacing::Double;
756 } else if (tmp == "other") {
758 tmp_space = Spacing::Other;
759 tmp_val = lex.GetFloat();
761 lex.printError("Unknown spacing token: '$$Token'");
763 // Small hack so that files written with klyx will be
766 par->params.spacing(Spacing(tmp_space, tmp_val));
768 params.spacing.set(tmp_space, tmp_val);
770 } else if (token == "\\paragraph_spacing") {
772 string const tmp = strip(lex.GetString());
773 if (tmp == "single") {
774 par->params.spacing(Spacing(Spacing::Single));
775 } else if (tmp == "onehalf") {
776 par->params.spacing(Spacing(Spacing::Onehalf));
777 } else if (tmp == "double") {
778 par->params.spacing(Spacing(Spacing::Double));
779 } else if (tmp == "other") {
781 par->params.spacing(Spacing(Spacing::Other,
784 lex.printError("Unknown spacing token: '$$Token'");
786 } else if (token == "\\float_placement") {
788 params.float_placement = lex.GetString();
789 } else if (token == "\\family") {
791 font.setLyXFamily(lex.GetString());
792 } else if (token == "\\series") {
794 font.setLyXSeries(lex.GetString());
795 } else if (token == "\\shape") {
797 font.setLyXShape(lex.GetString());
798 } else if (token == "\\size") {
800 font.setLyXSize(lex.GetString());
801 } else if (token == "\\latex") {
803 string const tok = lex.GetString();
804 // This is dirty, but gone with LyX3. (Asger)
805 if (tok == "no_latex")
806 font.setLatex(LyXFont::OFF);
807 else if (tok == "latex")
808 font.setLatex(LyXFont::ON);
809 else if (tok == "default")
810 font.setLatex(LyXFont::INHERIT);
812 lex.printError("Unknown LaTeX font flag "
814 } else if (token == "\\lang") {
816 string const tok = lex.GetString();
817 Language const * lang = languages.getLanguage(tok);
819 font.setLanguage(lang);
821 font.setLanguage(params.language);
822 lex.printError("Unknown language `$$Token'");
824 } else if (token == "\\numeric") {
826 font.setNumber(font.setLyXMisc(lex.GetString()));
827 } else if (token == "\\emph") {
829 font.setEmph(font.setLyXMisc(lex.GetString()));
830 } else if (token == "\\bar") {
832 string const tok = lex.GetString();
833 // This is dirty, but gone with LyX3. (Asger)
835 font.setUnderbar(LyXFont::ON);
836 else if (tok == "no")
837 font.setUnderbar(LyXFont::OFF);
838 else if (tok == "default")
839 font.setUnderbar(LyXFont::INHERIT);
841 lex.printError("Unknown bar font flag "
843 } else if (token == "\\noun") {
845 font.setNoun(font.setLyXMisc(lex.GetString()));
846 } else if (token == "\\color") {
848 font.setLyXColor(lex.GetString());
849 } else if (token == "\\align") {
850 int tmpret = lex.FindToken(string_align);
851 if (tmpret == -1) ++tmpret;
852 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
853 int const tmpret2 = int(pow(2.0, tmpret));
854 //lyxerr << "Tmpret2 = " << tmpret2 << endl;
855 par->params.align(LyXAlignment(tmpret2));
857 } else if (token == "\\added_space_top") {
859 par->params.spaceTop(VSpace(lex.GetString()));
860 } else if (token == "\\added_space_bottom") {
862 par->params.spaceBottom(VSpace(lex.GetString()));
863 } else if (token == "\\pextra_type") {
865 par->params.pextraType(lex.GetInteger());
866 } else if (token == "\\pextra_width") {
868 par->params.pextraWidth(lex.GetString());
869 } else if (token == "\\pextra_widthp") {
871 par->params.pextraWidthp(lex.GetString());
872 } else if (token == "\\pextra_alignment") {
874 par->params.pextraAlignment(lex.GetInteger());
875 } else if (token == "\\pextra_hfill") {
877 par->params.pextraHfill(lex.GetInteger());
878 } else if (token == "\\pextra_start_minipage") {
880 par->params.pextraStartMinipage(lex.GetInteger());
881 } else if (token == "\\labelwidthstring") {
883 par->params.labelWidthString(lex.GetString());
884 // do not delete this token, it is still needed!
885 } else if (token == "\\end_inset") {
886 lyxerr << "Solitary \\end_inset. Missing \\begin_inset?.\n"
887 << "Last inset read was: " << last_inset_read
889 // Simply ignore this. The insets do not have
891 // But insets should read it, it is a part of
892 // the inset isn't it? Lgb.
893 } else if (token == "\\begin_inset") {
894 readInset(lex, par, pos, font);
895 } else if (token == "\\SpecialChar") {
896 LyXLayout const & layout =
897 textclasslist.Style(params.textclass,
900 // Insets don't make sense in a free-spacing context! ---Kayvan
901 if (layout.free_spacing) {
904 string next_token = lex.GetString();
905 if (next_token == "\\-") {
906 par->InsertChar(pos, '-', font);
907 } else if (next_token == "\\protected_separator"
908 || next_token == "~") {
909 par->InsertChar(pos, ' ', font);
911 lex.printError("Token `$$Token' "
913 "paragraph layout!");
918 Inset * inset = new InsetSpecialChar;
919 inset->Read(this, lex);
920 par->InsertInset(pos, inset, font);
923 } else if (token == "\\newline") {
924 par->InsertChar(pos, LyXParagraph::META_NEWLINE, font);
926 } else if (token == "\\LyXTable") {
927 Inset * inset = new InsetTabular(*this);
928 inset->Read(this, lex);
929 par->InsertInset(pos, inset, font);
931 } else if (token == "\\hfill") {
932 par->InsertChar(pos, LyXParagraph::META_HFILL, font);
934 } else if (token == "\\protected_separator") { // obsolete
935 // This is a backward compability thingie. (Lgb)
936 // Remove it later some time...introduced with fileformat
938 LyXLayout const & layout =
939 textclasslist.Style(params.textclass,
942 if (layout.free_spacing) {
943 par->InsertChar(pos, ' ', font);
945 Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
946 par->InsertInset(pos, inset, font);
949 } else if (token == "\\bibitem") { // ale970302
951 InsetCommandParams p("bibitem", "dummy");
952 par->bibkey = new InsetBibKey(p);
954 par->bibkey->Read(this, lex);
955 } else if (token == "\\backslash") {
956 par->InsertChar(pos, '\\', font);
958 } else if (token == "\\the_end") {
961 // This should be insurance for the future: (Asger)
962 lex.printError("Unknown token `$$Token'. "
963 "Inserting as text.");
964 string::const_iterator cit = token.begin();
965 string::const_iterator end = token.end();
966 for (; cit != end; ++cit) {
967 par->InsertChar(pos, (*cit), font);
975 void Buffer::readInset(LyXLex & lex, LyXParagraph *& par,
976 int & pos, LyXFont & font)
979 if (lex.GetString() != "\\begin_inset") {
980 lyxerr << "Buffer::readInset: Consistency check failed."
987 string const tmptok = lex.GetString();
988 last_inset_read = tmptok;
990 // test the different insets
991 if (tmptok == "LatexCommand") {
992 InsetCommandParams inscmd;
995 if (inscmd.getCmdName() == "cite") {
996 inset = new InsetCitation(inscmd);
997 } else if (inscmd.getCmdName() == "bibitem") {
998 lex.printError("Wrong place for bibitem");
999 inset = new InsetBibKey(inscmd);
1000 } else if (inscmd.getCmdName() == "BibTeX") {
1001 inset = new InsetBibtex(inscmd);
1002 } else if (inscmd.getCmdName() == "index") {
1003 inset = new InsetIndex(inscmd);
1004 } else if (inscmd.getCmdName() == "include") {
1005 inset = new InsetInclude(inscmd, *this);
1006 } else if (inscmd.getCmdName() == "label") {
1007 inset = new InsetLabel(inscmd);
1008 } else if (inscmd.getCmdName() == "url"
1009 || inscmd.getCmdName() == "htmlurl") {
1010 inset = new InsetUrl(inscmd);
1011 } else if (inscmd.getCmdName() == "ref"
1012 || inscmd.getCmdName() == "pageref"
1013 || inscmd.getCmdName() == "vref"
1014 || inscmd.getCmdName() == "vpageref"
1015 || inscmd.getCmdName() == "prettyref") {
1016 if (!inscmd.getOptions().empty()
1017 || !inscmd.getContents().empty()) {
1018 inset = new InsetRef(inscmd, *this);
1020 } else if (inscmd.getCmdName() == "tableofcontents"
1021 || inscmd.getCmdName() == "listofalgorithms"
1022 || inscmd.getCmdName() == "listoffigures"
1023 || inscmd.getCmdName() == "listoftables") {
1024 inset = new InsetTOC(inscmd);
1025 } else if (inscmd.getCmdName() == "printindex") {
1026 inset = new InsetPrintIndex(inscmd);
1027 } else if (inscmd.getCmdName() == "lyxparent") {
1028 inset = new InsetParent(inscmd, *this);
1031 if (tmptok == "Quotes") {
1032 inset = new InsetQuotes;
1033 } else if (tmptok == "External") {
1034 inset = new InsetExternal;
1035 } else if (tmptok == "FormulaMacro") {
1036 inset = new InsetFormulaMacro;
1037 } else if (tmptok == "Formula") {
1038 inset = new InsetFormula;
1039 } else if (tmptok == "Figure") {
1040 inset = new InsetFig(100, 100, *this);
1041 } else if (tmptok == "Info") {
1042 inset = new InsetInfo;
1043 } else if (tmptok == "Include") {
1044 InsetCommandParams p( "Include" );
1045 inset = new InsetInclude(p, *this);
1046 } else if (tmptok == "ERT") {
1047 inset = new InsetERT;
1048 } else if (tmptok == "Tabular") {
1049 inset = new InsetTabular(*this);
1050 } else if (tmptok == "Text") {
1051 inset = new InsetText;
1052 } else if (tmptok == "Foot") {
1053 inset = new InsetFoot;
1054 } else if (tmptok == "Marginal") {
1055 inset = new InsetMarginal;
1056 } else if (tmptok == "Minipage") {
1057 inset = new InsetMinipage;
1058 } else if (tmptok == "Float") {
1060 string tmptok = lex.GetString();
1061 inset = new InsetFloat(tmptok);
1062 } else if (tmptok == "List") {
1063 inset = new InsetList;
1064 } else if (tmptok == "Theorem") {
1065 inset = new InsetList;
1066 } else if (tmptok == "Caption") {
1067 inset = new InsetCaption;
1068 } else if (tmptok == "GRAPHICS") {
1069 inset = new InsetGraphics;
1072 if (inset) inset->Read(this, lex);
1076 par->InsertInset(pos, inset, font);
1082 bool Buffer::readFile(LyXLex & lex, LyXParagraph * par)
1086 string const token(lex.GetString());
1087 if (token == "\\lyxformat") { // the first token _must_ be...
1089 string tmp_format = lex.GetString();
1090 //lyxerr << "LyX Format: `" << tmp_format << "'" << endl;
1091 // if present remove ".," from string.
1092 string::size_type dot = tmp_format.find_first_of(".,");
1093 //lyxerr << " dot found at " << dot << endl;
1094 if (dot != string::npos)
1095 tmp_format.erase(dot, 1);
1096 file_format = strToInt(tmp_format);
1097 if (file_format == LYX_FORMAT) {
1099 } else if (file_format > LYX_FORMAT) {
1101 WriteAlert(_("Warning!"),
1102 _("LyX file format is newer that what"),
1103 _("is supported in this LyX version. Expect some problems."));
1105 } else if (file_format < LYX_FORMAT) {
1107 if (file_format < 200) {
1108 WriteAlert(_("ERROR!"),
1109 _("Old LyX file format found. "
1110 "Use LyX 0.10.x to read this!"));
1114 bool the_end = readLyXformat2(lex, par);
1116 // the_end was added in 213
1117 if (file_format < 213)
1121 WriteAlert(_("Warning!"),
1122 _("Reading of document is not complete"),
1123 _("Maybe the document is truncated"));
1125 } else { // "\\lyxformat" not found
1126 WriteAlert(_("ERROR!"), _("Not a LyX file!"));
1129 WriteAlert(_("ERROR!"), _("Unable to read file!"));
1135 // Should probably be moved to somewhere else: BufferView? LyXView?
1136 bool Buffer::save() const
1138 // We don't need autosaves in the immediate future. (Asger)
1139 resetAutosaveTimers();
1143 if (lyxrc.make_backup) {
1144 s = fileName() + '~';
1145 if (!lyxrc.backupdir_path.empty())
1146 s = AddName(lyxrc.backupdir_path,
1147 subst(CleanupPath(s),'/','!'));
1149 // Rename is the wrong way of making a backup,
1150 // this is the correct way.
1151 /* truss cp fil fil2:
1152 lstat("LyXVC3.lyx", 0xEFFFF898) Err#2 ENOENT
1153 stat("LyXVC.lyx", 0xEFFFF688) = 0
1154 open("LyXVC.lyx", O_RDONLY) = 3
1155 open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1156 fstat(4, 0xEFFFF508) = 0
1157 fstat(3, 0xEFFFF508) = 0
1158 read(3, " # T h i s f i l e w".., 8192) = 5579
1159 write(4, " # T h i s f i l e w".., 5579) = 5579
1160 read(3, 0xEFFFD4A0, 8192) = 0
1163 chmod("LyXVC3.lyx", 0100644) = 0
1164 lseek(0, 0, SEEK_CUR) = 46440
1168 // Should proabaly have some more error checking here.
1169 // Should be cleaned up in 0.13, at least a bit.
1170 // Doing it this way, also makes the inodes stay the same.
1171 // This is still not a very good solution, in particular we
1172 // might loose the owner of the backup.
1173 FileInfo finfo(fileName());
1174 if (finfo.exist()) {
1175 mode_t fmode = finfo.getMode();
1176 struct utimbuf times = {
1177 finfo.getAccessTime(),
1178 finfo.getModificationTime() };
1180 ifstream ifs(fileName().c_str());
1181 ofstream ofs(s.c_str(), ios::out|ios::trunc);
1186 ::chmod(s.c_str(), fmode);
1188 if (::utime(s.c_str(), ×)) {
1189 lyxerr << "utime error." << endl;
1192 lyxerr << "LyX was not able to make "
1193 "backupcopy. Beware." << endl;
1198 if (writeFile(fileName(), false)) {
1200 removeAutosaveFile(fileName());
1202 // Saving failed, so backup is not backup
1203 if (lyxrc.make_backup) {
1204 lyx::rename(s, fileName());
1212 // Returns false if unsuccesful
1213 bool Buffer::writeFile(string const & fname, bool flag) const
1215 // if flag is false writeFile will not create any GUI
1216 // warnings, only cerr.
1217 // Needed for autosave in background or panic save (Matthias 120496)
1219 if (read_only && (fname == filename)) {
1220 // Here we should come with a question if we should
1221 // perform the write anyway.
1223 lyxerr << _("Error! Document is read-only: ")
1226 WriteAlert(_("Error! Document is read-only: "),
1231 FileInfo finfo(fname);
1232 if (finfo.exist() && !finfo.writable()) {
1233 // Here we should come with a question if we should
1234 // try to do the save anyway. (i.e. do a chmod first)
1236 lyxerr << _("Error! Cannot write file: ")
1239 WriteFSAlert(_("Error! Cannot write file: "),
1244 ofstream ofs(fname.c_str());
1247 lyxerr << _("Error! Cannot open file: ")
1250 WriteFSAlert(_("Error! Cannot open file: "),
1256 // Use the standard "C" locale for file output.
1257 ofs.imbue(std::locale::classic());
1260 // The top of the file should not be written by params.
1262 // write out a comment in the top of the file
1263 ofs << '#' << LYX_DOCVERSION
1264 << " created this file. For more info see http://www.lyx.org/\n"
1265 << "\\lyxformat " << LYX_FORMAT << "\n";
1267 // now write out the buffer paramters.
1268 params.writeFile(ofs);
1270 char footnoteflag = 0;
1273 // this will write out all the paragraphs
1274 // using recursive descent.
1275 paragraph->writeFile(this, ofs, params, footnoteflag, depth);
1277 // Write marker that shows file is complete
1278 ofs << "\n\\the_end" << endl;
1282 // how to check if close went ok?
1283 // Following is an attempt... (BE 20001011)
1285 // good() returns false if any error occured, including some
1286 // formatting error.
1287 // bad() returns true if something bad happened in the buffer,
1288 // which should include file system full errors.
1295 lyxerr << "Buffer::writeFile: BAD ERROR!" << endl;
1297 lyxerr << "Buffer::writeFile: NOT SO BAD ERROR!"
1307 string const Buffer::asciiParagraph(LyXParagraph const * par,
1308 unsigned int linelen) const
1310 ostringstream buffer;
1313 Inset const * inset;
1316 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1320 int ltype_depth = 0;
1321 unsigned int currlinelen = 0;
1322 bool ref_printed = false;
1327 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1329 || par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
1330 /* begins a footnote environment ? */
1331 if (footnoteflag != par->footnoteflag) {
1332 footnoteflag = par->footnoteflag;
1334 size_t const j = strlen(string_footnotekinds[par->footnotekind]) + 4;
1335 if ((linelen > 0) &&
1336 ((currlinelen + j) > linelen)) {
1341 << string_footnotekinds[par->footnotekind]
1347 if (!par->previous()) {
1349 /* begins or ends a deeper area ?*/
1350 if (depth != par->params.depth()) {
1351 if (par->params.depth() > depth) {
1352 while (par->params.depth() > depth) {
1356 while (par->params.depth() < depth) {
1362 /* First write the layout */
1363 string const tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1364 if (tmp == "Itemize") {
1366 ltype_depth = depth + 1;
1367 } else if (tmp == "Enumerate") {
1369 ltype_depth = depth + 1;
1370 } else if (strstr(tmp.c_str(), "ection")) {
1372 ltype_depth = depth + 1;
1373 } else if (strstr(tmp.c_str(), "aragraph")) {
1375 ltype_depth = depth + 1;
1376 } else if (tmp == "Description") {
1378 ltype_depth = depth + 1;
1379 } else if (tmp == "Abstract") {
1382 } else if (tmp == "Bibliography") {
1390 /* maybe some vertical spaces */
1392 /* the labelwidthstring used in lists */
1396 /* some pagebreaks? */
1400 /* what about the alignment */
1403 /* dummy layout, that means a footnote ended */
1404 footnoteflag = LyXParagraph::NO_FOOTNOTE;
1408 lyxerr << "Should this ever happen?" << endl;
1412 font1 = LyXFont(LyXFont::ALL_INHERIT, params.language);
1413 for (LyXParagraph::size_type i = 0; i < par->size(); ++i) {
1421 for (char j = 0; j < depth; ++j)
1423 currlinelen = depth * 2;
1425 case 0: /* Standard */
1426 case 4: /* (Sub)Paragraph */
1427 case 5: /* Description */
1429 case 6: /* Abstract */
1431 buffer << "Abstract\n\n";
1433 buffer << "Abstract: ";
1435 case 7: /* Bibliography */
1438 buffer << "References\n\n";
1440 buffer << "References: ";
1445 buffer << par->params.labelString() << " ";
1448 if (ltype_depth > depth) {
1449 for (char j = ltype_depth - 1; j > depth; --j)
1451 currlinelen += (ltype_depth-depth)*2;
1454 font2 = par->GetFontSettings(params, i);
1455 if (font1.latex() != font2.latex()) {
1456 if (font2.latex() == LyXFont::OFF)
1463 c = par->GetUChar(params, i);
1467 case LyXParagraph::META_INSET:
1468 if ((inset = par->GetInset(i))) {
1469 if (!inset->Ascii(this, buffer)) {
1471 string s = rsplit(buffer.str().c_str(),
1473 currlinelen += s.length();
1475 // to be sure it breaks paragraph
1476 currlinelen += linelen;
1480 case LyXParagraph::META_NEWLINE:
1483 for (char j = 0; j < depth; ++j)
1486 currlinelen = depth * 2;
1487 if (ltype_depth > depth) {
1488 for (char j = ltype_depth;
1491 currlinelen += (ltype_depth - depth) * 2;
1494 case LyXParagraph::META_HFILL:
1501 if ((linelen > 0) && (currlinelen > (linelen - 10)) &&
1502 (c == ' ') && ((i + 2) < par->size()))
1505 for (char j = 0; j < depth; ++j)
1507 currlinelen = depth * 2;
1508 if (ltype_depth > depth) {
1509 for (char j = ltype_depth;
1512 currlinelen += (ltype_depth-depth)*2;
1514 } else if (c != '\0')
1517 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1522 return buffer.str().c_str();
1526 void Buffer::writeFileAscii(string const & fname, int linelen)
1528 ofstream ofs(fname.c_str());
1530 WriteFSAlert(_("Error: Cannot write file:"), fname);
1533 writeFileAscii(ofs, linelen);
1537 void Buffer::writeFileAscii(ostream & ofs, int linelen)
1539 LyXParagraph * par = paragraph;
1541 ofs << asciiParagraph(par, linelen);
1549 void Buffer::makeLaTeXFile(string const & fname,
1550 string const & original_path,
1551 bool nice, bool only_body)
1553 lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1555 niceFile = nice; // this will be used by Insetincludes.
1557 tex_code_break_column = lyxrc.ascii_linelen;
1559 LyXTextClass const & tclass =
1560 textclasslist.TextClass(params.textclass);
1562 ofstream ofs(fname.c_str());
1564 WriteFSAlert(_("Error: Cannot open file: "), fname);
1568 // validate the buffer.
1569 lyxerr[Debug::LATEX] << " Validating buffer..." << endl;
1570 LaTeXFeatures features(params, tclass.numLayouts());
1572 lyxerr[Debug::LATEX] << " Buffer validation done." << endl;
1575 // The starting paragraph of the coming rows is the
1576 // first paragraph of the document. (Asger)
1577 texrow.start(paragraph, 0);
1579 if (!only_body && nice) {
1580 ofs << "%% " LYX_DOCVERSION " created this file. "
1581 "For more info, see http://www.lyx.org/.\n"
1582 "%% Do not edit unless you really know what "
1587 lyxerr.debug() << "lyx header finished" << endl;
1588 // There are a few differences between nice LaTeX and usual files:
1589 // usual is \batchmode and has a
1590 // special input@path to allow the including of figures
1591 // with either \input or \includegraphics (what figinsets do).
1592 // batchmode is not set if there is a tex_code_break_column.
1593 // In this case somebody is interested in the generated LaTeX,
1594 // so this is OK. input@path is set when the actual parameter
1595 // original_path is set. This is done for usual tex-file, but not
1596 // for nice-latex-file. (Matthias 250696)
1599 // code for usual, NOT nice-latex-file
1600 ofs << "\\batchmode\n"; // changed
1601 // from \nonstopmode
1604 if (!original_path.empty()) {
1605 ofs << "\\makeatletter\n"
1606 << "\\def\\input@path{{"
1607 << original_path << "/}}\n"
1608 << "\\makeatother\n";
1614 ofs << "\\documentclass";
1616 string options; // the document class options.
1618 if (tokenPos(tclass.opt_fontsize(),
1619 '|', params.fontsize) >= 0) {
1620 // only write if existing in list (and not default)
1621 options += params.fontsize;
1626 if (!params.use_geometry &&
1627 (params.paperpackage == BufferParams::PACKAGE_NONE)) {
1628 switch (params.papersize) {
1629 case BufferParams::PAPER_A4PAPER:
1630 options += "a4paper,";
1632 case BufferParams::PAPER_USLETTER:
1633 options += "letterpaper,";
1635 case BufferParams::PAPER_A5PAPER:
1636 options += "a5paper,";
1638 case BufferParams::PAPER_B5PAPER:
1639 options += "b5paper,";
1641 case BufferParams::PAPER_EXECUTIVEPAPER:
1642 options += "executivepaper,";
1644 case BufferParams::PAPER_LEGALPAPER:
1645 options += "legalpaper,";
1651 if (params.sides != tclass.sides()) {
1652 switch (params.sides) {
1653 case LyXTextClass::OneSide:
1654 options += "oneside,";
1656 case LyXTextClass::TwoSides:
1657 options += "twoside,";
1664 if (params.columns != tclass.columns()) {
1665 if (params.columns == 2)
1666 options += "twocolumn,";
1668 options += "onecolumn,";
1671 if (!params.use_geometry
1672 && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1673 options += "landscape,";
1675 // language should be a parameter to \documentclass
1677 string language_options;
1678 if (params.language->babel() == "hebrew"
1679 && default_language->babel() != "hebrew")
1680 // This seems necessary
1681 features.UsedLanguages.insert(default_language);
1683 if (lyxrc.language_use_babel ||
1684 params.language->lang() != lyxrc.default_language ||
1685 !features.UsedLanguages.empty()) {
1687 for (LaTeXFeatures::LanguageList::const_iterator cit =
1688 features.UsedLanguages.begin();
1689 cit != features.UsedLanguages.end(); ++cit)
1690 language_options += (*cit)->babel() + ',';
1691 language_options += params.language->babel();
1692 if (lyxrc.language_global_options)
1693 options += language_options + ',';
1696 // the user-defined options
1697 if (!params.options.empty()) {
1698 options += params.options + ',';
1701 if (!options.empty()){
1702 options = strip(options, ',');
1703 ofs << '[' << options << ']';
1707 << textclasslist.LatexnameOfClass(params.textclass)
1710 // end of \documentclass defs
1712 // font selection must be done before loading fontenc.sty
1713 // The ae package is not needed when using OT1 font encoding.
1714 if (params.fonts != "default" &&
1715 (params.fonts != "ae" || lyxrc.fontenc != "default")) {
1716 ofs << "\\usepackage{" << params.fonts << "}\n";
1718 if (params.fonts == "ae") {
1719 ofs << "\\usepackage{aecompl}\n";
1723 // this one is not per buffer
1724 if (lyxrc.fontenc != "default") {
1725 ofs << "\\usepackage[" << lyxrc.fontenc
1730 if (params.inputenc == "auto") {
1731 string const doc_encoding =
1732 params.language->encoding()->LatexName();
1734 // Create a list with all the input encodings used
1736 set<string> encodings;
1737 for (LaTeXFeatures::LanguageList::const_iterator it =
1738 features.UsedLanguages.begin();
1739 it != features.UsedLanguages.end(); ++it)
1740 if ((*it)->encoding()->LatexName() != doc_encoding)
1741 encodings.insert((*it)->encoding()->LatexName());
1743 ofs << "\\usepackage[";
1744 std::copy(encodings.begin(), encodings.end(),
1745 std::ostream_iterator<string>(ofs, ","));
1746 ofs << doc_encoding << "]{inputenc}\n";
1748 } else if (params.inputenc != "default") {
1749 ofs << "\\usepackage[" << params.inputenc
1754 // At the very beginning the text parameters.
1755 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
1756 switch (params.paperpackage) {
1757 case BufferParams::PACKAGE_A4:
1758 ofs << "\\usepackage{a4}\n";
1761 case BufferParams::PACKAGE_A4WIDE:
1762 ofs << "\\usepackage{a4wide}\n";
1765 case BufferParams::PACKAGE_WIDEMARGINSA4:
1766 ofs << "\\usepackage[widemargins]{a4}\n";
1771 if (params.use_geometry) {
1772 ofs << "\\usepackage{geometry}\n";
1774 ofs << "\\geometry{verbose";
1775 if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1776 ofs << ",landscape";
1777 switch (params.papersize2) {
1778 case BufferParams::VM_PAPER_CUSTOM:
1779 if (!params.paperwidth.empty())
1780 ofs << ",paperwidth="
1781 << params.paperwidth;
1782 if (!params.paperheight.empty())
1783 ofs << ",paperheight="
1784 << params.paperheight;
1786 case BufferParams::VM_PAPER_USLETTER:
1787 ofs << ",letterpaper";
1789 case BufferParams::VM_PAPER_USLEGAL:
1790 ofs << ",legalpaper";
1792 case BufferParams::VM_PAPER_USEXECUTIVE:
1793 ofs << ",executivepaper";
1795 case BufferParams::VM_PAPER_A3:
1798 case BufferParams::VM_PAPER_A4:
1801 case BufferParams::VM_PAPER_A5:
1804 case BufferParams::VM_PAPER_B3:
1807 case BufferParams::VM_PAPER_B4:
1810 case BufferParams::VM_PAPER_B5:
1814 // default papersize ie BufferParams::VM_PAPER_DEFAULT
1815 switch (lyxrc.default_papersize) {
1816 case BufferParams::PAPER_DEFAULT: // keep compiler happy
1817 case BufferParams::PAPER_USLETTER:
1818 ofs << ",letterpaper";
1820 case BufferParams::PAPER_LEGALPAPER:
1821 ofs << ",legalpaper";
1823 case BufferParams::PAPER_EXECUTIVEPAPER:
1824 ofs << ",executivepaper";
1826 case BufferParams::PAPER_A3PAPER:
1829 case BufferParams::PAPER_A4PAPER:
1832 case BufferParams::PAPER_A5PAPER:
1835 case BufferParams::PAPER_B5PAPER:
1840 if (!params.topmargin.empty())
1841 ofs << ",tmargin=" << params.topmargin;
1842 if (!params.bottommargin.empty())
1843 ofs << ",bmargin=" << params.bottommargin;
1844 if (!params.leftmargin.empty())
1845 ofs << ",lmargin=" << params.leftmargin;
1846 if (!params.rightmargin.empty())
1847 ofs << ",rmargin=" << params.rightmargin;
1848 if (!params.headheight.empty())
1849 ofs << ",headheight=" << params.headheight;
1850 if (!params.headsep.empty())
1851 ofs << ",headsep=" << params.headsep;
1852 if (!params.footskip.empty())
1853 ofs << ",footskip=" << params.footskip;
1857 if (features.amsstyle
1858 && !tclass.provides(LyXTextClass::amsmath)) {
1859 ofs << "\\usepackage{amsmath}\n";
1863 if (tokenPos(tclass.opt_pagestyle(),
1864 '|', params.pagestyle) >= 0) {
1865 if (params.pagestyle == "fancy") {
1866 ofs << "\\usepackage{fancyhdr}\n";
1869 ofs << "\\pagestyle{" << params.pagestyle << "}\n";
1873 // We try to load babel late, in case it interferes
1874 // with other packages.
1876 string tmp = lyxrc.language_package;
1877 if (!lyxrc.language_global_options
1878 && tmp == "\\usepackage{babel}")
1879 tmp = "\\usepackage[" +
1880 language_options + "]{babel}";
1885 if (params.secnumdepth != tclass.secnumdepth()) {
1886 ofs << "\\setcounter{secnumdepth}{"
1887 << params.secnumdepth
1891 if (params.tocdepth != tclass.tocdepth()) {
1892 ofs << "\\setcounter{tocdepth}{"
1898 if (params.paragraph_separation) {
1899 switch (params.defskip.kind()) {
1900 case VSpace::SMALLSKIP:
1901 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
1903 case VSpace::MEDSKIP:
1904 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1906 case VSpace::BIGSKIP:
1907 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
1909 case VSpace::LENGTH:
1910 ofs << "\\setlength\\parskip{"
1911 << params.defskip.length().asLatexString()
1914 default: // should never happen // Then delete it.
1915 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1920 ofs << "\\setlength\\parindent{0pt}\n";
1924 // Now insert the LyX specific LaTeX commands...
1926 // The optional packages;
1927 string preamble(features.getPackages());
1929 // this might be useful...
1930 preamble += "\n\\makeatletter\n";
1932 // Some macros LyX will need
1933 string tmppreamble(features.getMacros());
1935 if (!tmppreamble.empty()) {
1936 preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1937 "LyX specific LaTeX commands.\n"
1938 + tmppreamble + '\n';
1941 // the text class specific preamble
1942 tmppreamble = features.getTClassPreamble();
1943 if (!tmppreamble.empty()) {
1944 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1945 "Textclass specific LaTeX commands.\n"
1946 + tmppreamble + '\n';
1949 /* the user-defined preamble */
1950 if (!params.preamble.empty()) {
1951 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1952 "User specified LaTeX commands.\n"
1953 + params.preamble + '\n';
1956 preamble += "\\makeatother\n";
1958 // Itemize bullet settings need to be last in case the user
1959 // defines their own bullets that use a package included
1960 // in the user-defined preamble -- ARRae
1961 // Actually it has to be done much later than that
1962 // since some packages like frenchb make modifications
1963 // at \begin{document} time -- JMarc
1965 for (int i = 0; i < 4; ++i) {
1966 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
1967 if (bullets_def.empty())
1968 bullets_def="\\AtBeginDocument{\n";
1969 bullets_def += " \\renewcommand{\\labelitemi";
1971 // `i' is one less than the item to modify
1978 bullets_def += "ii";
1984 bullets_def += "}{" +
1985 params.user_defined_bullets[i].getText()
1990 if (!bullets_def.empty())
1991 preamble += bullets_def + "}\n\n";
1993 for (int j = countChar(preamble, '\n'); j-- ;) {
2000 ofs << "\\begin{document}\n";
2003 lyxerr.debug() << "preamble finished, now the body." << endl;
2005 if (!lyxrc.language_auto_begin) {
2006 ofs << subst(lyxrc.language_command_begin, "$$lang",
2007 params.language->babel())
2012 latexParagraphs(ofs, paragraph, 0, texrow);
2014 // add this just in case after all the paragraphs
2018 if (!lyxrc.language_auto_end) {
2019 ofs << subst(lyxrc.language_command_end, "$$lang",
2020 params.language->babel())
2026 ofs << "\\end{document}\n";
2029 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2031 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2035 // Just to be sure. (Asger)
2038 // tex_code_break_column's value is used to decide
2039 // if we are in batchmode or not (within mathed_write()
2040 // in math_write.C) so we must set it to a non-zero
2041 // value when we leave otherwise we save incorrect .lyx files.
2042 tex_code_break_column = lyxrc.ascii_linelen;
2046 lyxerr << "File was not closed properly." << endl;
2049 lyxerr.debug() << "Finished making latex file." << endl;
2054 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2056 void Buffer::latexParagraphs(ostream & ofs, LyXParagraph * par,
2057 LyXParagraph * endpar, TexRow & texrow) const
2059 bool was_title = false;
2060 bool already_title = false;
2061 std::ostringstream ftnote;
2066 while (par != endpar) {
2069 lyxerr[Debug::LATEX] << "Error in latexParagraphs."
2072 LyXLayout const & layout =
2073 textclasslist.Style(params.textclass,
2076 if (layout.intitle) {
2077 if (already_title) {
2078 lyxerr <<"Error in latexParagraphs: You"
2079 " should not mix title layouts"
2080 " with normal ones." << endl;
2083 } else if (was_title && !already_title) {
2084 ofs << "\\maketitle\n";
2086 already_title = true;
2089 // We are at depth 0 so we can just use
2090 // ordinary \footnote{} generation
2091 // flag this with ftcount
2093 if (layout.isEnvironment()
2094 || par->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
2095 par = par->TeXEnvironment(this, params, ofs, texrow
2097 ,ftnote, ft_texrow, ftcount
2101 par = par->TeXOnePar(this, params, ofs, texrow, false
2104 ftnote, ft_texrow, ftcount
2109 // Write out what we've generated...
2112 ofs << "\\addtocounter{footnote}{-"
2116 ofs << ftnote.str();
2117 texrow += ft_texrow;
2119 // The extra .c_str() is needed when we use
2120 // lyxstring instead of the STL string class.
2121 ftnote.str(string().c_str());
2126 // It might be that we only have a title in this document
2127 if (was_title && !already_title) {
2128 ofs << "\\maketitle\n";
2134 bool Buffer::isLatex() const
2136 return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2140 bool Buffer::isLinuxDoc() const
2142 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2146 bool Buffer::isLiterate() const
2148 return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2152 bool Buffer::isDocBook() const
2154 return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2158 bool Buffer::isSGML() const
2160 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2161 textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2165 void Buffer::sgmlOpenTag(ostream & os, int depth,
2166 string const & latexname) const
2168 if (latexname != "!-- --")
2169 os << string(depth, ' ') << "<" << latexname << ">\n";
2173 void Buffer::sgmlCloseTag(ostream & os, int depth,
2174 string const & latexname) const
2176 if (latexname != "!-- --")
2177 os << string(depth, ' ') << "</" << latexname << ">\n";
2181 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2183 LyXParagraph * par = paragraph;
2185 niceFile = nice; // this will be used by Insetincludes.
2187 string top_element = textclasslist.LatexnameOfClass(params.textclass);
2188 string environment_stack[10];
2191 int depth = 0; // paragraph depth
2193 ofstream ofs(fname.c_str());
2196 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2200 LyXTextClass const & tclass =
2201 textclasslist.TextClass(params.textclass);
2203 LaTeXFeatures features(params, tclass.numLayouts());
2207 tex_code_break_column = lyxrc.ascii_linelen;
2209 //tex_code_break_column = 0;
2214 string sgml_includedfiles=features.getIncludedFiles(fname);
2216 if (params.preamble.empty() && sgml_includedfiles.empty()) {
2217 ofs << "<!doctype linuxdoc system>\n\n";
2219 ofs << "<!doctype linuxdoc system [ "
2220 << params.preamble << sgml_includedfiles << " \n]>\n\n";
2223 if (params.options.empty())
2224 sgmlOpenTag(ofs, 0, top_element);
2226 string top = top_element;
2228 top += params.options;
2229 sgmlOpenTag(ofs, 0, top);
2233 ofs << "<!-- " << LYX_DOCVERSION
2234 << " created this file. For more info see http://www.lyx.org/"
2238 int desc_on = 0; // description mode
2239 LyXLayout const & style =
2240 textclasslist.Style(params.textclass,
2243 // treat <toc> as a special case for compatibility with old code
2244 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2245 Inset * inset = par->GetInset(0);
2246 Inset::Code lyx_code = inset->LyxCode();
2247 if (lyx_code == Inset::TOC_CODE){
2248 string const temp = "toc";
2249 sgmlOpenTag(ofs, depth, temp);
2253 linuxDocHandleFootnote(ofs, par, depth);
2261 // environment tag closing
2262 for (; depth > par->params.depth(); --depth) {
2263 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2264 environment_stack[depth].erase();
2267 // write opening SGML tags
2268 switch (style.latextype) {
2269 case LATEX_PARAGRAPH:
2270 if (depth == par->params.depth()
2271 && !environment_stack[depth].empty()) {
2272 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2273 environment_stack[depth].erase();
2279 sgmlOpenTag(ofs, depth, style.latexname());
2284 LinuxDocError(par, 0,
2285 _("Error : Wrong depth for"
2286 " LatexType Command.\n"));
2288 if (!environment_stack[depth].empty()){
2289 sgmlCloseTag(ofs, depth,
2290 environment_stack[depth]);
2294 environment_stack[depth].erase();
2295 sgmlOpenTag(ofs, depth, style.latexname());
2298 case LATEX_ENVIRONMENT:
2299 case LATEX_ITEM_ENVIRONMENT:
2300 if (depth == par->params.depth()
2301 && environment_stack[depth] != style.latexname()
2302 && !environment_stack[depth].empty()) {
2304 sgmlCloseTag(ofs, depth,
2305 environment_stack[depth]);
2306 environment_stack[depth].erase();
2308 if (depth < par->params.depth()) {
2309 depth = par->params.depth();
2310 environment_stack[depth].erase();
2312 if (environment_stack[depth] != style.latexname()) {
2314 string const temp = "p";
2315 sgmlOpenTag(ofs, depth, temp);
2317 environment_stack[depth] = style.latexname();
2318 sgmlOpenTag(ofs, depth,
2319 environment_stack[depth]);
2321 if (style.latextype == LATEX_ENVIRONMENT) break;
2323 desc_on = (style.labeltype == LABEL_MANUAL);
2330 sgmlOpenTag(ofs, depth + 1, item_name);
2333 sgmlOpenTag(ofs, depth, style.latexname());
2339 SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2342 linuxDocHandleFootnote(ofs, par, depth);
2344 while(par && par->IsDummy());
2346 SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2352 // write closing SGML tags
2353 switch (style.latextype) {
2355 case LATEX_ENVIRONMENT:
2356 case LATEX_ITEM_ENVIRONMENT:
2359 sgmlCloseTag(ofs, depth, style.latexname());
2365 for (; depth > 0; --depth)
2366 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2368 if (!environment_stack[depth].empty())
2369 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2373 sgmlCloseTag(ofs, 0, top_element);
2377 // How to check for successful close
2382 void Buffer::linuxDocHandleFootnote(ostream & os, LyXParagraph * & par,
2385 string const tag = "footnote";
2387 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2388 sgmlOpenTag(os, depth + 1, tag);
2389 SimpleLinuxDocOnePar(os, par, 0, depth + 1);
2390 sgmlCloseTag(os, depth + 1, tag);
2397 void Buffer::DocBookHandleCaption(ostream & os, string & inner_tag,
2398 int depth, int desc_on,
2399 LyXParagraph * & par)
2401 LyXParagraph * tpar = par;
2404 && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE)
2405 && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2410 && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2412 tpar = tpar->next();
2415 tpar->layout == textclasslist.NumberOfLayout(params.textclass,
2416 "Caption").second) {
2417 sgmlOpenTag(os, depth + 1, inner_tag);
2419 SimpleDocBookOnePar(os, extra_par, tpar,
2420 desc_on, depth + 2);
2421 sgmlCloseTag(os, depth+1, inner_tag);
2422 if (!extra_par.empty())
2429 void Buffer::DocBookHandleFootnote(ostream & os, LyXParagraph * & par,
2432 string tag, inner_tag;
2433 string tmp_par, extra_par;
2434 bool inner_span = false;
2437 // Someone should give this enum a proper name (Lgb)
2445 SOME_ENUM last = NO_ONE;
2446 SOME_ENUM present = FOOTNOTE_LIKE;
2448 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2449 if (last == present) {
2451 if (!tmp_par.empty()) {
2454 sgmlCloseTag(os, depth + 1, inner_tag);
2455 sgmlOpenTag(os, depth + 1, inner_tag);
2462 if (!inner_tag.empty()) sgmlCloseTag(os, depth + 1,
2464 if (!extra_par.empty()) os << extra_par;
2465 if (!tag.empty()) sgmlCloseTag(os, depth, tag);
2468 switch (par->footnotekind) {
2469 case LyXParagraph::FOOTNOTE:
2470 case LyXParagraph::ALGORITHM:
2473 present = FOOTNOTE_LIKE;
2476 case LyXParagraph::MARGIN:
2479 present = MARGIN_LIKE;
2482 case LyXParagraph::FIG:
2483 case LyXParagraph::WIDE_FIG:
2485 inner_tag = "title";
2489 case LyXParagraph::TAB:
2490 case LyXParagraph::WIDE_TAB:
2492 inner_tag = "title";
2497 sgmlOpenTag(os, depth, tag);
2498 if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2499 DocBookHandleCaption(os, inner_tag, depth,
2503 sgmlOpenTag(os, depth + 1, inner_tag);
2506 // ignore all caption here, we processed them above!!!
2507 if (par->layout != textclasslist
2508 .NumberOfLayout(params.textclass,
2509 "Caption").second) {
2510 std::ostringstream ost;
2511 SimpleDocBookOnePar(ost, extra_par, par,
2512 desc_on, depth + 2);
2513 tmp_par += ost.str().c_str();
2515 tmp_par = frontStrip(strip(tmp_par));
2521 if (!inner_tag.empty()) sgmlCloseTag(os, depth + 1, inner_tag);
2522 if (!extra_par.empty()) os << extra_par;
2523 if (!tag.empty()) sgmlCloseTag(os, depth, tag);
2528 // push a tag in a style stack
2529 void Buffer::push_tag(ostream & os, string const & tag,
2530 int & pos, char stack[5][3])
2532 #ifdef WITH_WARNINGS
2533 #warning Use a real stack! (Lgb)
2535 // pop all previous tags
2536 for (int j = pos; j >= 0; --j)
2537 os << "</" << stack[j] << ">";
2540 sprintf(stack[++pos], "%s", tag.c_str());
2543 for (int i = 0; i <= pos; ++i)
2544 os << "<" << stack[i] << ">";
2548 void Buffer::pop_tag(ostream & os, string const & tag,
2549 int & pos, char stack[5][3])
2551 #ifdef WITH_WARNINGS
2552 #warning Use a real stack! (Lgb)
2554 // Please, Lars, do not remove the global variable. I already
2555 // had to reintroduce it twice! (JMarc)
2556 // but...but... I'll remove it anyway. (well not quite) (Lgb)
2560 // pop all tags till specified one
2561 for (j = pos; (j >= 0) && tag != stack[j]; --j)
2562 os << "</" << stack[j] << ">";
2565 os << "</" << tag << ">";
2567 // push all tags, but the specified one
2568 for (j = j + 1; j <= pos; ++j) {
2569 os << "<" << stack[j] << ">";
2570 strcpy(stack[j - 1], stack[j]);
2574 // pop all tags till specified one
2576 for (int j = pos; (j >= 0) && tag != stack[j]; --j)
2577 os << "</" << stack[j] << ">";
2580 os << "</" << tag << ">";
2582 // push all tags, but the specified one
2583 for (int i = j + 1; i <= pos; ++i) {
2584 os << "<" << stack[i] << ">";
2585 strcpy(stack[i - 1], stack[i]);
2592 // Handle internal paragraph parsing -- layout already processed.
2594 // checks, if newcol chars should be put into this line
2595 // writes newline, if necessary.
2597 void linux_doc_line_break(ostream & os, string::size_type & colcount,
2598 string::size_type newcol)
2601 if (colcount > lyxrc.ascii_linelen) {
2603 colcount = newcol; // assume write after this call
2608 void Buffer::SimpleLinuxDocOnePar(ostream & os, LyXParagraph * par,
2609 int desc_on, int /*depth*/)
2614 LyXParagraph::size_type main_body;
2616 LyXLayout const & style = textclasslist.Style(params.textclass,
2619 char family_type = 0; // family font flag
2620 bool is_bold = false; // series font flag
2621 char shape_type = 0; // shape font flag
2622 bool is_em = false; // emphasis (italic) font flag
2624 int stack_num = -1; // style stack position
2625 // Can this be rewritten to use a std::stack, please. (Lgb)
2626 char stack[5][3]; // style stack
2627 string::size_type char_line_count = 5; // Heuristic choice ;-)
2629 if (style.labeltype != LABEL_MANUAL)
2632 main_body = par->BeginningOfMainBody();
2634 // gets paragraph main font
2636 font1 = style.labelfont;
2641 // parsing main loop
2642 for (LyXParagraph::size_type i = 0;
2643 i < par->size(); ++i) {
2655 LyXFont const font2 = par->getFont(params, i);
2657 if (font1.family() != font2.family()) {
2658 switch (family_type) {
2660 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2661 push_tag(os, "tt", stack_num, stack);
2664 else if (font2.family() == LyXFont::SANS_FAMILY) {
2665 push_tag(os, "sf", stack_num, stack);
2670 pop_tag(os, "tt", stack_num, stack);
2671 if (font2.family() == LyXFont::SANS_FAMILY) {
2672 push_tag(os, "sf", stack_num, stack);
2679 pop_tag(os, "sf", stack_num, stack);
2680 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2681 push_tag(os, "tt", stack_num, stack);
2690 if (font1.series() != font2.series()) {
2691 if (font2.series() == LyXFont::BOLD_SERIES) {
2692 push_tag(os, "bf", stack_num, stack);
2694 } else if (is_bold) {
2695 pop_tag(os, "bf", stack_num, stack);
2700 // handle italic and slanted fonts
2701 if (font1.shape() != font2.shape()) {
2702 switch (shape_type) {
2704 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2705 push_tag(os, "it", stack_num, stack);
2707 } else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2708 push_tag(os, "sl", stack_num, stack);
2713 pop_tag(os, "it", stack_num, stack);
2714 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2715 push_tag(os, "sl", stack_num, stack);
2722 pop_tag(os, "sl", stack_num, stack);
2723 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2724 push_tag(os, "it", stack_num, stack);
2732 if (font1.emph() != font2.emph()) {
2733 if (font2.emph() == LyXFont::ON) {
2734 push_tag(os, "em", stack_num, stack);
2737 pop_tag(os, "em", stack_num, stack);
2742 c = par->GetChar(i);
2744 if (c == LyXParagraph::META_INSET) {
2745 inset = par->GetInset(i);
2746 inset->Linuxdoc(this, os);
2749 if (font2.latex() == LyXFont::ON) {
2750 // "TeX"-Mode on == > SGML-Mode on.
2752 os << c; // see LaTeX-Generation...
2756 if (par->linuxDocConvertChar(c, sgml_string)
2757 && !style.free_spacing) { // in freespacing
2759 // non-breaking characters
2763 linux_doc_line_break(os, char_line_count, 6);
2767 linux_doc_line_break(os, char_line_count, 1);
2772 char_line_count += sgml_string.length();
2778 // needed if there is an optional argument but no contents
2779 if (main_body > 0 && main_body == par->size()) {
2783 // pop all defined Styles
2784 for (j = stack_num; j >= 0; --j) {
2785 linux_doc_line_break(os,
2787 3 + strlen(stack[j]));
2788 os << "</" << stack[j] << ">";
2791 // resets description flag correctly
2794 // <tag> not closed...
2795 linux_doc_line_break(os, char_line_count, 6);
2799 // fprintf(file, "</p>");
2805 // Print an error message.
2806 void Buffer::LinuxDocError(LyXParagraph * par, int pos,
2807 string const & message)
2809 // insert an error marker in text
2810 InsetError * new_inset = new InsetError(message);
2811 par->InsertInset(pos, new_inset);
2814 // This constant defines the maximum number of
2815 // environment layouts that can be nesteded.
2816 // The same applies for command layouts.
2817 // These values should be more than enough.
2818 // José Matos (1999/07/22)
2820 enum { MAX_NEST_LEVEL = 25};
2822 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
2824 LyXParagraph * par = paragraph;
2826 niceFile = nice; // this will be used by Insetincludes.
2828 string top_element= textclasslist.LatexnameOfClass(params.textclass);
2829 // Please use a real stack.
2830 string environment_stack[MAX_NEST_LEVEL];
2831 string environment_inner[MAX_NEST_LEVEL];
2832 // Please use a real stack.
2833 string command_stack[MAX_NEST_LEVEL];
2834 bool command_flag= false;
2835 int command_depth= 0, command_base= 0, cmd_depth= 0;
2837 string item_name, command_name;
2838 string c_depth, c_params, tmps;
2840 int depth = 0; // paragraph depth
2841 LyXTextClass const & tclass =
2842 textclasslist.TextClass(params.textclass);
2844 LaTeXFeatures features(params, tclass.numLayouts());
2848 tex_code_break_column = lyxrc.ascii_linelen;
2850 //tex_code_break_column = 0;
2852 ofstream ofs(fname.c_str());
2854 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2861 string sgml_includedfiles=features.getIncludedFiles(fname);
2863 ofs << "<!doctype " << top_element
2864 << " public \"-//OASIS//DTD DocBook V3.1//EN\"";
2866 if (params.preamble.empty() && sgml_includedfiles.empty())
2869 ofs << "\n [ " << params.preamble
2870 << sgml_includedfiles << " \n]>\n\n";
2873 string top = top_element;
2875 top += params.language->code();
2878 if (!params.options.empty()) {
2880 top += params.options;
2882 sgmlOpenTag(ofs, 0, top);
2884 ofs << "<!-- DocBook file was created by " << LYX_DOCVERSION
2885 << "\n See http://www.lyx.org/ for more information -->\n";
2888 int desc_on = 0; // description mode
2889 LyXLayout const & style =
2890 textclasslist.Style(params.textclass,
2893 // environment tag closing
2894 for (; depth > par->params.depth(); --depth) {
2895 if (environment_inner[depth] != "!-- --") {
2896 item_name= "listitem";
2897 sgmlCloseTag(ofs, command_depth + depth,
2899 if (environment_inner[depth] == "varlistentry")
2900 sgmlCloseTag(ofs, depth+command_depth,
2901 environment_inner[depth]);
2903 sgmlCloseTag(ofs, depth + command_depth,
2904 environment_stack[depth]);
2905 environment_stack[depth].erase();
2906 environment_inner[depth].erase();
2909 if (depth == par->params.depth()
2910 && environment_stack[depth] != style.latexname()
2911 && !environment_stack[depth].empty()) {
2912 if (environment_inner[depth] != "!-- --") {
2913 item_name= "listitem";
2914 sgmlCloseTag(ofs, command_depth+depth,
2916 if (environment_inner[depth] == "varlistentry")
2918 depth + command_depth,
2919 environment_inner[depth]);
2922 sgmlCloseTag(ofs, depth + command_depth,
2923 environment_stack[depth]);
2925 environment_stack[depth].erase();
2926 environment_inner[depth].erase();
2929 // Write opening SGML tags.
2930 switch (style.latextype) {
2931 case LATEX_PARAGRAPH:
2932 sgmlOpenTag(ofs, depth+command_depth, style.latexname());
2937 LinuxDocError(par, 0,
2938 _("Error : Wrong depth for "
2939 "LatexType Command.\n"));
2941 command_name = style.latexname();
2943 tmps = style.latexparam();
2944 c_params = split(tmps, c_depth,'|');
2946 cmd_depth= lyx::atoi(c_depth);
2949 if (cmd_depth<command_base) {
2950 for (int j = command_depth;
2951 j >= command_base; --j)
2952 if (!command_stack[j].empty())
2953 sgmlCloseTag(ofs, j, command_stack[j]);
2954 command_depth= command_base= cmd_depth;
2955 } else if (cmd_depth <= command_depth) {
2956 for (int j = command_depth;
2957 j >= cmd_depth; --j)
2959 if (!command_stack[j].empty())
2960 sgmlCloseTag(ofs, j, command_stack[j]);
2961 command_depth= cmd_depth;
2963 command_depth= cmd_depth;
2965 command_depth = command_base = cmd_depth;
2966 command_flag = true;
2968 command_stack[command_depth]= command_name;
2970 // treat label as a special case for
2971 // more WYSIWYM handling.
2972 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2973 Inset * inset = par->GetInset(0);
2974 Inset::Code lyx_code = inset->LyxCode();
2975 if (lyx_code == Inset::LABEL_CODE){
2976 command_name += " id=\"";
2977 command_name += (static_cast<InsetCommand *>(inset))->getContents();
2978 command_name += "\"";
2983 sgmlOpenTag(ofs, depth + command_depth, command_name);
2984 if (c_params.empty())
2985 item_name = "title";
2987 item_name = c_params;
2988 sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
2991 case LATEX_ENVIRONMENT:
2992 case LATEX_ITEM_ENVIRONMENT:
2993 if (depth < par->params.depth()) {
2994 depth = par->params.depth();
2995 environment_stack[depth].erase();
2998 if (environment_stack[depth] != style.latexname()) {
2999 environment_stack[depth] = style.latexname();
3000 environment_inner[depth] = "!-- --";
3001 sgmlOpenTag(ofs, depth + command_depth,
3002 environment_stack[depth]);
3004 if (environment_inner[depth] != "!-- --") {
3005 item_name= "listitem";
3007 command_depth + depth,
3009 if (environment_inner[depth] == "varlistentry")
3011 depth + command_depth,
3012 environment_inner[depth]);
3016 if (style.latextype == LATEX_ENVIRONMENT) {
3017 if (!style.latexparam().empty()) {
3018 if(style.latexparam() == "CDATA")
3019 ofs << "<![ CDATA [";
3021 sgmlOpenTag(ofs, depth + command_depth,
3022 style.latexparam());
3027 desc_on = (style.labeltype == LABEL_MANUAL);
3030 environment_inner[depth]= "varlistentry";
3032 environment_inner[depth]= "listitem";
3034 sgmlOpenTag(ofs, depth + 1 + command_depth,
3035 environment_inner[depth]);
3039 sgmlOpenTag(ofs, depth + 1 + command_depth,
3043 sgmlOpenTag(ofs, depth + 1 + command_depth,
3048 sgmlOpenTag(ofs, depth + command_depth,
3056 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3057 depth + 1 + command_depth);
3059 DocBookHandleFootnote(ofs, par,
3060 depth + 1 + command_depth);
3061 } while(par && par->IsDummy());
3064 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3065 depth + 1 + command_depth);
3069 // write closing SGML tags
3070 switch (style.latextype) {
3072 if (c_params.empty())
3076 sgmlCloseTag(ofs, depth + command_depth, end_tag);
3078 case LATEX_ENVIRONMENT:
3079 if (!style.latexparam().empty()) {
3080 if(style.latexparam() == "CDATA")
3083 sgmlCloseTag(ofs, depth + command_depth,
3084 style.latexparam());
3087 case LATEX_ITEM_ENVIRONMENT:
3088 if (desc_on == 1) break;
3090 sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
3092 case LATEX_PARAGRAPH:
3093 sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3096 sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3102 for (; depth >= 0; --depth) {
3103 if (!environment_stack[depth].empty()) {
3104 if (environment_inner[depth] != "!-- --") {
3105 item_name= "listitem";
3106 sgmlCloseTag(ofs, command_depth + depth,
3108 if (environment_inner[depth] == "varlistentry")
3109 sgmlCloseTag(ofs, depth + command_depth,
3110 environment_inner[depth]);
3113 sgmlCloseTag(ofs, depth + command_depth,
3114 environment_stack[depth]);
3118 for (int j = command_depth; j >= command_base; --j)
3119 if (!command_stack[j].empty())
3120 sgmlCloseTag(ofs, j, command_stack[j]);
3123 sgmlCloseTag(ofs, 0, top_element);
3126 // How to check for successful close
3130 void Buffer::SimpleDocBookOnePar(ostream & os, string & extra,
3131 LyXParagraph * par, int & desc_on,
3134 bool emph_flag = false;
3136 LyXLayout const & style = textclasslist.Style(params.textclass,
3139 LyXParagraph::size_type main_body;
3140 if (style.labeltype != LABEL_MANUAL)
3143 main_body = par->BeginningOfMainBody();
3145 // gets paragraph main font
3146 LyXFont font1 = main_body > 0 ? style.labelfont : style.font;
3148 int char_line_count = depth;
3149 if (!style.free_spacing)
3150 for (int j = 0; j < depth; ++j)
3153 // parsing main loop
3154 for (LyXParagraph::size_type i = 0;
3155 i < par->size(); ++i) {
3156 LyXFont font2 = par->getFont(params, i);
3158 // handle <emphasis> tag
3159 if (font1.emph() != font2.emph() && i) {
3160 if (font2.emph() == LyXFont::ON) {
3164 os << "</emphasis>";
3169 char c = par->GetChar(i);
3171 if (c == LyXParagraph::META_INSET) {
3172 Inset * inset = par->GetInset(i);
3173 std::ostringstream ost;
3174 inset->DocBook(this, ost);
3175 string tmp_out = ost.str().c_str();
3178 // This code needs some explanation:
3179 // Two insets are treated specially
3180 // label if it is the first element in a command paragraph
3182 // graphics inside tables or figure floats can't go on
3183 // title (the equivalente in latex for this case is caption
3184 // and title should come first
3187 if (desc_on!= 3 || i!= 0) {
3188 if (!tmp_out.empty() && tmp_out[0] == '@') {
3190 extra += frontStrip(tmp_out, '@');
3192 os << frontStrip(tmp_out, '@');
3197 } else if (font2.latex() == LyXFont::ON) {
3198 // "TeX"-Mode on ==> SGML-Mode on.
3204 if (par->linuxDocConvertChar(c, sgml_string)
3205 && !style.free_spacing) { // in freespacing
3207 // non-breaking characters
3211 os << "\n</term><listitem><para>";
3223 // needed if there is an optional argument but no contents
3224 if (main_body > 0 && main_body == par->size()) {
3228 os << "</emphasis>";
3231 // resets description flag correctly
3234 // <term> not closed...
3242 // This should be enabled when the Chktex class is implemented. (Asger)
3243 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3244 // Other flags: -wall -v0 -x
3245 int Buffer::runChktex()
3247 if (!users->text) return 0;
3249 ProhibitInput(users);
3251 // get LaTeX-Filename
3252 string const name = getLatexName();
3253 string path = OnlyPath(filename);
3255 string const org_path = path;
3256 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3260 Path p(path); // path to LaTeX file
3261 users->owner()->getMiniBuffer()->Set(_("Running chktex..."));
3263 // Remove all error insets
3264 bool const removedErrorInsets = users->removeAutoInsets();
3266 // Generate the LaTeX file if neccessary
3267 makeLaTeXFile(name, org_path, false);
3270 Chktex chktex(lyxrc.chktex_command, name, filepath);
3271 int res = chktex.run(terr); // run chktex
3274 WriteAlert(_("chktex did not work!"),
3275 _("Could not run with file:"), name);
3276 } else if (res > 0) {
3277 // Insert all errors as errors boxes
3278 users->insertErrors(terr);
3281 // if we removed error insets before we ran chktex or if we inserted
3282 // error insets after we ran chktex, this must be run:
3283 if (removedErrorInsets || res){
3285 users->fitCursor(users->text);
3293 void Buffer::validate(LaTeXFeatures & features) const
3295 LyXParagraph * par = paragraph;
3296 LyXTextClass const & tclass =
3297 textclasslist.TextClass(params.textclass);
3299 // AMS Style is at document level
3301 features.amsstyle = (params.use_amsmath ||
3302 tclass.provides(LyXTextClass::amsmath));
3305 // We don't use "lyxerr.debug" because of speed. (Asger)
3306 if (lyxerr.debugging(Debug::LATEX))
3307 lyxerr << "Paragraph: " << par << endl;
3309 // Now just follow the list of paragraphs and run
3310 // validate on each of them.
3311 par->validate(features);
3313 // and then the next paragraph
3321 // the bullet shapes are buffer level not paragraph level
3322 // so they are tested here
3323 for (int i = 0; i < 4; ++i) {
3324 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3325 int const font = params.user_defined_bullets[i].getFont();
3327 int const c = params
3328 .user_defined_bullets[i]
3335 features.latexsym = true;
3337 } else if (font == 1) {
3338 features.amssymb = true;
3339 } else if ((font >= 2 && font <= 5)) {
3340 features.pifont = true;
3345 if (lyxerr.debugging(Debug::LATEX)) {
3346 features.showStruct();
3351 void Buffer::setPaperStuff()
3353 params.papersize = BufferParams::PAPER_DEFAULT;
3354 char const c1 = params.paperpackage;
3355 if (c1 == BufferParams::PACKAGE_NONE) {
3356 char const c2 = params.papersize2;
3357 if (c2 == BufferParams::VM_PAPER_USLETTER)
3358 params.papersize = BufferParams::PAPER_USLETTER;
3359 else if (c2 == BufferParams::VM_PAPER_USLEGAL)
3360 params.papersize = BufferParams::PAPER_LEGALPAPER;
3361 else if (c2 == BufferParams::VM_PAPER_USEXECUTIVE)
3362 params.papersize = BufferParams::PAPER_EXECUTIVEPAPER;
3363 else if (c2 == BufferParams::VM_PAPER_A3)
3364 params.papersize = BufferParams::PAPER_A3PAPER;
3365 else if (c2 == BufferParams::VM_PAPER_A4)
3366 params.papersize = BufferParams::PAPER_A4PAPER;
3367 else if (c2 == BufferParams::VM_PAPER_A5)
3368 params.papersize = BufferParams::PAPER_A5PAPER;
3369 else if ((c2 == BufferParams::VM_PAPER_B3) || (c2 == BufferParams::VM_PAPER_B4) ||
3370 (c2 == BufferParams::VM_PAPER_B5))
3371 params.papersize = BufferParams::PAPER_B5PAPER;
3372 } else if ((c1 == BufferParams::PACKAGE_A4) || (c1 == BufferParams::PACKAGE_A4WIDE) ||
3373 (c1 == BufferParams::PACKAGE_WIDEMARGINSA4))
3374 params.papersize = BufferParams::PAPER_A4PAPER;
3378 // This function should be in Buffer because it's a buffer's property (ale)
3379 string const Buffer::getIncludeonlyList(char delim)
3382 for (inset_iterator it = inset_iterator_begin();
3383 it != inset_iterator_end(); ++it) {
3384 if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3385 InsetInclude * insetinc =
3386 static_cast<InsetInclude *>(*it);
3387 if (insetinc->isInclude()
3388 && insetinc->isNoLoad()) {
3391 lst += OnlyFilename(ChangeExtension(insetinc->getContents(), string()));
3395 lyxerr.debug() << "Includeonly(" << lst << ')' << endl;
3400 vector<string> const Buffer::getLabelList()
3402 /// if this is a child document and the parent is already loaded
3403 /// Use the parent's list instead [ale990407]
3404 if (!params.parentname.empty()
3405 && bufferlist.exists(params.parentname)) {
3406 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3408 return tmp->getLabelList();
3411 vector<string> label_list;
3412 for (inset_iterator it = inset_iterator_begin();
3413 it != inset_iterator_end(); ++it) {
3414 vector<string> const l = (*it)->getLabelList();
3415 label_list.insert(label_list.end(), l.begin(), l.end());
3421 vector<vector<Buffer::TocItem> > const Buffer::getTocList() const
3426 vector<vector<TocItem> > l(4);
3427 LyXParagraph * par = paragraph;
3430 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3431 if (textclasslist.Style(params.textclass,
3432 par->GetLayout()).labeltype
3433 == LABEL_SENSITIVE) {
3437 tmp.str = par->String(this, false);
3438 switch (par->footnotekind) {
3439 case LyXParagraph::FIG:
3440 case LyXParagraph::WIDE_FIG:
3441 tmp.str = tostr(++figs) + ". "
3443 l[TOC_LOF].push_back(tmp);
3445 case LyXParagraph::TAB:
3446 case LyXParagraph::WIDE_TAB:
3447 tmp.str = tostr(++tables) + ". "
3449 l[TOC_LOT].push_back(tmp);
3451 case LyXParagraph::ALGORITHM:
3452 tmp.str = tostr(++algs) + ". "
3454 l[TOC_LOA].push_back(tmp);
3456 case LyXParagraph::FOOTNOTE:
3457 case LyXParagraph::MARGIN:
3461 } else if (!par->IsDummy()) {
3463 char const labeltype =
3464 textclasslist.Style(params.textclass,
3465 par->GetLayout()).labeltype;
3467 if (labeltype >= LABEL_COUNTER_CHAPTER
3468 && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3469 // insert this into the table of contents
3474 textclasslist.TextClass(params.textclass).maxcounter());
3475 tmp.str = par->String(this, true);
3476 l[TOC_TOC].push_back(tmp);
3489 // This is also a buffer property (ale)
3490 vector<pair<string,string> > const Buffer::getBibkeyList()
3492 /// if this is a child document and the parent is already loaded
3493 /// Use the parent's list instead [ale990412]
3494 if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3495 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3497 return tmp->getBibkeyList();
3500 vector<pair<string, string> > keys;
3501 LyXParagraph * par = paragraph;
3504 keys.push_back(pair<string, string>(par->bibkey->getContents(),
3505 par->String(this, false)));
3513 // Might be either using bibtex or a child has bibliography
3515 for (inset_iterator it = inset_iterator_begin();
3516 it != inset_iterator_end(); ++it) {
3517 // Search for Bibtex or Include inset
3518 if ((*it)->LyxCode() == Inset::BIBTEX_CODE) {
3519 vector<pair<string,string> > tmp =
3520 static_cast<InsetBibtex*>(*it)->getKeys(this);
3521 keys.insert(keys.end(), tmp.begin(), tmp.end());
3522 } else if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3523 vector<pair<string,string> > const tmp =
3524 static_cast<InsetInclude*>(*it)->getKeys();
3525 keys.insert(keys.end(), tmp.begin(), tmp.end());
3534 bool Buffer::isDepClean(string const & name) const
3536 DEPCLEAN * item = dep_clean;
3537 while (item && item->master != name)
3539 if (!item) return true;
3544 void Buffer::markDepClean(string const & name)
3547 dep_clean = new DEPCLEAN;
3548 dep_clean->clean = true;
3549 dep_clean->master = name;
3550 dep_clean->next = 0;
3552 DEPCLEAN * item = dep_clean;
3553 while (item && item->master != name)
3558 item = new DEPCLEAN;
3560 item->master = name;
3567 bool Buffer::Dispatch(string const & command)
3569 // Split command string into command and argument
3571 string line = frontStrip(command);
3572 string const arg = strip(frontStrip(split(line, cmd, ' ')));
3574 return Dispatch(lyxaction.LookupFunc(cmd), arg);
3578 bool Buffer::Dispatch(int action, string const & argument)
3580 bool dispatched = true;
3583 Exporter::Export(this, argument, false);
3593 void Buffer::resize()
3595 /// resize the BufferViews!
3601 void Buffer::resizeInsets(BufferView * bv)
3603 /// then remove all LyXText in text-insets
3604 LyXParagraph * par = paragraph;
3606 for (; par; par = par->next_) {
3607 par->resizeInsetsLyXText(bv);
3610 for (; par; par = par->next()) {
3611 par->resizeInsetsLyXText(bv);
3617 void Buffer::ChangeLanguage(Language const * from, Language const * to)
3620 LyXParagraph * par = paragraph;
3622 par->ChangeLanguage(params, from, to);
3632 bool Buffer::isMultiLingual()
3634 LyXParagraph * par = paragraph;
3636 if (par->isMultiLingual(params))
3648 Buffer::inset_iterator::inset_iterator(LyXParagraph * paragraph,
3649 LyXParagraph::size_type pos)
3652 it = par->InsetIterator(pos);
3653 if (it == par->inset_iterator_end()) {
3664 void Buffer::inset_iterator::SetParagraph()
3667 it = par->inset_iterator_begin();
3668 if (it != par->inset_iterator_end())
3677 // We maintain an invariant that whenever par = 0 then it = 0