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 * ======================================================
22 #include <sys/types.h>
32 #pragma implementation "buffer.h"
36 #include "bufferlist.h"
38 #include "lyx_gui_misc.h"
39 #include "LyXAction.h"
42 #include "tex-strings.h"
44 #include "bufferview_funcs.h"
45 #include "minibuffer.h"
48 #include "mathed/formulamacro.h"
49 #include "insets/lyxinset.h"
50 #include "insets/inseterror.h"
51 #include "insets/insetlabel.h"
52 #include "insets/insetref.h"
53 #include "insets/inseturl.h"
54 #include "insets/insetinfo.h"
55 #include "insets/insetquotes.h"
56 #include "insets/insetlatexaccent.h"
57 #include "insets/insetbib.h"
58 #include "insets/insetcite.h"
59 #include "insets/insetexternal.h"
60 #include "insets/insetindex.h"
61 #include "insets/insetinclude.h"
62 #include "insets/insettoc.h"
63 #include "insets/insetparent.h"
64 #include "insets/insetspecialchar.h"
65 #include "insets/figinset.h"
66 #include "insets/insettext.h"
67 #include "insets/insetert.h"
68 #include "insets/insetgraphics.h"
69 #include "insets/insetfoot.h"
70 #include "insets/insetmarginal.h"
71 #include "insets/insetminipage.h"
72 #include "insets/insetfloat.h"
73 #include "insets/insetlist.h"
74 #include "insets/insettabular.h"
75 #include "insets/insettheorem.h"
76 #include "insets/insetcaption.h"
77 #include "support/filetools.h"
78 #include "support/path.h"
84 #include "LaTeXFeatures.h"
85 #include "support/syscall.h"
86 #include "support/lyxlib.h"
87 #include "support/FileInfo.h"
91 #include "lyx_gui_misc.h" // WarnReadonly()
92 #include "frontends/Dialogs.h"
107 using std::istringstream;
109 // all these externs should eventually be removed.
110 extern BufferList bufferlist;
113 extern void MenuExport(Buffer *, string const &);
115 extern LyXAction lyxaction;
118 static const float LYX_FORMAT = 2.17;
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;
168 string const Buffer::getLatexName(bool no_path) const
171 return OnlyFilename(ChangeExtension(MakeLatexName(filename),
174 return ChangeExtension(MakeLatexName(filename),
179 void Buffer::setReadonly(bool flag)
181 if (read_only != flag) {
184 users->owner()->getDialogs()->updateBufferDependent();
187 WarnReadonly(filename);
192 bool Buffer::saveParamsAsDefaults()
194 string fname = AddName(AddPath(user_lyxdir, "templates/"),
196 Buffer defaults = Buffer(fname);
198 // Use the current buffer's parameters as default
199 defaults.params = params;
201 // add an empty paragraph. Is this enough?
202 defaults.paragraph = new LyXParagraph;
204 return defaults.writeFile(defaults.filename, false);
208 /// Update window titles of all users
209 // Should work on a list
210 void Buffer::updateTitles() const
212 if (users) users->owner()->updateWindowTitle();
216 /// Reset autosave timer of all users
217 // Should work on a list
218 void Buffer::resetAutosaveTimers() const
220 if (users) users->owner()->resetAutosaveTimer();
224 void Buffer::fileName(string const & newfile)
226 filename = MakeAbsPath(newfile);
227 filepath = OnlyPath(filename);
228 setReadonly(IsFileWriteable(filename) == 0);
233 // candidate for move to BufferView
234 // (at least some parts in the beginning of the func)
237 // changed to be public and have one parameter
238 // if par = 0 normal behavior
239 // else insert behavior
240 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
241 bool Buffer::readLyXformat2(LyXLex & lex, LyXParagraph * par)
245 char depth = 0; // signed or unsigned?
247 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
248 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
250 bool the_end_read = false;
252 LyXParagraph * return_par = 0;
253 LyXFont font(LyXFont::ALL_INHERIT, params.language_info);
254 if (format < 2.16 && params.language == "hebrew")
255 font.setLanguage(default_language);
257 // If we are inserting, we cheat and get a token in advance
258 bool has_token = false;
262 par = new LyXParagraph;
264 users->text->BreakParagraph(users);
265 return_par = users->text->FirstParagraph();
268 // We don't want to adopt the parameters from the
269 // document we insert, so we skip until the text begins:
272 pretoken = lex.GetString();
273 if (pretoken == "\\layout") {
285 pretoken = lex.GetString();
288 // Profiling show this should give a lot: (Asger)
289 string const token = pretoken;
293 the_end_read = parseSingleLyXformat2Token(lex, par, return_par,
306 paragraph = return_par;
312 // We'll remove this later. (Lgb)
313 static string last_inset_read;
317 Buffer::parseSingleLyXformat2Token(LyXLex & lex, LyXParagraph *& par,
318 LyXParagraph *& return_par,
319 string const & token, int & pos,
320 char & depth, LyXFont & font
322 , LyXParagraph::footnote_flag & footnoteflag,
323 LyXParagraph::footnote_kind & footnotekind
327 bool the_end_read = false;
329 if (token[0] != '\\') {
330 for (string::const_iterator cit = token.begin();
331 cit != token.end(); ++cit) {
332 par->InsertChar(pos, (*cit), font);
335 } else if (token == "\\i") {
336 Inset * inset = new InsetLatexAccent;
337 inset->Read(this, lex);
338 par->InsertInset(pos, inset, font);
340 } else if (token == "\\layout") {
345 par = new LyXParagraph(par);
349 string layoutname = lex.GetString();
350 pair<bool, LyXTextClass::LayoutList::size_type> pp
351 = textclasslist.NumberOfLayout(params.textclass,
354 par->layout = pp.second;
355 } else { // layout not found
356 // use default layout "Standard" (0)
359 // Test whether the layout is obsolete.
360 LyXLayout const & layout =
361 textclasslist.Style(params.textclass,
363 if (!layout.obsoleted_by().empty())
365 textclasslist.NumberOfLayout(params.textclass,
366 layout.obsoleted_by()).second;
368 par->footnoteflag = footnoteflag;
369 par->footnotekind = footnotekind;
372 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
373 if (format < 2.16 && params.language == "hebrew")
374 font.setLanguage(default_language);
376 } else if (token == "\\end_float") {
381 par = new LyXParagraph(par);
383 footnotekind = LyXParagraph::FOOTNOTE;
384 footnoteflag = LyXParagraph::NO_FOOTNOTE;
387 par->layout = LYX_DUMMY_LAYOUT;
388 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
389 if (format < 2.16 && params.language == "hebrew")
390 font.setLanguage(default_language);
391 } else if (token == "\\begin_float") {
392 int tmpret = lex.FindToken(string_footnotekinds);
393 if (tmpret == -1) ++tmpret;
394 if (tmpret != LYX_LAYOUT_DEFAULT)
395 footnotekind = static_cast<LyXParagraph::footnote_kind>(tmpret); // bad
396 if (footnotekind == LyXParagraph::FOOTNOTE
397 || footnotekind == LyXParagraph::MARGIN)
398 footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
400 footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
402 } else if (token == "\\begin_float") {
403 // This is the compability reader, unfinished but tested.
406 string tmptok = lex.GetString();
407 //lyxerr << "old float: " << tmptok << endl;
412 if (tmptok == "footnote") {
413 inset = new InsetFoot;
414 } else if (tmptok == "margin") {
415 inset = new InsetMarginal;
416 } else if (tmptok == "fig") {
417 inset = new InsetFloat("figure");
418 old_float += "placement htbp\n";
419 } else if (tmptok == "tab") {
420 inset = new InsetFloat("table");
421 old_float += "placement htbp\n";
422 } else if (tmptok == "alg") {
423 inset = new InsetFloat("algorithm");
424 old_float += "placement htbp\n";
425 } else if (tmptok == "wide-fig") {
426 InsetFloat * tmp = new InsetFloat("figure");
429 old_float += "placement htbp\n";
430 } else if (tmptok == "wide-tab") {
431 InsetFloat * tmp = new InsetFloat("table");
434 old_float += "placement htbp\n";
437 if (!inset) return false; // no end read yet
439 old_float += "collapsed true\n";
441 // Here we need to check for \end_deeper and handle that
442 // before we do the footnote parsing.
443 // This _is_ a hack! (Lgb)
446 string tmp = lex.GetString();
447 if (tmp == "\\end_deeper") {
448 lyxerr << "\\end_deeper caught!" << endl;
450 lex.printError("\\end_deeper: "
451 "depth is already null");
462 old_float += lex.getLongString("\\end_float");
463 old_float += "\n\\end_inset\n";
464 //lyxerr << "float body: " << old_float << endl;
466 istringstream istr(old_float);
469 nylex.setStream(istr);
471 inset->Read(this, nylex);
472 par->InsertInset(pos, inset, font);
475 } else if (token == "\\begin_deeper") {
477 } else if (token == "\\end_deeper") {
479 lex.printError("\\end_deeper: "
480 "depth is already null");
484 } else if (token == "\\begin_preamble") {
485 params.readPreamble(lex);
486 } else if (token == "\\textclass") {
488 pair<bool, LyXTextClassList::size_type> pp =
489 textclasslist.NumberOfClass(lex.GetString());
491 params.textclass = pp.second;
493 lex.printError("Unknown textclass `$$Token'");
494 params.textclass = 0;
496 if (!textclasslist.Load(params.textclass)) {
497 // if the textclass wasn't loaded properly
498 // we need to either substitute another
499 // or stop loading the file.
500 // I can substitute but I don't see how I can
501 // stop loading... ideas?? ARRae980418
502 WriteAlert(_("Textclass Loading Error!"),
503 string(_("Can't load textclass ")) +
504 textclasslist.NameOfClass(params.textclass),
505 _("-- substituting default"));
506 params.textclass = 0;
508 } else if (token == "\\options") {
510 params.options = lex.GetString();
511 } else if (token == "\\language") {
512 params.readLanguage(lex);
513 } else if (token == "\\fontencoding") {
515 } else if (token == "\\inputencoding") {
517 params.inputenc = lex.GetString();
518 } else if (token == "\\graphics") {
519 params.readGraphicsDriver(lex);
520 } else if (token == "\\fontscheme") {
522 params.fonts = lex.GetString();
523 } else if (token == "\\noindent") {
524 par->noindent = true;
525 } else if (token == "\\fill_top") {
526 par->added_space_top = VSpace(VSpace::VFILL);
527 } else if (token == "\\fill_bottom") {
528 par->added_space_bottom = VSpace(VSpace::VFILL);
529 } else if (token == "\\line_top") {
530 par->line_top = true;
531 } else if (token == "\\line_bottom") {
532 par->line_bottom = true;
533 } else if (token == "\\pagebreak_top") {
534 par->pagebreak_top = true;
535 } else if (token == "\\pagebreak_bottom") {
536 par->pagebreak_bottom = true;
537 } else if (token == "\\start_of_appendix") {
538 par->start_of_appendix = true;
539 } else if (token == "\\paragraph_separation") {
540 int tmpret = lex.FindToken(string_paragraph_separation);
541 if (tmpret == -1) ++tmpret;
542 if (tmpret != LYX_LAYOUT_DEFAULT)
543 params.paragraph_separation =
544 static_cast<BufferParams::PARSEP>(tmpret);
545 } else if (token == "\\defskip") {
547 params.defskip = VSpace(lex.GetString());
548 } else if (token == "\\epsfig") { // obsolete
549 // Indeed it is obsolete, but we HAVE to be backwards
550 // compatible until 0.14, because otherwise all figures
551 // in existing documents are irretrivably lost. (Asger)
552 params.readGraphicsDriver(lex);
553 } else if (token == "\\quotes_language") {
554 int tmpret = lex.FindToken(string_quotes_language);
555 if (tmpret == -1) ++tmpret;
556 if (tmpret != LYX_LAYOUT_DEFAULT) {
557 InsetQuotes::quote_language tmpl =
558 InsetQuotes::EnglishQ;
561 tmpl = InsetQuotes::EnglishQ;
564 tmpl = InsetQuotes::SwedishQ;
567 tmpl = InsetQuotes::GermanQ;
570 tmpl = InsetQuotes::PolishQ;
573 tmpl = InsetQuotes::FrenchQ;
576 tmpl = InsetQuotes::DanishQ;
579 params.quotes_language = tmpl;
581 } else if (token == "\\quotes_times") {
583 switch(lex.GetInteger()) {
585 params.quotes_times = InsetQuotes::SingleQ;
588 params.quotes_times = InsetQuotes::DoubleQ;
591 } else if (token == "\\papersize") {
592 int tmpret = lex.FindToken(string_papersize);
596 params.papersize2 = tmpret;
597 } else if (token == "\\paperpackage") {
598 int tmpret = lex.FindToken(string_paperpackages);
601 params.paperpackage = BufferParams::PACKAGE_NONE;
603 params.paperpackage = tmpret;
604 } else if (token == "\\use_geometry") {
606 params.use_geometry = lex.GetInteger();
607 } else if (token == "\\use_amsmath") {
609 params.use_amsmath = lex.GetInteger();
610 } else if (token == "\\paperorientation") {
611 int tmpret = lex.FindToken(string_orientation);
612 if (tmpret == -1) ++tmpret;
613 if (tmpret != LYX_LAYOUT_DEFAULT)
614 params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
615 } else if (token == "\\paperwidth") {
617 params.paperwidth = lex.GetString();
618 } else if (token == "\\paperheight") {
620 params.paperheight = lex.GetString();
621 } else if (token == "\\leftmargin") {
623 params.leftmargin = lex.GetString();
624 } else if (token == "\\topmargin") {
626 params.topmargin = lex.GetString();
627 } else if (token == "\\rightmargin") {
629 params.rightmargin = lex.GetString();
630 } else if (token == "\\bottommargin") {
632 params.bottommargin = lex.GetString();
633 } else if (token == "\\headheight") {
635 params.headheight = lex.GetString();
636 } else if (token == "\\headsep") {
638 params.headsep = lex.GetString();
639 } else if (token == "\\footskip") {
641 params.footskip = lex.GetString();
642 } else if (token == "\\paperfontsize") {
644 params.fontsize = strip(lex.GetString());
645 } else if (token == "\\papercolumns") {
647 params.columns = lex.GetInteger();
648 } else if (token == "\\papersides") {
650 switch(lex.GetInteger()) {
652 case 1: params.sides = LyXTextClass::OneSide; break;
653 case 2: params.sides = LyXTextClass::TwoSides; break;
655 } else if (token == "\\paperpagestyle") {
657 params.pagestyle = strip(lex.GetString());
658 } else if (token == "\\bullet") {
660 int index = lex.GetInteger();
662 int temp_int = lex.GetInteger();
663 params.user_defined_bullets[index].setFont(temp_int);
664 params.temp_bullets[index].setFont(temp_int);
666 temp_int = lex.GetInteger();
667 params.user_defined_bullets[index].setCharacter(temp_int);
668 params.temp_bullets[index].setCharacter(temp_int);
670 temp_int = lex.GetInteger();
671 params.user_defined_bullets[index].setSize(temp_int);
672 params.temp_bullets[index].setSize(temp_int);
674 string temp_str = lex.GetString();
675 if (temp_str != "\\end_bullet") {
676 // this element isn't really necessary for
677 // parsing but is easier for humans
678 // to understand bullets. Put it back and
679 // set a debug message?
680 lex.printError("\\end_bullet expected, got" + temp_str);
681 //how can I put it back?
683 } else if (token == "\\bulletLaTeX") {
685 int index = lex.GetInteger();
687 string temp_str = lex.GetString(), sum_str;
688 while (temp_str != "\\end_bullet") {
689 // this loop structure is needed when user
690 // enters an empty string since the first
691 // thing returned will be the \\end_bullet
693 // if the LaTeX entry has spaces. Each element
694 // therefore needs to be read in turn
697 temp_str = lex.GetString();
699 params.user_defined_bullets[index].setText(sum_str);
700 params.temp_bullets[index].setText(sum_str);
701 } else if (token == "\\secnumdepth") {
703 params.secnumdepth = lex.GetInteger();
704 } else if (token == "\\tocdepth") {
706 params.tocdepth = lex.GetInteger();
707 } else if (token == "\\spacing") {
709 string tmp = strip(lex.GetString());
710 Spacing::Space tmp_space = Spacing::Default;
712 if (tmp == "single") {
713 tmp_space = Spacing::Single;
714 } else if (tmp == "onehalf") {
715 tmp_space = Spacing::Onehalf;
716 } else if (tmp == "double") {
717 tmp_space = Spacing::Double;
718 } else if (tmp == "other") {
720 tmp_space = Spacing::Other;
721 tmp_val = lex.GetFloat();
723 lex.printError("Unknown spacing token: '$$Token'");
725 // Small hack so that files written with klyx will be
728 par->spacing.set(tmp_space, tmp_val);
730 params.spacing.set(tmp_space, tmp_val);
732 } else if (token == "\\paragraph_spacing") {
734 string tmp = strip(lex.GetString());
735 if (tmp == "single") {
736 par->spacing.set(Spacing::Single);
737 } else if (tmp == "onehalf") {
738 par->spacing.set(Spacing::Onehalf);
739 } else if (tmp == "double") {
740 par->spacing.set(Spacing::Double);
741 } else if (tmp == "other") {
743 par->spacing.set(Spacing::Other,
746 lex.printError("Unknown spacing token: '$$Token'");
748 } else if (token == "\\float_placement") {
750 params.float_placement = lex.GetString();
751 } else if (token == "\\family") {
753 font.setLyXFamily(lex.GetString());
754 } else if (token == "\\series") {
756 font.setLyXSeries(lex.GetString());
757 } else if (token == "\\shape") {
759 font.setLyXShape(lex.GetString());
760 } else if (token == "\\size") {
762 font.setLyXSize(lex.GetString());
763 } else if (token == "\\latex") {
765 string tok = lex.GetString();
766 // This is dirty, but gone with LyX3. (Asger)
767 if (tok == "no_latex")
768 font.setLatex(LyXFont::OFF);
769 else if (tok == "latex")
770 font.setLatex(LyXFont::ON);
771 else if (tok == "default")
772 font.setLatex(LyXFont::INHERIT);
774 lex.printError("Unknown LaTeX font flag "
776 } else if (token == "\\lang") {
778 string tok = lex.GetString();
779 Languages::iterator lit = languages.find(tok);
780 if (lit != languages.end()) {
781 font.setLanguage(&(*lit).second);
783 font.setLanguage(params.language_info);
784 lex.printError("Unknown language `$$Token'");
786 } else if (token == "\\emph") {
788 font.setEmph(font.setLyXMisc(lex.GetString()));
789 } else if (token == "\\bar") {
791 string tok = lex.GetString();
792 // This is dirty, but gone with LyX3. (Asger)
794 font.setUnderbar(LyXFont::ON);
795 else if (tok == "no")
796 font.setUnderbar(LyXFont::OFF);
797 else if (tok == "default")
798 font.setUnderbar(LyXFont::INHERIT);
800 lex.printError("Unknown bar font flag "
802 } else if (token == "\\noun") {
804 font.setNoun(font.setLyXMisc(lex.GetString()));
805 } else if (token == "\\color") {
807 font.setLyXColor(lex.GetString());
808 } else if (token == "\\align") {
809 int tmpret = lex.FindToken(string_align);
810 if (tmpret == -1) ++tmpret;
811 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
813 for (; tmpret > 0; --tmpret)
814 tmpret2 = tmpret2 * 2;
815 par->align = LyXAlignment(tmpret2);
817 } else if (token == "\\added_space_top") {
819 par->added_space_top = VSpace(lex.GetString());
820 } else if (token == "\\added_space_bottom") {
822 par->added_space_bottom = VSpace(lex.GetString());
823 } else if (token == "\\pextra_type") {
825 par->pextra_type = lex.GetInteger();
826 } else if (token == "\\pextra_width") {
828 par->pextra_width = lex.GetString();
829 } else if (token == "\\pextra_widthp") {
831 par->pextra_widthp = lex.GetString();
832 } else if (token == "\\pextra_alignment") {
834 par->pextra_alignment = lex.GetInteger();
835 } else if (token == "\\pextra_hfill") {
837 par->pextra_hfill = lex.GetInteger();
838 } else if (token == "\\pextra_start_minipage") {
840 par->pextra_start_minipage = lex.GetInteger();
841 } else if (token == "\\labelwidthstring") {
843 par->labelwidthstring = lex.GetString();
844 // do not delete this token, it is still needed!
845 } else if (token == "\\end_inset") {
846 lyxerr << "Solitary \\end_inset. Missing \\begin_inset?.\n"
847 << "Last inset read was: " << last_inset_read
849 // Simply ignore this. The insets do not have
851 // But insets should read it, it is a part of
852 // the inset isn't it? Lgb.
853 } else if (token == "\\begin_inset") {
854 readInset(lex, par, pos, font);
855 } else if (token == "\\SpecialChar") {
856 LyXLayout const & layout =
857 textclasslist.Style(params.textclass,
860 // Insets don't make sense in a free-spacing context! ---Kayvan
861 if (layout.free_spacing) {
864 string next_token = lex.GetString();
865 if (next_token == "\\-") {
866 par->InsertChar(pos, '-', font);
867 } else if (next_token == "\\protected_separator"
868 || next_token == "~") {
869 par->InsertChar(pos, ' ', font);
871 lex.printError("Token `$$Token' "
873 "paragraph layout!");
878 Inset * inset = new InsetSpecialChar;
879 inset->Read(this, lex);
880 par->InsertInset(pos, inset, font);
883 } else if (token == "\\newline") {
884 par->InsertChar(pos, LyXParagraph::META_NEWLINE, font);
886 } else if (token == "\\LyXTable") {
887 Inset * inset = new InsetTabular(this);
888 inset->Read(this, lex);
889 par->InsertInset(pos, inset, font);
891 } else if (token == "\\hfill") {
892 par->InsertChar(pos, LyXParagraph::META_HFILL, font);
894 } else if (token == "\\protected_separator") { // obsolete
895 // This is a backward compability thingie. (Lgb)
896 // Remove it later some time...introduced with fileformat
898 LyXLayout const & layout =
899 textclasslist.Style(params.textclass,
902 if (layout.free_spacing) {
903 par->InsertChar(pos, ' ', font);
905 Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
906 par->InsertInset(pos, inset, font);
909 } else if (token == "\\bibitem") { // ale970302
911 InsetCommandParams p( "bibitem" );
912 par->bibkey = new InsetBibKey(p);
914 par->bibkey->Read(this, lex);
915 } else if (token == "\\backslash") {
916 par->InsertChar(pos, '\\', font);
918 } else if (token == "\\the_end") {
921 // This should be insurance for the future: (Asger)
922 lex.printError("Unknown token `$$Token'. "
923 "Inserting as text.");
924 string::const_iterator cit = token.begin();
925 string::const_iterator end = token.end();
926 for(; cit != end; ++cit) {
927 par->InsertChar(pos, (*cit), font);
935 void Buffer::readInset(LyXLex & lex, LyXParagraph *& par,
936 int & pos, LyXFont & font)
939 if (lex.GetString() != "\\begin_inset") {
940 lyxerr << "Buffer::readInset: Consistency check failed."
945 string tmptok = lex.GetString();
946 last_inset_read = tmptok;
947 // test the different insets
948 if (tmptok == "Quotes") {
949 Inset * inset = new InsetQuotes;
950 inset->Read(this, lex);
951 par->InsertInset(pos, inset, font);
953 } else if (tmptok == "External") {
954 Inset * inset = new InsetExternal;
955 inset->Read(this, lex);
956 par->InsertInset(pos, inset, font);
958 } else if (tmptok == "FormulaMacro") {
959 Inset * inset = new InsetFormulaMacro;
960 inset->Read(this, lex);
961 par->InsertInset(pos, inset, font);
963 } else if (tmptok == "Formula") {
964 Inset * inset = new InsetFormula;
965 inset->Read(this, lex);
966 par->InsertInset(pos, inset, font);
968 } else if (tmptok == "Figure") {
969 Inset * inset = new InsetFig(100, 100, this);
970 inset->Read(this, lex);
971 par->InsertInset(pos, inset, font);
973 } else if (tmptok == "Info") {
974 Inset * inset = new InsetInfo;
975 inset->Read(this, lex);
976 par->InsertInset(pos, inset, font);
978 } else if (tmptok == "Include") {
979 InsetCommandParams p( "Include" );
980 Inset * inset = new InsetInclude(p, this);
981 inset->Read(this, lex);
982 par->InsertInset(pos, inset, font);
984 } else if (tmptok == "ERT") {
985 Inset * inset = new InsetERT;
986 inset->Read(this, lex);
987 par->InsertInset(pos, inset, font);
989 } else if (tmptok == "Tabular") {
990 Inset * inset = new InsetTabular(this);
991 inset->Read(this, lex);
992 par->InsertInset(pos, inset, font);
994 } else if (tmptok == "Text") {
995 Inset * inset = new InsetText;
996 inset->Read(this, lex);
997 par->InsertInset(pos, inset, font);
999 } else if (tmptok == "Foot") {
1000 Inset * inset = new InsetFoot;
1001 inset->Read(this, lex);
1002 par->InsertInset(pos, inset, font);
1004 } else if (tmptok == "Marginal") {
1005 Inset * inset = new InsetMarginal;
1006 inset->Read(this, lex);
1007 par->InsertInset(pos, inset, font);
1009 } else if (tmptok == "Minipage") {
1010 Inset * inset = new InsetMinipage;
1011 inset->Read(this, lex);
1012 par->InsertInset(pos, inset, font);
1014 } else if (tmptok == "Float") {
1016 string tmptok = lex.GetString();
1017 Inset * inset = new InsetFloat(tmptok);
1018 inset->Read(this, lex);
1019 par->InsertInset(pos, inset, font);
1021 } else if (tmptok == "List") {
1022 Inset * inset = new InsetList;
1023 inset->Read(this, lex);
1024 par->InsertInset(pos, inset, font);
1026 } else if (tmptok == "Theorem") {
1027 Inset * inset = new InsetList;
1028 inset->Read(this, lex);
1029 par->InsertInset(pos, inset, font);
1031 } else if (tmptok == "Caption") {
1032 Inset * inset = new InsetCaption;
1033 inset->Read(this, lex);
1034 par->InsertInset(pos, inset, font);
1036 } else if (tmptok == "GRAPHICS") {
1037 Inset * inset = new InsetGraphics;
1038 inset->Read(this, lex);
1039 par->InsertInset(pos, inset, font);
1041 } else if (tmptok == "LatexCommand") {
1042 InsetCommandParams inscmd;
1045 if (inscmd.getCmdName() == "cite") {
1046 inset = new InsetCitation(inscmd);
1047 } else if (inscmd.getCmdName() == "bibitem") {
1048 lex.printError("Wrong place for bibitem");
1049 inset = new InsetBibKey(inscmd);
1050 } else if (inscmd.getCmdName() == "BibTeX") {
1051 inset = new InsetBibtex(inscmd, this);
1052 } else if (inscmd.getCmdName() == "index") {
1053 inset = new InsetIndex(inscmd);
1054 } else if (inscmd.getCmdName() == "include") {
1055 inset = new InsetInclude(inscmd, this);
1056 } else if (inscmd.getCmdName() == "label") {
1057 inset = new InsetLabel(inscmd);
1058 } else if (inscmd.getCmdName() == "url"
1059 || inscmd.getCmdName() == "htmlurl") {
1060 inset = new InsetUrl(inscmd);
1061 } else if (inscmd.getCmdName() == "ref"
1062 || inscmd.getCmdName() == "pageref"
1063 || inscmd.getCmdName() == "vref"
1064 || inscmd.getCmdName() == "vpageref"
1065 || inscmd.getCmdName() == "prettyref") {
1066 if (!inscmd.getOptions().empty()
1067 || !inscmd.getContents().empty()) {
1068 inset = new InsetRef(inscmd);
1070 } else if (inscmd.getCmdName() == "tableofcontents"
1071 || inscmd.getCmdName() == "listofalgorithms"
1072 || inscmd.getCmdName() == "listoffigures"
1073 || inscmd.getCmdName() == "listoftables") {
1074 inset = new InsetTOC(inscmd);
1075 } else if (inscmd.getCmdName() == "printindex") {
1076 inset = new InsetPrintIndex(inscmd);
1077 } else if (inscmd.getCmdName() == "lyxparent") {
1078 inset = new InsetParent(inscmd, this);
1082 par->InsertInset(pos, inset, font);
1089 bool Buffer::readFile(LyXLex & lex, LyXParagraph * par)
1093 string token(lex.GetString());
1094 if (token == "\\lyxformat") { // the first token _must_ be...
1096 format = lex.GetFloat();
1098 if (LYX_FORMAT - format > 0.05) {
1100 printf(_("Warning: need lyxformat %.2f but found %.2f\n"),
1101 LYX_FORMAT, format);
1103 if (format - LYX_FORMAT > 0.05) {
1104 printf(_("ERROR: need lyxformat %.2f but found %.2f\n"),
1105 LYX_FORMAT, format);
1107 bool the_end = readLyXformat2(lex, par);
1108 // Formats >= 2.13 support "\the_end" marker
1115 WriteAlert(_("Warning!"),
1116 _("Reading of document is not complete"),
1117 _("Maybe the document is truncated"));
1118 // We simulate a safe reading anyways to allow
1119 // users to take the chance... (Asger)
1123 WriteAlert(_("ERROR!"),
1124 _("Old LyX file format found. "
1125 "Use LyX 0.10.x to read this!"));
1129 } else { // "\\lyxformat" not found
1130 WriteAlert(_("ERROR!"), _("Not a LyX file!"));
1133 WriteAlert(_("ERROR!"), _("Unable to read file!"));
1139 // Should probably be moved to somewhere else: BufferView? LyXView?
1140 bool Buffer::save() const
1142 // We don't need autosaves in the immediate future. (Asger)
1143 resetAutosaveTimers();
1147 if (lyxrc.make_backup) {
1148 s = fileName() + '~';
1149 if (!lyxrc.backupdir_path.empty())
1150 s = AddName(lyxrc.backupdir_path,
1151 subst(CleanupPath(s),'/','!'));
1153 // Rename is the wrong way of making a backup,
1154 // this is the correct way.
1155 /* truss cp fil fil2:
1156 lstat("LyXVC3.lyx", 0xEFFFF898) Err#2 ENOENT
1157 stat("LyXVC.lyx", 0xEFFFF688) = 0
1158 open("LyXVC.lyx", O_RDONLY) = 3
1159 open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1160 fstat(4, 0xEFFFF508) = 0
1161 fstat(3, 0xEFFFF508) = 0
1162 read(3, " # T h i s f i l e w".., 8192) = 5579
1163 write(4, " # T h i s f i l e w".., 5579) = 5579
1164 read(3, 0xEFFFD4A0, 8192) = 0
1167 chmod("LyXVC3.lyx", 0100644) = 0
1168 lseek(0, 0, SEEK_CUR) = 46440
1172 // Should proabaly have some more error checking here.
1173 // Should be cleaned up in 0.13, at least a bit.
1174 // Doing it this way, also makes the inodes stay the same.
1175 // This is still not a very good solution, in particular we
1176 // might loose the owner of the backup.
1177 FileInfo finfo(fileName());
1178 if (finfo.exist()) {
1179 mode_t fmode = finfo.getMode();
1180 struct utimbuf times = {
1181 finfo.getAccessTime(),
1182 finfo.getModificationTime() };
1184 ifstream ifs(fileName().c_str());
1185 ofstream ofs(s.c_str(), ios::out|ios::trunc);
1190 ::chmod(s.c_str(), fmode);
1192 if (::utime(s.c_str(), ×)) {
1193 lyxerr << "utime error." << endl;
1196 lyxerr << "LyX was not able to make "
1197 "backupcopy. Beware." << endl;
1202 if (writeFile(fileName(), false)) {
1204 removeAutosaveFile(fileName());
1206 // Saving failed, so backup is not backup
1207 if (lyxrc.make_backup) {
1208 ::rename(s.c_str(), fileName().c_str());
1216 // Returns false if unsuccesful
1217 bool Buffer::writeFile(string const & fname, bool flag) const
1219 // if flag is false writeFile will not create any GUI
1220 // warnings, only cerr.
1221 // Needed for autosave in background or panic save (Matthias 120496)
1223 if (read_only && (fname == filename)) {
1224 // Here we should come with a question if we should
1225 // perform the write anyway.
1227 lyxerr << _("Error! Document is read-only: ")
1230 WriteAlert(_("Error! Document is read-only: "),
1235 FileInfo finfo(fname);
1236 if (finfo.exist() && !finfo.writable()) {
1237 // Here we should come with a question if we should
1238 // try to do the save anyway. (i.e. do a chmod first)
1240 lyxerr << _("Error! Cannot write file: ")
1243 WriteFSAlert(_("Error! Cannot write file: "),
1248 ofstream ofs(fname.c_str());
1251 lyxerr << _("Error! Cannot open file: ")
1254 WriteFSAlert(_("Error! Cannot open file: "),
1260 // Use the standard "C" locale for file output.
1261 ofs.imbue(std::locale::classic());
1264 // The top of the file should not be written by params.
1266 // write out a comment in the top of the file
1267 ofs << '#' << LYX_DOCVERSION
1268 << " created this file. For more info see http://www.lyx.org/\n";
1269 ofs.setf(ios::showpoint|ios::fixed);
1272 char dummy_format[512];
1273 sprintf(dummy_format, "%.2f", LYX_FORMAT);
1274 ofs << "\\lyxformat " << dummy_format << "\n";
1276 ofs << "\\lyxformat " << setw(4) << LYX_FORMAT << "\n";
1278 // now write out the buffer paramters.
1279 params.writeFile(ofs);
1281 char footnoteflag = 0;
1284 // this will write out all the paragraphs
1285 // using recursive descent.
1286 paragraph->writeFile(this, ofs, params, footnoteflag, depth);
1288 // Write marker that shows file is complete
1289 ofs << "\n\\the_end" << endl;
1291 // how to check if close went ok?
1296 void Buffer::writeFileAscii(string const & fname, int linelen)
1298 LyXFont font1, font2;
1300 char c, footnoteflag = 0, depth = 0;
1302 LyXParagraph::size_type i;
1305 int ltype_depth = 0;
1308 int currlinelen = 0;
1310 bool ref_printed = false;
1312 ofstream ofs(fname.c_str());
1314 WriteFSAlert(_("Error: Cannot write file:"), fname);
1318 string fname1 = TmpFileName();
1319 LyXParagraph * par = paragraph;
1325 par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1329 || par->previous->footnoteflag == LyXParagraph::NO_FOOTNOTE
1334 /* begins a footnote environment ? */
1335 if (footnoteflag != par->footnoteflag) {
1336 footnoteflag = par->footnoteflag;
1338 j = strlen(string_footnotekinds[par->footnotekind])+4;
1339 if (currlinelen + j > linelen)
1342 << string_footnotekinds[par->footnotekind] << "] ";
1348 /* begins or ends a deeper area ?*/
1349 if (depth != par->depth) {
1350 if (par->depth > depth) {
1351 while (par->depth > depth) {
1356 while (par->depth < depth) {
1362 /* First write the layout */
1363 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_info);
1414 for (i = 0, actpos = 1; i < par->size(); ++i, ++actpos) {
1415 if (!i && !footnoteflag && !noparbreak){
1417 for(j = 0; j < depth; ++j)
1419 currlinelen = depth * 2;
1421 case 0: /* Standard */
1422 case 4: /* (Sub)Paragraph */
1423 case 5: /* Description */
1425 case 6: /* Abstract */
1426 ofs << "Abstract\n\n";
1428 case 7: /* Bibliography */
1430 ofs << "References\n\n";
1435 ofs << par->labelstring << " ";
1438 if (ltype_depth > depth) {
1439 for(j = ltype_depth - 1; j > depth; --j)
1441 currlinelen += (ltype_depth-depth)*2;
1444 font2 = par->GetFontSettings(params, i);
1445 if (font1.latex() != font2.latex()) {
1446 if (font2.latex() == LyXFont::OFF)
1453 c = par->GetChar(i);
1457 case LyXParagraph::META_INSET:
1458 if ((inset = par->GetInset(i))) {
1460 inset->Ascii(this, ofs);
1461 currlinelen += (ofs.tellp() - fpos);
1462 actpos += (ofs.tellp() - fpos) - 1;
1465 case LyXParagraph::META_NEWLINE:
1467 for(j = 0; j < depth; ++j)
1469 currlinelen = depth * 2;
1470 if (ltype_depth > depth) {
1471 for(j = ltype_depth;
1474 currlinelen += (ltype_depth - depth) * 2;
1477 case LyXParagraph::META_HFILL:
1484 if (currlinelen > linelen - 10
1485 && c == ' ' && i + 2 < par->size()) {
1487 for(j = 0; j < depth; ++j)
1489 currlinelen = depth * 2;
1490 if (ltype_depth > depth) {
1491 for(j = ltype_depth;
1494 currlinelen += (ltype_depth-depth)*2;
1496 } else if (c != '\0')
1499 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1511 void Buffer::makeLaTeXFile(string const & fname,
1512 string const & original_path,
1513 bool nice, bool only_body)
1515 lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1517 niceFile = nice; // this will be used by Insetincludes.
1519 tex_code_break_column = lyxrc.ascii_linelen;
1521 LyXTextClass const & tclass =
1522 textclasslist.TextClass(params.textclass);
1524 ofstream ofs(fname.c_str());
1526 WriteFSAlert(_("Error: Cannot open file: "), fname);
1530 // validate the buffer.
1531 lyxerr[Debug::LATEX] << " Validating buffer..." << endl;
1532 LaTeXFeatures features(params, tclass.numLayouts());
1534 lyxerr[Debug::LATEX] << " Buffer validation done." << endl;
1537 // The starting paragraph of the coming rows is the
1538 // first paragraph of the document. (Asger)
1539 texrow.start(paragraph, 0);
1541 if (!only_body && nice) {
1542 ofs << "%% " LYX_DOCVERSION " created this file. "
1543 "For more info, see http://www.lyx.org/.\n"
1544 "%% Do not edit unless you really know what "
1549 lyxerr.debug() << "lyx header finished" << endl;
1550 // There are a few differences between nice LaTeX and usual files:
1551 // usual is \batchmode and has a
1552 // special input@path to allow the including of figures
1553 // with either \input or \includegraphics (what figinsets do).
1554 // batchmode is not set if there is a tex_code_break_column.
1555 // In this case somebody is interested in the generated LaTeX,
1556 // so this is OK. input@path is set when the actual parameter
1557 // original_path is set. This is done for usual tex-file, but not
1558 // for nice-latex-file. (Matthias 250696)
1561 // code for usual, NOT nice-latex-file
1562 ofs << "\\batchmode\n"; // changed
1563 // from \nonstopmode
1566 if (!original_path.empty()) {
1567 ofs << "\\makeatletter\n"
1568 << "\\def\\input@path{{"
1569 << original_path << "/}}\n"
1570 << "\\makeatother\n";
1576 ofs << "\\documentclass";
1578 string options; // the document class options.
1580 if (tokenPos(tclass.opt_fontsize(),
1581 '|', params.fontsize) >= 0) {
1582 // only write if existing in list (and not default)
1583 options += params.fontsize;
1588 if (!params.use_geometry &&
1589 (params.paperpackage == BufferParams::PACKAGE_NONE)) {
1590 switch (params.papersize) {
1591 case BufferParams::PAPER_A4PAPER:
1592 options += "a4paper,";
1594 case BufferParams::PAPER_USLETTER:
1595 options += "letterpaper,";
1597 case BufferParams::PAPER_A5PAPER:
1598 options += "a5paper,";
1600 case BufferParams::PAPER_B5PAPER:
1601 options += "b5paper,";
1603 case BufferParams::PAPER_EXECUTIVEPAPER:
1604 options += "executivepaper,";
1606 case BufferParams::PAPER_LEGALPAPER:
1607 options += "legalpaper,";
1613 if (params.sides != tclass.sides()) {
1614 switch (params.sides) {
1615 case LyXTextClass::OneSide:
1616 options += "oneside,";
1618 case LyXTextClass::TwoSides:
1619 options += "twoside,";
1626 if (params.columns != tclass.columns()) {
1627 if (params.columns == 2)
1628 options += "twocolumn,";
1630 options += "onecolumn,";
1633 if (!params.use_geometry
1634 && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1635 options += "landscape,";
1637 // language should be a parameter to \documentclass
1638 bool use_babel = false;
1639 if (params.language_info->lang() == "hebrew") // This seems necessary
1640 features.UsedLanguages.insert(default_language);
1641 if (params.language != "default" ||
1642 !features.UsedLanguages.empty() ) {
1644 for (LaTeXFeatures::LanguageList::const_iterator cit =
1645 features.UsedLanguages.begin();
1646 cit != features.UsedLanguages.end(); ++cit)
1647 options += (*cit)->lang() + ",";
1648 options += params.language_info->lang() + ',';
1651 // the user-defined options
1652 if (!params.options.empty()) {
1653 options += params.options + ',';
1656 if (!options.empty()){
1657 options = strip(options, ',');
1658 ofs << '[' << options << ']';
1662 << textclasslist.LatexnameOfClass(params.textclass)
1665 // end of \documentclass defs
1667 // font selection must be done before loading fontenc.sty
1668 if (params.fonts != "default") {
1669 ofs << "\\usepackage{" << params.fonts << "}\n";
1672 // this one is not per buffer
1673 if (lyxrc.fontenc != "default") {
1674 ofs << "\\usepackage[" << lyxrc.fontenc
1679 if (params.inputenc == "auto") {
1680 string doc_encoding =
1681 params.language_info->encoding()->LatexName();
1683 // Create a list with all the input encodings used
1685 set<string> encodings;
1686 for (LaTeXFeatures::LanguageList::const_iterator it =
1687 features.UsedLanguages.begin();
1688 it != features.UsedLanguages.end(); ++it)
1689 if ((*it)->encoding()->LatexName() != doc_encoding)
1690 encodings.insert((*it)->encoding()->LatexName());
1692 ofs << "\\usepackage[";
1693 for (set<string>::const_iterator it = encodings.begin();
1694 it != encodings.end(); ++it)
1696 ofs << doc_encoding << "]{inputenc}\n";
1698 } else if (params.inputenc != "default") {
1699 ofs << "\\usepackage[" << params.inputenc
1704 // At the very beginning the text parameters.
1705 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
1706 switch (params.paperpackage) {
1707 case BufferParams::PACKAGE_A4:
1708 ofs << "\\usepackage{a4}\n";
1711 case BufferParams::PACKAGE_A4WIDE:
1712 ofs << "\\usepackage{a4wide}\n";
1715 case BufferParams::PACKAGE_WIDEMARGINSA4:
1716 ofs << "\\usepackage[widemargins]{a4}\n";
1721 if (params.use_geometry) {
1722 ofs << "\\usepackage{geometry}\n";
1724 ofs << "\\geometry{verbose";
1725 if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1726 ofs << ",landscape";
1727 switch (params.papersize2) {
1728 case BufferParams::VM_PAPER_CUSTOM:
1729 if (!params.paperwidth.empty())
1730 ofs << ",paperwidth="
1731 << params.paperwidth;
1732 if (!params.paperheight.empty())
1733 ofs << ",paperheight="
1734 << params.paperheight;
1736 case BufferParams::VM_PAPER_USLETTER:
1737 ofs << ",letterpaper";
1739 case BufferParams::VM_PAPER_USLEGAL:
1740 ofs << ",legalpaper";
1742 case BufferParams::VM_PAPER_USEXECUTIVE:
1743 ofs << ",executivepaper";
1745 case BufferParams::VM_PAPER_A3:
1748 case BufferParams::VM_PAPER_A4:
1751 case BufferParams::VM_PAPER_A5:
1754 case BufferParams::VM_PAPER_B3:
1757 case BufferParams::VM_PAPER_B4:
1760 case BufferParams::VM_PAPER_B5:
1764 // default papersize ie BufferParams::VM_PAPER_DEFAULT
1765 switch (lyxrc.default_papersize) {
1766 case BufferParams::PAPER_DEFAULT: // keep compiler happy
1767 case BufferParams::PAPER_USLETTER:
1768 ofs << ",letterpaper";
1770 case BufferParams::PAPER_LEGALPAPER:
1771 ofs << ",legalpaper";
1773 case BufferParams::PAPER_EXECUTIVEPAPER:
1774 ofs << ",executivepaper";
1776 case BufferParams::PAPER_A3PAPER:
1779 case BufferParams::PAPER_A4PAPER:
1782 case BufferParams::PAPER_A5PAPER:
1785 case BufferParams::PAPER_B5PAPER:
1790 if (!params.topmargin.empty())
1791 ofs << ",tmargin=" << params.topmargin;
1792 if (!params.bottommargin.empty())
1793 ofs << ",bmargin=" << params.bottommargin;
1794 if (!params.leftmargin.empty())
1795 ofs << ",lmargin=" << params.leftmargin;
1796 if (!params.rightmargin.empty())
1797 ofs << ",rmargin=" << params.rightmargin;
1798 if (!params.headheight.empty())
1799 ofs << ",headheight=" << params.headheight;
1800 if (!params.headsep.empty())
1801 ofs << ",headsep=" << params.headsep;
1802 if (!params.footskip.empty())
1803 ofs << ",footskip=" << params.footskip;
1807 if (params.use_amsmath
1808 && !tclass.provides(LyXTextClass::amsmath)) {
1809 ofs << "\\usepackage{amsmath}\n";
1813 if (tokenPos(tclass.opt_pagestyle(),
1814 '|', params.pagestyle) >= 0) {
1815 if (params.pagestyle == "fancy") {
1816 ofs << "\\usepackage{fancyhdr}\n";
1819 ofs << "\\pagestyle{" << params.pagestyle << "}\n";
1823 // We try to load babel late, in case it interferes
1824 // with other packages.
1826 ofs << lyxrc.language_package << endl;
1830 if (params.secnumdepth != tclass.secnumdepth()) {
1831 ofs << "\\setcounter{secnumdepth}{"
1832 << params.secnumdepth
1836 if (params.tocdepth != tclass.tocdepth()) {
1837 ofs << "\\setcounter{tocdepth}{"
1843 if (params.paragraph_separation) {
1844 switch (params.defskip.kind()) {
1845 case VSpace::SMALLSKIP:
1846 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
1848 case VSpace::MEDSKIP:
1849 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1851 case VSpace::BIGSKIP:
1852 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
1854 case VSpace::LENGTH:
1855 ofs << "\\setlength\\parskip{"
1856 << params.defskip.length().asLatexString()
1859 default: // should never happen // Then delete it.
1860 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1865 ofs << "\\setlength\\parindent{0pt}\n";
1869 // Now insert the LyX specific LaTeX commands...
1871 // The optional packages;
1872 string preamble(features.getPackages());
1874 // this might be useful...
1875 preamble += "\n\\makeatletter\n";
1877 // Some macros LyX will need
1878 string tmppreamble(features.getMacros());
1880 if (!tmppreamble.empty()) {
1881 preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1882 "LyX specific LaTeX commands.\n"
1883 + tmppreamble + '\n';
1886 // the text class specific preamble
1887 tmppreamble = features.getTClassPreamble();
1888 if (!tmppreamble.empty()) {
1889 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1890 "Textclass specific LaTeX commands.\n"
1891 + tmppreamble + '\n';
1894 /* the user-defined preamble */
1895 if (!params.preamble.empty()) {
1896 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1897 "User specified LaTeX commands.\n"
1898 + params.preamble + '\n';
1901 preamble += "\\makeatother\n";
1903 // Itemize bullet settings need to be last in case the user
1904 // defines their own bullets that use a package included
1905 // in the user-defined preamble -- ARRae
1906 // Actually it has to be done much later than that
1907 // since some packages like frenchb make modifications
1908 // at \begin{document} time -- JMarc
1910 for (int i = 0; i < 4; ++i) {
1911 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
1912 if (bullets_def.empty())
1913 bullets_def="\\AtBeginDocument{\n";
1914 bullets_def += " \\renewcommand{\\labelitemi";
1916 // `i' is one less than the item to modify
1923 bullets_def += "ii";
1929 bullets_def += "}{" +
1930 params.user_defined_bullets[i].getText()
1935 if (!bullets_def.empty())
1936 preamble += bullets_def + "}\n\n";
1938 for (int j = countChar(preamble, '\n'); j-- ;) {
1945 ofs << "\\begin{document}\n";
1948 lyxerr.debug() << "preamble finished, now the body." << endl;
1949 if (!lyxrc.language_auto_begin && params.language != "default") {
1950 ofs << subst(lyxrc.language_command_begin, "$$lang",
1956 latexParagraphs(ofs, paragraph, 0, texrow);
1958 // add this just in case after all the paragraphs
1962 if (!lyxrc.language_auto_end && params.language != "default") {
1963 ofs << subst(lyxrc.language_command_end, "$$lang",
1970 ofs << "\\end{document}\n";
1973 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
1975 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
1979 // Just to be sure. (Asger)
1982 // tex_code_break_column's value is used to decide
1983 // if we are in batchmode or not (within mathed_write()
1984 // in math_write.C) so we must set it to a non-zero
1985 // value when we leave otherwise we save incorrect .lyx files.
1986 tex_code_break_column = lyxrc.ascii_linelen;
1990 lyxerr << "File was not closed properly." << endl;
1993 lyxerr.debug() << "Finished making latex file." << endl;
1998 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2000 void Buffer::latexParagraphs(ostream & ofs, LyXParagraph * par,
2001 LyXParagraph * endpar, TexRow & texrow) const
2003 bool was_title = false;
2004 bool already_title = false;
2005 std::ostringstream ftnote;
2010 while (par != endpar) {
2013 lyxerr[Debug::LATEX] << "Error in latexParagraphs."
2016 LyXLayout const & layout =
2017 textclasslist.Style(params.textclass,
2020 if (layout.intitle) {
2021 if (already_title) {
2022 lyxerr <<"Error in latexParagraphs: You"
2023 " should not mix title layouts"
2024 " with normal ones." << endl;
2027 } else if (was_title && !already_title) {
2028 ofs << "\\maketitle\n";
2030 already_title = true;
2033 // We are at depth 0 so we can just use
2034 // ordinary \footnote{} generation
2035 // flag this with ftcount
2037 if (layout.isEnvironment()
2038 || par->pextra_type != LyXParagraph::PEXTRA_NONE) {
2039 par = par->TeXEnvironment(this, params, ofs, texrow
2041 ,ftnote, ft_texrow, ftcount
2045 par = par->TeXOnePar(this, params, ofs, texrow, false
2048 ftnote, ft_texrow, ftcount
2053 // Write out what we've generated...
2056 ofs << "\\addtocounter{footnote}{-"
2060 ofs << ftnote.str();
2061 texrow += ft_texrow;
2063 // The extra .c_str() is needed when we use
2064 // lyxstring instead of the STL string class.
2065 ftnote.str(string().c_str());
2070 // It might be that we only have a title in this document
2071 if (was_title && !already_title) {
2072 ofs << "\\maketitle\n";
2078 bool Buffer::isLatex() const
2080 return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2084 bool Buffer::isLinuxDoc() const
2086 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2090 bool Buffer::isLiterate() const
2092 return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2096 bool Buffer::isDocBook() const
2098 return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2102 bool Buffer::isSGML() const
2104 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2105 textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2109 void Buffer::sgmlOpenTag(ostream & os, int depth,
2110 string const & latexname) const
2112 os << string(depth, ' ') << "<" << latexname << ">\n";
2116 void Buffer::sgmlCloseTag(ostream & os, int depth,
2117 string const & latexname) const
2119 os << string(depth, ' ') << "</" << latexname << ">\n";
2123 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2125 LyXParagraph * par = paragraph;
2127 niceFile = nice; // this will be used by Insetincludes.
2129 string top_element = textclasslist.LatexnameOfClass(params.textclass);
2130 string environment_stack[10];
2133 int depth = 0; // paragraph depth
2135 ofstream ofs(fname.c_str());
2138 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2142 LyXTextClass const & tclass =
2143 textclasslist.TextClass(params.textclass);
2145 LaTeXFeatures features(params, tclass.numLayouts());
2149 tex_code_break_column = lyxrc.ascii_linelen;
2151 //tex_code_break_column = 0;
2156 string sgml_includedfiles=features.getIncludedFiles();
2158 if (params.preamble.empty() && sgml_includedfiles.empty()) {
2159 ofs << "<!doctype linuxdoc system>\n\n";
2161 ofs << "<!doctype linuxdoc system [ "
2162 << params.preamble << sgml_includedfiles << " \n]>\n\n";
2165 if(params.options.empty())
2166 sgmlOpenTag(ofs, 0, top_element);
2168 string top = top_element;
2170 top += params.options;
2171 sgmlOpenTag(ofs, 0, top);
2175 ofs << "<!-- " << LYX_DOCVERSION
2176 << " created this file. For more info see http://www.lyx.org/"
2180 int desc_on = 0; // description mode
2181 LyXLayout const & style =
2182 textclasslist.Style(params.textclass,
2185 // treat <toc> as a special case for compatibility with old code
2186 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2187 Inset * inset = par->GetInset(0);
2188 Inset::Code lyx_code = inset->LyxCode();
2189 if (lyx_code == Inset::TOC_CODE){
2190 string temp = "toc";
2191 sgmlOpenTag(ofs, depth, temp);
2195 linuxDocHandleFootnote(ofs, par, depth);
2201 // environment tag closing
2202 for( ; depth > par->depth; --depth) {
2203 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2204 environment_stack[depth].erase();
2207 // write opening SGML tags
2208 switch(style.latextype) {
2209 case LATEX_PARAGRAPH:
2210 if(depth == par->depth
2211 && !environment_stack[depth].empty()) {
2212 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2213 environment_stack[depth].erase();
2219 sgmlOpenTag(ofs, depth, style.latexname());
2224 LinuxDocError(par, 0,
2225 _("Error : Wrong depth for"
2226 " LatexType Command.\n"));
2228 if (!environment_stack[depth].empty()){
2229 sgmlCloseTag(ofs, depth,
2230 environment_stack[depth]);
2234 environment_stack[depth].erase();
2235 sgmlOpenTag(ofs, depth, style.latexname());
2238 case LATEX_ENVIRONMENT:
2239 case LATEX_ITEM_ENVIRONMENT:
2240 if(depth == par->depth
2241 && environment_stack[depth] != style.latexname()
2242 && !environment_stack[depth].empty()) {
2244 sgmlCloseTag(ofs, depth,
2245 environment_stack[depth]);
2246 environment_stack[depth].erase();
2248 if (depth < par->depth) {
2250 environment_stack[depth].erase();
2252 if (environment_stack[depth] != style.latexname()) {
2255 sgmlOpenTag(ofs, depth, temp);
2257 environment_stack[depth] = style.latexname();
2258 sgmlOpenTag(ofs, depth,
2259 environment_stack[depth]);
2261 if(style.latextype == LATEX_ENVIRONMENT) break;
2263 desc_on = (style.labeltype == LABEL_MANUAL);
2270 sgmlOpenTag(ofs, depth + 1, item_name);
2273 sgmlOpenTag(ofs, depth, style.latexname());
2280 SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2284 linuxDocHandleFootnote(ofs, par, depth);
2286 while(par && par->IsDummy());
2290 // write closing SGML tags
2291 switch(style.latextype) {
2293 case LATEX_ENVIRONMENT:
2294 case LATEX_ITEM_ENVIRONMENT:
2297 sgmlCloseTag(ofs, depth, style.latexname());
2303 for(; depth > 0; --depth)
2304 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2306 if(!environment_stack[depth].empty())
2307 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2311 sgmlCloseTag(ofs, 0, top_element);
2315 // How to check for successful close
2320 void Buffer::linuxDocHandleFootnote(ostream & os, LyXParagraph * & par,
2323 string tag = "footnote";
2325 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2326 sgmlOpenTag(os, depth + 1, tag);
2327 SimpleLinuxDocOnePar(os, par, 0, depth + 1);
2328 sgmlCloseTag(os, depth + 1, tag);
2335 void Buffer::DocBookHandleCaption(ostream & os, string & inner_tag,
2336 int const depth, int desc_on,
2337 LyXParagraph * & par)
2339 LyXParagraph * tpar = par;
2342 && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE)
2344 && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2348 tpar->layout == textclasslist.NumberOfLayout(params.textclass,
2349 "Caption").second) {
2350 sgmlOpenTag(os, depth + 1, inner_tag);
2352 SimpleDocBookOnePar(os, extra_par, tpar,
2353 desc_on, depth + 2);
2354 sgmlCloseTag(os, depth+1, inner_tag);
2355 if(!extra_par.empty())
2362 void Buffer::DocBookHandleFootnote(ostream & os, LyXParagraph * & par,
2365 string tag, inner_tag;
2366 string tmp_par, extra_par;
2367 bool inner_span = false;
2370 // Someone should give this enum a proper name (Lgb)
2378 SOME_ENUM last = NO_ONE;
2379 SOME_ENUM present = FOOTNOTE_LIKE;
2381 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2382 if(last == present) {
2384 if(!tmp_par.empty()) {
2387 sgmlCloseTag(os, depth + 1, inner_tag);
2388 sgmlOpenTag(os, depth + 1, inner_tag);
2395 if(!inner_tag.empty()) sgmlCloseTag(os, depth + 1,
2397 if(!extra_par.empty()) os << extra_par;
2398 if(!tag.empty()) sgmlCloseTag(os, depth, tag);
2401 switch (par->footnotekind) {
2402 case LyXParagraph::FOOTNOTE:
2403 case LyXParagraph::ALGORITHM:
2406 present = FOOTNOTE_LIKE;
2409 case LyXParagraph::MARGIN:
2412 present = MARGIN_LIKE;
2415 case LyXParagraph::FIG:
2416 case LyXParagraph::WIDE_FIG:
2418 inner_tag = "title";
2422 case LyXParagraph::TAB:
2423 case LyXParagraph::WIDE_TAB:
2425 inner_tag = "title";
2430 sgmlOpenTag(os, depth, tag);
2431 if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2432 DocBookHandleCaption(os, inner_tag, depth,
2436 sgmlOpenTag(os, depth + 1, inner_tag);
2439 // ignore all caption here, we processed them above!!!
2440 if (par->layout != textclasslist
2441 .NumberOfLayout(params.textclass,
2442 "Caption").second) {
2443 std::ostringstream ost;
2444 SimpleDocBookOnePar(ost, extra_par, par,
2445 desc_on, depth + 2);
2446 tmp_par += ost.str().c_str();
2448 tmp_par = frontStrip(strip(tmp_par));
2454 if(!inner_tag.empty()) sgmlCloseTag(os, depth + 1, inner_tag);
2455 if(!extra_par.empty()) os << extra_par;
2456 if(!tag.empty()) sgmlCloseTag(os, depth, tag);
2461 // push a tag in a style stack
2462 void Buffer::push_tag(ostream & os, string const & tag,
2463 int & pos, char stack[5][3])
2465 #warning Use a real stack! (Lgb)
2466 // pop all previous tags
2467 for (int j = pos; j >= 0; --j)
2468 os << "</" << stack[j] << ">";
2471 sprintf(stack[++pos], "%s", tag.c_str());
2474 for (int i = 0; i <= pos; ++i)
2475 os << "<" << stack[i] << ">";
2479 void Buffer::pop_tag(ostream & os, string const & tag,
2480 int & pos, char stack[5][3])
2482 #ifdef WITH_WARNINGS
2483 #warning Use a real stack! (Lgb)
2485 // Please, Lars, do not remove the global variable. I already
2486 // had to reintroduce it twice! (JMarc)
2489 // pop all tags till specified one
2490 for (j = pos; (j >= 0) && (strcmp(stack[j], tag.c_str())); --j)
2491 os << "</" << stack[j] << ">";
2494 os << "</" << tag << ">";
2496 // push all tags, but the specified one
2497 for (j = j + 1; j <= pos; ++j) {
2498 os << "<" << stack[j] << ">";
2499 strcpy(stack[j-1], stack[j]);
2505 // Handle internal paragraph parsing -- layout already processed.
2507 // checks, if newcol chars should be put into this line
2508 // writes newline, if necessary.
2510 void linux_doc_line_break(ostream & os, unsigned int & colcount,
2511 const unsigned int newcol)
2514 if (colcount > lyxrc.ascii_linelen) {
2516 colcount = newcol; // assume write after this call
2521 void Buffer::SimpleLinuxDocOnePar(ostream & os, LyXParagraph * par,
2522 int desc_on, int const /*depth*/)
2524 LyXFont font1, font2;
2527 LyXParagraph::size_type main_body;
2529 LyXLayout const & style = textclasslist.Style(params.textclass,
2532 char family_type = 0; // family font flag
2533 bool is_bold = false; // series font flag
2534 char shape_type = 0; // shape font flag
2535 bool is_em = false; // emphasis (italic) font flag
2537 int stack_num = -1; // style stack position
2538 // Can this be rewritten to use a std::stack, please. (Lgb)
2539 char stack[5][3]; // style stack
2540 unsigned int char_line_count = 5; // Heuristic choice ;-)
2542 if (style.labeltype != LABEL_MANUAL)
2545 main_body = par->BeginningOfMainBody();
2547 // gets paragraph main font
2549 font1 = style.labelfont;
2554 // parsing main loop
2555 for (LyXParagraph::size_type i = 0;
2556 i < par->size(); ++i) {
2568 font2 = par->getFont(params, i);
2570 if (font1.family() != font2.family()) {
2571 switch(family_type) {
2573 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2574 push_tag(os, "tt", stack_num, stack);
2577 else if (font2.family() == LyXFont::SANS_FAMILY) {
2578 push_tag(os, "sf", stack_num, stack);
2583 pop_tag(os, "tt", stack_num, stack);
2584 if (font2.family() == LyXFont::SANS_FAMILY) {
2585 push_tag(os, "sf", stack_num, stack);
2592 pop_tag(os, "sf", stack_num, stack);
2593 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2594 push_tag(os, "tt", stack_num, stack);
2603 if (font1.series() != font2.series()) {
2604 if (font2.series() == LyXFont::BOLD_SERIES) {
2605 push_tag(os, "bf", stack_num, stack);
2607 } else if (is_bold) {
2608 pop_tag(os, "bf", stack_num, stack);
2613 // handle italic and slanted fonts
2614 if (font1.shape() != font2.shape()) {
2615 switch(shape_type) {
2617 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2618 push_tag(os, "it", stack_num, stack);
2620 } else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2621 push_tag(os, "sl", stack_num, stack);
2626 pop_tag(os, "it", stack_num, stack);
2627 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2628 push_tag(os, "sl", stack_num, stack);
2635 pop_tag(os, "sl", stack_num, stack);
2636 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2637 push_tag(os, "it", stack_num, stack);
2645 if (font1.emph() != font2.emph()) {
2646 if (font2.emph() == LyXFont::ON) {
2647 push_tag(os, "em", stack_num, stack);
2650 pop_tag(os, "em", stack_num, stack);
2655 c = par->GetChar(i);
2657 if (c == LyXParagraph::META_INSET) {
2658 inset = par->GetInset(i);
2659 inset->Linuxdoc(this, os);
2662 if (font2.latex() == LyXFont::ON) {
2663 // "TeX"-Mode on == > SGML-Mode on.
2665 os << c; // see LaTeX-Generation...
2669 if (par->linuxDocConvertChar(c, sgml_string)
2670 && !style.free_spacing) { // in freespacing
2672 // non-breaking characters
2676 linux_doc_line_break(os, char_line_count, 6);
2680 linux_doc_line_break(os, char_line_count, 1);
2685 char_line_count += sgml_string.length();
2691 // needed if there is an optional argument but no contents
2692 if (main_body > 0 && main_body == par->size()) {
2696 // pop all defined Styles
2697 for (j = stack_num; j >= 0; --j) {
2698 linux_doc_line_break(os,
2700 3 + strlen(stack[j]));
2701 os << "</" << stack[j] << ">";
2704 // resets description flag correctly
2707 // <tag> not closed...
2708 linux_doc_line_break(os, char_line_count, 6);
2712 // fprintf(file, "</p>");
2718 // Print an error message.
2719 void Buffer::LinuxDocError(LyXParagraph * par, int pos,
2720 string const & message)
2722 // insert an error marker in text
2723 InsetError * new_inset = new InsetError(message);
2724 par->InsertInset(pos, new_inset);
2727 // This constant defines the maximum number of
2728 // environment layouts that can be nesteded.
2729 // The same applies for command layouts.
2730 // These values should be more than enough.
2731 // José Matos (1999/07/22)
2733 enum { MAX_NEST_LEVEL = 25};
2735 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
2737 LyXParagraph * par = paragraph;
2739 niceFile = nice; // this will be used by Insetincludes.
2741 string top_element= textclasslist.LatexnameOfClass(params.textclass);
2742 // Please use a real stack.
2743 string environment_stack[MAX_NEST_LEVEL];
2744 string environment_inner[MAX_NEST_LEVEL];
2745 // Please use a real stack.
2746 string command_stack[MAX_NEST_LEVEL];
2747 bool command_flag= false;
2748 int command_depth= 0, command_base= 0, cmd_depth= 0;
2750 string item_name, command_name;
2751 string c_depth, c_params, tmps;
2753 int depth = 0; // paragraph depth
2754 LyXTextClass const & tclass =
2755 textclasslist.TextClass(params.textclass);
2757 LaTeXFeatures features(params, tclass.numLayouts());
2761 tex_code_break_column = lyxrc.ascii_linelen;
2763 //tex_code_break_column = 0;
2765 ofstream ofs(fname.c_str());
2767 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2774 string sgml_includedfiles=features.getIncludedFiles();
2776 ofs << "<!doctype " << top_element
2777 << " public \"-//OASIS//DTD DocBook V3.1//EN\"";
2779 if (params.preamble.empty() && sgml_includedfiles.empty())
2782 ofs << "\n [ " << params.preamble
2783 << sgml_includedfiles << " \n]>\n\n";
2785 if(params.options.empty())
2786 sgmlOpenTag(ofs, 0, top_element);
2788 string top = top_element;
2790 top += params.options;
2791 sgmlOpenTag(ofs, 0, top);
2795 ofs << "<!-- DocBook file was created by " << LYX_DOCVERSION
2796 << "\n See http://www.lyx.org/ for more information -->\n";
2799 int desc_on = 0; // description mode
2800 LyXLayout const & style =
2801 textclasslist.Style(params.textclass,
2804 // environment tag closing
2805 for( ; depth > par->depth; --depth) {
2806 if(environment_inner[depth] != "!-- --") {
2807 item_name= "listitem";
2808 sgmlCloseTag(ofs, command_depth + depth,
2810 if( environment_inner[depth] == "varlistentry")
2811 sgmlCloseTag(ofs, depth+command_depth,
2812 environment_inner[depth]);
2814 sgmlCloseTag(ofs, depth + command_depth,
2815 environment_stack[depth]);
2816 environment_stack[depth].erase();
2817 environment_inner[depth].erase();
2820 if(depth == par->depth
2821 && environment_stack[depth] != style.latexname()
2822 && !environment_stack[depth].empty()) {
2823 if(environment_inner[depth] != "!-- --") {
2824 item_name= "listitem";
2825 sgmlCloseTag(ofs, command_depth+depth,
2827 if( environment_inner[depth] == "varlistentry")
2829 depth + command_depth,
2830 environment_inner[depth]);
2833 sgmlCloseTag(ofs, depth + command_depth,
2834 environment_stack[depth]);
2836 environment_stack[depth].erase();
2837 environment_inner[depth].erase();
2840 // Write opening SGML tags.
2841 switch(style.latextype) {
2842 case LATEX_PARAGRAPH:
2843 if(style.latexname() != "dummy")
2844 sgmlOpenTag(ofs, depth+command_depth,
2850 LinuxDocError(par, 0,
2851 _("Error : Wrong depth for "
2852 "LatexType Command.\n"));
2854 command_name = style.latexname();
2856 tmps = style.latexparam();
2857 c_params = split(tmps, c_depth,'|');
2859 cmd_depth= atoi(c_depth.c_str());
2862 if(cmd_depth<command_base) {
2863 for(int j = command_depth;
2864 j >= command_base; --j)
2865 if(!command_stack[j].empty())
2866 sgmlCloseTag(ofs, j, command_stack[j]);
2867 command_depth= command_base= cmd_depth;
2868 } else if(cmd_depth <= command_depth) {
2869 for(int j = command_depth;
2870 j >= cmd_depth; --j)
2872 if(!command_stack[j].empty())
2873 sgmlCloseTag(ofs, j, command_stack[j]);
2874 command_depth= cmd_depth;
2876 command_depth= cmd_depth;
2878 command_depth = command_base = cmd_depth;
2879 command_flag = true;
2881 command_stack[command_depth]= command_name;
2883 // treat label as a special case for
2884 // more WYSIWYM handling.
2885 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2886 Inset * inset = par->GetInset(0);
2887 Inset::Code lyx_code = inset->LyxCode();
2888 if (lyx_code == Inset::LABEL_CODE){
2889 command_name += " id=\"";
2890 command_name += (static_cast<InsetCommand *>(inset))->getContents();
2891 command_name += "\"";
2896 sgmlOpenTag(ofs, depth + command_depth, command_name);
2897 item_name = "title";
2898 sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
2901 case LATEX_ENVIRONMENT:
2902 case LATEX_ITEM_ENVIRONMENT:
2903 if (depth < par->depth) {
2905 environment_stack[depth].erase();
2908 if (environment_stack[depth] != style.latexname()) {
2909 environment_stack[depth] = style.latexname();
2910 environment_inner[depth] = "!-- --";
2911 sgmlOpenTag(ofs, depth + command_depth,
2912 environment_stack[depth]);
2914 if(environment_inner[depth] != "!-- --") {
2915 item_name= "listitem";
2917 command_depth + depth,
2919 if (environment_inner[depth] == "varlistentry")
2921 depth + command_depth,
2922 environment_inner[depth]);
2926 if(style.latextype == LATEX_ENVIRONMENT) {
2927 if(!style.latexparam().empty())
2928 sgmlOpenTag(ofs, depth + command_depth,
2929 style.latexparam());
2933 desc_on = (style.labeltype == LABEL_MANUAL);
2936 environment_inner[depth]= "varlistentry";
2938 environment_inner[depth]= "listitem";
2940 sgmlOpenTag(ofs, depth + 1 + command_depth,
2941 environment_inner[depth]);
2945 sgmlOpenTag(ofs, depth + 1 + command_depth,
2949 sgmlOpenTag(ofs, depth + 1 + command_depth,
2954 sgmlOpenTag(ofs, depth + command_depth,
2963 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
2964 depth + 1 + command_depth);
2967 DocBookHandleFootnote(ofs, par,
2968 depth + 1 + command_depth);
2970 while(par && par->IsDummy());
2973 // write closing SGML tags
2974 switch(style.latextype) {
2977 sgmlCloseTag(ofs, depth + command_depth, end_tag);
2979 case LATEX_ENVIRONMENT:
2980 if(!style.latexparam().empty())
2981 sgmlCloseTag(ofs, depth + command_depth,
2982 style.latexparam());
2984 case LATEX_ITEM_ENVIRONMENT:
2985 if(desc_on == 1) break;
2987 sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
2989 case LATEX_PARAGRAPH:
2990 if(style.latexname() != "dummy")
2991 sgmlCloseTag(ofs, depth + command_depth,
2995 sgmlCloseTag(ofs, depth + command_depth,
3002 for(; depth >= 0; --depth) {
3003 if(!environment_stack[depth].empty()) {
3004 if(environment_inner[depth] != "!-- --") {
3005 item_name= "listitem";
3006 sgmlCloseTag(ofs, command_depth + depth,
3008 if( environment_inner[depth] == "varlistentry")
3009 sgmlCloseTag(ofs, depth + command_depth,
3010 environment_inner[depth]);
3013 sgmlCloseTag(ofs, depth + command_depth,
3014 environment_stack[depth]);
3018 for(int j = command_depth; j >= command_base; --j)
3019 if(!command_stack[j].empty())
3020 sgmlCloseTag(ofs, j, command_stack[j]);
3024 sgmlCloseTag(ofs, 0, top_element);
3028 // How to check for successful close
3032 void Buffer::SimpleDocBookOnePar(ostream & os, string & extra,
3033 LyXParagraph * par, int & desc_on,
3036 bool emph_flag = false;
3038 LyXLayout const & style = textclasslist.Style(params.textclass,
3041 LyXParagraph::size_type main_body;
3042 if (style.labeltype != LABEL_MANUAL)
3045 main_body = par->BeginningOfMainBody();
3047 // gets paragraph main font
3048 LyXFont font1 = main_body > 0 ? style.labelfont : style.font;
3050 int char_line_count = depth;
3051 if(!style.free_spacing)
3052 for (int j = 0; j < depth; ++j)
3055 // parsing main loop
3056 for (LyXParagraph::size_type i = 0;
3057 i < par->size(); ++i) {
3058 LyXFont font2 = par->getFont(params, i);
3060 // handle <emphasis> tag
3061 if (font1.emph() != font2.emph() && i) {
3062 if (font2.emph() == LyXFont::ON) {
3066 os << "</emphasis>";
3071 char c = par->GetChar(i);
3073 if (c == LyXParagraph::META_INSET) {
3074 Inset * inset = par->GetInset(i);
3075 std::ostringstream ost;
3076 inset->DocBook(this, ost);
3077 string tmp_out = ost.str().c_str();
3080 // This code needs some explanation:
3081 // Two insets are treated specially
3082 // label if it is the first element in a command paragraph
3084 // graphics inside tables or figure floats can't go on
3085 // title (the equivalente in latex for this case is caption
3086 // and title should come first
3089 if(desc_on!= 3 || i!= 0) {
3090 if(!tmp_out.empty() && tmp_out[0] == '@') {
3092 extra += frontStrip(tmp_out, '@');
3094 os << frontStrip(tmp_out, '@');
3099 } else if (font2.latex() == LyXFont::ON) {
3100 // "TeX"-Mode on ==> SGML-Mode on.
3106 if (par->linuxDocConvertChar(c, sgml_string)
3107 && !style.free_spacing) { // in freespacing
3109 // non-breaking characters
3113 os << "\n</term><listitem><para>";
3125 // needed if there is an optional argument but no contents
3126 if (main_body > 0 && main_body == par->size()) {
3130 os << "</emphasis>";
3133 // resets description flag correctly
3136 // <term> not closed...
3144 int Buffer::runLaTeX()
3148 if (!users->text) return 0;
3150 ProhibitInput(users);
3152 // get LaTeX-Filename
3153 string name = getLatexName();
3155 string path = OnlyPath(filename);
3157 string org_path = path;
3158 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3162 Path p(path); // path to LaTeX file
3163 users->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
3165 // Remove all error insets
3166 bool a = users->removeAutoInsets();
3168 // Always generate the LaTeX file
3169 makeLaTeXFile(name, org_path, false);
3171 // do the LaTex run(s)
3173 string latex_command = lyxrc.pdf_mode ?
3174 lyxrc.pdflatex_command : lyxrc.latex_command;
3175 LaTeX latex(latex_command, name, filepath);
3176 int res = latex.run(terr,
3177 users->owner()->getMiniBuffer()); // running latex
3179 // check return value from latex.run().
3180 if ((res & LaTeX::NO_LOGFILE)) {
3181 WriteAlert(_("LaTeX did not work!"),
3182 _("Missing log file:"), name);
3183 } else if ((res & LaTeX::ERRORS)) {
3184 users->owner()->getMiniBuffer()->Set(_("Done"));
3185 // Insert all errors as errors boxes
3186 users->insertErrors(terr);
3188 // Dvi should also be kept dirty if the latex run
3189 // ends up with errors. However it should be possible
3190 // to view a dirty dvi too.
3192 //no errors or any other things to think about so:
3193 users->owner()->getMiniBuffer()->Set(_("Done"));
3196 // if we removed error insets before we ran LaTeX or if we inserted
3197 // error insets after we ran LaTeX this must be run:
3198 if (a || (res & LaTeX::ERRORS)){
3201 //users->updateScrollbar();
3205 return latex.getNumErrors();
3212 int Buffer::runLiterate()
3214 if (!users->text) return 0;
3216 ProhibitInput(users);
3218 // get LaTeX-Filename
3219 string name = getLatexName();
3220 // get Literate-Filename
3221 string lit_name = OnlyFilename(ChangeExtension (getLatexName(),
3222 lyxrc.literate_extension));
3224 string path = OnlyPath(filename);
3226 string org_path = path;
3227 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3231 Path p(path); // path to Literate file
3232 users->owner()->getMiniBuffer()->Set(_("Running Literate..."));
3234 // Remove all error insets
3235 bool removedErrorInsets = users->removeAutoInsets();
3237 // generate the Literate file if necessary
3238 makeLaTeXFile(lit_name, org_path, false);
3240 string latex_command = lyxrc.pdf_mode ?
3241 lyxrc.pdflatex_command : lyxrc.latex_command;
3242 Literate literate(latex_command, name, filepath,
3244 lyxrc.literate_command, lyxrc.literate_error_filter,
3245 lyxrc.build_command, lyxrc.build_error_filter);
3247 int res = literate.weave(terr, users->owner()->getMiniBuffer());
3249 // check return value from literate.weave().
3250 if ((res & Literate::NO_LOGFILE)) {
3251 WriteAlert(_("Literate command did not work!"),
3252 _("Missing log file:"), name);
3253 } else if ((res & Literate::ERRORS)) {
3254 users->owner()->getMiniBuffer()->Set(_("Done"));
3255 // Insert all errors as errors boxes
3256 users->insertErrors(terr);
3258 // Dvi should also be kept dirty if the latex run
3259 // ends up with errors. However it should be possible
3260 // to view a dirty dvi too.
3262 //no errors or any other things to think about so:
3263 users->owner()->getMiniBuffer()->Set(_("Done"));
3266 // if we removed error insets before we ran LaTeX or if we inserted
3267 // error insets after we ran LaTeX this must be run:
3268 if (removedErrorInsets || (res & Literate::ERRORS)){
3271 //users->updateScrollbar();
3275 return literate.getNumErrors();
3279 int Buffer::buildProgram()
3281 if (!users->text) return 0;
3283 ProhibitInput(users);
3285 // get LaTeX-Filename
3286 string name = getLatexName();
3287 // get Literate-Filename
3288 string lit_name = OnlyFilename(ChangeExtension(getLatexName(),
3289 lyxrc.literate_extension));
3291 string path = OnlyPath(filename);
3293 string org_path = path;
3294 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3298 Path p(path); // path to Literate file
3299 users->owner()->getMiniBuffer()->Set(_("Building Program..."));
3301 // Remove all error insets
3302 bool removedErrorInsets = users->removeAutoInsets();
3304 // generate the LaTeX file if necessary
3305 if (!isNwClean() || removedErrorInsets) {
3306 makeLaTeXFile(lit_name, org_path, false);
3310 string latex_command = lyxrc.pdf_mode ?
3311 lyxrc.pdflatex_command : lyxrc.latex_command;
3312 Literate literate(latex_command, name, filepath,
3314 lyxrc.literate_command, lyxrc.literate_error_filter,
3315 lyxrc.build_command, lyxrc.build_error_filter);
3317 int res = literate.build(terr, users->owner()->getMiniBuffer());
3319 // check return value from literate.build().
3320 if ((res & Literate::NO_LOGFILE)) {
3321 WriteAlert(_("Build did not work!"),
3322 _("Missing log file:"), name);
3323 } else if ((res & Literate::ERRORS)) {
3324 users->owner()->getMiniBuffer()->Set(_("Done"));
3325 // Insert all errors as errors boxes
3326 users->insertErrors(terr);
3328 // Literate files should also be kept dirty if the literate
3329 // command run ends up with errors.
3331 //no errors or any other things to think about so:
3332 users->owner()->getMiniBuffer()->Set(_("Done"));
3336 // if we removed error insets before we ran Literate/Build or
3337 // if we inserted error insets after we ran Literate/Build this
3339 if (removedErrorInsets || (res & Literate::ERRORS)){
3342 //users->updateScrollbar();
3346 return literate.getNumErrors();
3350 // This should be enabled when the Chktex class is implemented. (Asger)
3351 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3352 // Other flags: -wall -v0 -x
3353 int Buffer::runChktex()
3355 if (!users->text) return 0;
3357 ProhibitInput(users);
3359 // get LaTeX-Filename
3360 string name = getLatexName();
3361 string path = OnlyPath(filename);
3363 string org_path = path;
3364 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3368 Path p(path); // path to LaTeX file
3369 users->owner()->getMiniBuffer()->Set(_("Running chktex..."));
3371 // Remove all error insets
3372 bool removedErrorInsets = users->removeAutoInsets();
3374 // Generate the LaTeX file if neccessary
3375 makeLaTeXFile(name, org_path, false);
3378 Chktex chktex(lyxrc.chktex_command, name, filepath);
3379 int res = chktex.run(terr); // run chktex
3382 WriteAlert(_("chktex did not work!"),
3383 _("Could not run with file:"), name);
3384 } else if (res > 0) {
3385 // Insert all errors as errors boxes
3386 users->insertErrors(terr);
3389 // if we removed error insets before we ran chktex or if we inserted
3390 // error insets after we ran chktex, this must be run:
3391 if (removedErrorInsets || res){
3394 //users->updateScrollbar();
3402 void Buffer::validate(LaTeXFeatures & features) const
3404 LyXParagraph * par = paragraph;
3405 LyXTextClass const & tclass =
3406 textclasslist.TextClass(params.textclass);
3408 // AMS Style is at document level
3410 features.amsstyle = (params.use_amsmath ||
3411 tclass.provides(LyXTextClass::amsmath));
3414 // We don't use "lyxerr.debug" because of speed. (Asger)
3415 if (lyxerr.debugging(Debug::LATEX))
3416 lyxerr << "Paragraph: " << par << endl;
3418 // Now just follow the list of paragraphs and run
3419 // validate on each of them.
3420 par->validate(features);
3422 // and then the next paragraph
3426 // the bullet shapes are buffer level not paragraph level
3427 // so they are tested here
3428 for (int i = 0; i < 4; ++i) {
3429 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3430 int font = params.user_defined_bullets[i].getFont();
3433 .user_defined_bullets[i]
3440 features.latexsym = true;
3444 features.amssymb = true;
3446 else if ((font >= 2 && font <= 5)) {
3447 features.pifont = true;
3452 if (lyxerr.debugging(Debug::LATEX)) {
3453 features.showStruct();
3458 void Buffer::setPaperStuff()
3460 params.papersize = BufferParams::PAPER_DEFAULT;
3461 char c1 = params.paperpackage;
3462 if (c1 == BufferParams::PACKAGE_NONE) {
3463 char c2 = params.papersize2;
3464 if (c2 == BufferParams::VM_PAPER_USLETTER)
3465 params.papersize = BufferParams::PAPER_USLETTER;
3466 else if (c2 == BufferParams::VM_PAPER_USLEGAL)
3467 params.papersize = BufferParams::PAPER_LEGALPAPER;
3468 else if (c2 == BufferParams::VM_PAPER_USEXECUTIVE)
3469 params.papersize = BufferParams::PAPER_EXECUTIVEPAPER;
3470 else if (c2 == BufferParams::VM_PAPER_A3)
3471 params.papersize = BufferParams::PAPER_A3PAPER;
3472 else if (c2 == BufferParams::VM_PAPER_A4)
3473 params.papersize = BufferParams::PAPER_A4PAPER;
3474 else if (c2 == BufferParams::VM_PAPER_A5)
3475 params.papersize = BufferParams::PAPER_A5PAPER;
3476 else if ((c2 == BufferParams::VM_PAPER_B3) || (c2 == BufferParams::VM_PAPER_B4) ||
3477 (c2 == BufferParams::VM_PAPER_B5))
3478 params.papersize = BufferParams::PAPER_B5PAPER;
3479 } else if ((c1 == BufferParams::PACKAGE_A4) || (c1 == BufferParams::PACKAGE_A4WIDE) ||
3480 (c1 == BufferParams::PACKAGE_WIDEMARGINSA4))
3481 params.papersize = BufferParams::PAPER_A4PAPER;
3485 // This function should be in Buffer because it's a buffer's property (ale)
3486 string const Buffer::getIncludeonlyList(char delim)
3489 for (inset_iterator it = inset_iterator_begin();
3490 it != inset_iterator_end(); ++it) {
3491 if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3492 InsetInclude * insetinc =
3493 static_cast<InsetInclude *>(*it);
3494 if (insetinc->isInclude()
3495 && insetinc->isNoLoad()) {
3498 lst += OnlyFilename(ChangeExtension(insetinc->getContents(), string()));
3502 lyxerr.debug() << "Includeonly(" << lst << ')' << endl;
3507 vector<string> const Buffer::getLabelList()
3509 /// if this is a child document and the parent is already loaded
3510 /// Use the parent's list instead [ale990407]
3511 if (!params.parentname.empty()
3512 && bufferlist.exists(params.parentname)) {
3513 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3515 return tmp->getLabelList();
3518 vector<string> label_list;
3519 for (inset_iterator it = inset_iterator_begin();
3520 it != inset_iterator_end(); ++it) {
3521 vector<string> l = (*it)->getLabelList();
3522 label_list.insert(label_list.end(), l.begin(), l.end());
3528 vector<vector<Buffer::TocItem> > const Buffer::getTocList()
3530 vector<vector<TocItem> > l(4);
3531 LyXParagraph * par = paragraph;
3534 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3535 if (textclasslist.Style(params.textclass,
3536 par->GetLayout()).labeltype
3537 == LABEL_SENSITIVE) {
3541 tmp.str = par->String(this, false);
3542 switch (par->footnotekind) {
3543 case LyXParagraph::FIG:
3544 case LyXParagraph::WIDE_FIG:
3545 l[TOC_LOF].push_back(tmp);
3547 case LyXParagraph::TAB:
3548 case LyXParagraph::WIDE_TAB:
3549 l[TOC_LOT].push_back(tmp);
3551 case LyXParagraph::ALGORITHM:
3552 l[TOC_LOA].push_back(tmp);
3554 case LyXParagraph::FOOTNOTE:
3555 case LyXParagraph::MARGIN:
3559 } else if (!par->IsDummy()) {
3561 char labeltype = textclasslist.Style(params.textclass,
3562 par->GetLayout()).labeltype;
3564 if (labeltype >= LABEL_COUNTER_CHAPTER
3565 && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3566 // insert this into the table of contents
3571 textclasslist.TextClass(params.textclass).maxcounter());
3572 tmp.str = par->String(this, true);
3573 l[TOC_TOC].push_back(tmp);
3584 // This is also a buffer property (ale)
3585 vector<pair<string,string> > const Buffer::getBibkeyList()
3587 /// if this is a child document and the parent is already loaded
3588 /// Use the parent's list instead [ale990412]
3589 if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3590 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3592 return tmp->getBibkeyList();
3595 vector<pair<string, string> > keys;
3596 LyXParagraph * par = paragraph;
3599 keys.push_back(pair<string, string>(par->bibkey->getContents(),
3600 par->String(this, false)));
3604 // Might be either using bibtex or a child has bibliography
3606 for (inset_iterator it = inset_iterator_begin();
3607 it != inset_iterator_end(); ++it) {
3608 // Search for Bibtex or Include inset
3609 if ((*it)->LyxCode() == Inset::BIBTEX_CODE) {
3610 vector<pair<string,string> > tmp =
3611 static_cast<InsetBibtex*>(*it)->getKeys();
3612 keys.insert(keys.end(), tmp.begin(), tmp.end());
3613 } else if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3614 vector<pair<string,string> > tmp =
3615 static_cast<InsetInclude*>(*it)->getKeys();
3616 keys.insert(keys.end(), tmp.begin(), tmp.end());
3625 bool Buffer::isDepClean(string const & name) const
3627 DEPCLEAN * item = dep_clean;
3628 while (item && item->master != name)
3630 if (!item) return true;
3635 void Buffer::markDepClean(string const & name)
3638 dep_clean = new DEPCLEAN;
3639 dep_clean->clean = true;
3640 dep_clean->master = name;
3641 dep_clean->next = 0;
3643 DEPCLEAN* item = dep_clean;
3644 while (item && item->master != name)
3649 item = new DEPCLEAN;
3651 item->master = name;
3658 bool Buffer::Dispatch(string const & command)
3660 // Split command string into command and argument
3661 string cmd, line = frontStrip(command);
3662 string arg = strip(frontStrip(split(line, cmd, ' ')));
3664 return Dispatch(lyxaction.LookupFunc(cmd.c_str()), arg);
3668 bool Buffer::Dispatch(int action, string const & argument)
3670 bool dispatched = true;
3674 Exporter::Export(this, argument, false);
3676 MenuExport(this, argument);
3687 void Buffer::resize()
3689 /// resize the BufferViews!
3695 void Buffer::resizeInsets(BufferView * bv)
3697 /// then remove all LyXText in text-insets
3698 LyXParagraph * par = paragraph;
3699 for(;par;par = par->next) {
3700 par->resizeInsetsLyXText(bv);
3704 void Buffer::ChangeLanguage(Language const * from, Language const * to)
3707 LyXParagraph * par = paragraph;
3709 par->ChangeLanguage(params, from, to);
3715 bool Buffer::isMultiLingual()
3718 LyXParagraph * par = paragraph;
3720 if (par->isMultiLingual(params))
3728 Buffer::inset_iterator::inset_iterator(LyXParagraph * paragraph,
3729 LyXParagraph::size_type pos)
3731 it = par->InsetIterator(pos);
3732 if (it == par->inset_iterator_end()) {
3739 void Buffer::inset_iterator::SetParagraph() {
3741 it = par->inset_iterator_begin();
3742 if (it != par->inset_iterator_end())
3747 // We maintain an invariant that whenever par = 0 then it = 0