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"
83 #include "LaTeXFeatures.h"
84 #include "support/syscall.h"
85 #include "support/lyxlib.h"
86 #include "support/FileInfo.h"
90 #include "lyx_gui_misc.h" // WarnReadonly()
91 #include "frontends/Dialogs.h"
107 using std::istringstream;
109 // all these externs should eventually be removed.
110 extern BufferList bufferlist;
112 extern LyXAction lyxaction;
115 static const float LYX_FORMAT = 2.17;
117 extern int tex_code_break_column;
120 Buffer::Buffer(string const & file, bool ronly)
122 lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
124 filepath = OnlyPath(file);
133 if (read_only || (lyxrc.use_tempdir)) {
134 tmppath = CreateBufferTmpDir();
135 } else tmppath.erase();
141 lyxerr[Debug::INFO] << "Buffer::~Buffer()" << endl;
142 // here the buffer should take care that it is
143 // saved properly, before it goes into the void.
145 // make sure that views using this buffer
150 if (!tmppath.empty()) {
151 DestroyBufferTmpDir(tmppath);
154 LyXParagraph * par = paragraph;
155 LyXParagraph * tmppar;
165 string const Buffer::getLatexName(bool no_path) const
168 return OnlyFilename(ChangeExtension(MakeLatexName(filename),
171 return ChangeExtension(MakeLatexName(filename),
176 void Buffer::setReadonly(bool flag)
178 if (read_only != flag) {
181 users->owner()->getDialogs()->updateBufferDependent();
184 WarnReadonly(filename);
189 bool Buffer::saveParamsAsDefaults() // const
191 string const fname = AddName(AddPath(user_lyxdir, "templates/"),
193 Buffer defaults = Buffer(fname);
195 // Use the current buffer's parameters as default
196 defaults.params = params;
198 // add an empty paragraph. Is this enough?
199 defaults.paragraph = new LyXParagraph;
201 return defaults.writeFile(defaults.filename, false);
205 /// Update window titles of all users
206 // Should work on a list
207 void Buffer::updateTitles() const
209 if (users) users->owner()->updateWindowTitle();
213 /// Reset autosave timer of all users
214 // Should work on a list
215 void Buffer::resetAutosaveTimers() const
217 if (users) users->owner()->resetAutosaveTimer();
221 void Buffer::fileName(string const & newfile)
223 filename = MakeAbsPath(newfile);
224 filepath = OnlyPath(filename);
225 setReadonly(IsFileWriteable(filename) == 0);
230 // candidate for move to BufferView
231 // (at least some parts in the beginning of the func)
234 // changed to be public and have one parameter
235 // if par = 0 normal behavior
236 // else insert behavior
237 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
238 bool Buffer::readLyXformat2(LyXLex & lex, LyXParagraph * par)
241 char depth = 0; // signed or unsigned?
243 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
244 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
246 bool the_end_read = false;
248 LyXParagraph * return_par = 0;
249 LyXFont font(LyXFont::ALL_INHERIT, params.language_info);
250 if (format < 2.16 && params.language == "hebrew")
251 font.setLanguage(default_language);
253 // If we are inserting, we cheat and get a token in advance
254 bool has_token = false;
258 par = new LyXParagraph;
260 users->text->BreakParagraph(users);
261 return_par = users->text->FirstParagraph();
264 // We don't want to adopt the parameters from the
265 // document we insert, so we skip until the text begins:
268 pretoken = lex.GetString();
269 if (pretoken == "\\layout") {
281 pretoken = lex.GetString();
284 if (pretoken.empty()) continue;
287 parseSingleLyXformat2Token(lex, par, return_par,
288 pretoken, pos, depth,
300 paragraph = return_par;
306 // We'll remove this later. (Lgb)
307 static string last_inset_read;
311 Buffer::parseSingleLyXformat2Token(LyXLex & lex, LyXParagraph *& par,
312 LyXParagraph *& return_par,
313 string const & token, int & pos,
314 char & depth, LyXFont & font
316 , LyXParagraph::footnote_flag & footnoteflag,
317 LyXParagraph::footnote_kind & footnotekind
321 bool the_end_read = false;
323 if (token[0] != '\\') {
324 for (string::const_iterator cit = token.begin();
325 cit != token.end(); ++cit) {
326 par->InsertChar(pos, (*cit), font);
329 } else if (token == "\\i") {
330 Inset * inset = new InsetLatexAccent;
331 inset->Read(this, lex);
332 par->InsertInset(pos, inset, font);
334 } else if (token == "\\layout") {
339 par = new LyXParagraph(par);
343 string const layoutname = lex.GetString();
344 pair<bool, LyXTextClass::LayoutList::size_type> pp
345 = textclasslist.NumberOfLayout(params.textclass,
348 par->layout = pp.second;
349 } else { // layout not found
350 // use default layout "Standard" (0)
353 // Test whether the layout is obsolete.
354 LyXLayout const & layout =
355 textclasslist.Style(params.textclass,
357 if (!layout.obsoleted_by().empty())
359 textclasslist.NumberOfLayout(params.textclass,
360 layout.obsoleted_by()).second;
362 par->footnoteflag = footnoteflag;
363 par->footnotekind = footnotekind;
366 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
367 if (format < 2.16 && params.language == "hebrew")
368 font.setLanguage(default_language);
370 } else if (token == "\\end_float") {
375 par = new LyXParagraph(par);
377 footnotekind = LyXParagraph::FOOTNOTE;
378 footnoteflag = LyXParagraph::NO_FOOTNOTE;
381 par->layout = LYX_DUMMY_LAYOUT;
382 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
383 if (format < 2.16 && params.language == "hebrew")
384 font.setLanguage(default_language);
385 } else if (token == "\\begin_float") {
386 int tmpret = lex.FindToken(string_footnotekinds);
387 if (tmpret == -1) ++tmpret;
388 if (tmpret != LYX_LAYOUT_DEFAULT)
389 footnotekind = static_cast<LyXParagraph::footnote_kind>(tmpret); // bad
390 if (footnotekind == LyXParagraph::FOOTNOTE
391 || footnotekind == LyXParagraph::MARGIN)
392 footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
394 footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
396 } else if (token == "\\begin_float") {
397 // This is the compability reader, unfinished but tested.
400 string const tmptok = lex.GetString();
401 //lyxerr << "old float: " << tmptok << endl;
406 if (tmptok == "footnote") {
407 inset = new InsetFoot;
408 } else if (tmptok == "margin") {
409 inset = new InsetMarginal;
410 } else if (tmptok == "fig") {
411 inset = new InsetFloat("figure");
412 old_float += "placement htbp\n";
413 } else if (tmptok == "tab") {
414 inset = new InsetFloat("table");
415 old_float += "placement htbp\n";
416 } else if (tmptok == "alg") {
417 inset = new InsetFloat("algorithm");
418 old_float += "placement htbp\n";
419 } else if (tmptok == "wide-fig") {
420 InsetFloat * tmp = new InsetFloat("figure");
423 old_float += "placement htbp\n";
424 } else if (tmptok == "wide-tab") {
425 InsetFloat * tmp = new InsetFloat("table");
428 old_float += "placement htbp\n";
431 if (!inset) return false; // no end read yet
433 old_float += "collapsed true\n";
435 // Here we need to check for \end_deeper and handle that
436 // before we do the footnote parsing.
437 // This _is_ a hack! (Lgb)
440 string const tmp = lex.GetString();
441 if (tmp == "\\end_deeper") {
442 lyxerr << "\\end_deeper caught!" << endl;
444 lex.printError("\\end_deeper: "
445 "depth is already null");
456 old_float += lex.getLongString("\\end_float");
457 old_float += "\n\\end_inset\n";
458 //lyxerr << "float body: " << old_float << endl;
460 istringstream istr(old_float);
463 nylex.setStream(istr);
465 inset->Read(this, nylex);
466 par->InsertInset(pos, inset, font);
469 } else if (token == "\\begin_deeper") {
471 } else if (token == "\\end_deeper") {
473 lex.printError("\\end_deeper: "
474 "depth is already null");
478 } else if (token == "\\begin_preamble") {
479 params.readPreamble(lex);
480 } else if (token == "\\textclass") {
482 pair<bool, LyXTextClassList::size_type> pp =
483 textclasslist.NumberOfClass(lex.GetString());
485 params.textclass = pp.second;
487 lex.printError("Unknown textclass `$$Token'");
488 params.textclass = 0;
490 if (!textclasslist.Load(params.textclass)) {
491 // if the textclass wasn't loaded properly
492 // we need to either substitute another
493 // or stop loading the file.
494 // I can substitute but I don't see how I can
495 // stop loading... ideas?? ARRae980418
496 WriteAlert(_("Textclass Loading Error!"),
497 string(_("Can't load textclass ")) +
498 textclasslist.NameOfClass(params.textclass),
499 _("-- substituting default"));
500 params.textclass = 0;
502 } else if (token == "\\options") {
504 params.options = lex.GetString();
505 } else if (token == "\\language") {
506 params.readLanguage(lex);
507 } else if (token == "\\fontencoding") {
509 } else if (token == "\\inputencoding") {
511 params.inputenc = lex.GetString();
512 } else if (token == "\\graphics") {
513 params.readGraphicsDriver(lex);
514 } else if (token == "\\fontscheme") {
516 params.fonts = lex.GetString();
517 } else if (token == "\\noindent") {
518 par->noindent = true;
519 } else if (token == "\\fill_top") {
520 par->added_space_top = VSpace(VSpace::VFILL);
521 } else if (token == "\\fill_bottom") {
522 par->added_space_bottom = VSpace(VSpace::VFILL);
523 } else if (token == "\\line_top") {
524 par->line_top = true;
525 } else if (token == "\\line_bottom") {
526 par->line_bottom = true;
527 } else if (token == "\\pagebreak_top") {
528 par->pagebreak_top = true;
529 } else if (token == "\\pagebreak_bottom") {
530 par->pagebreak_bottom = true;
531 } else if (token == "\\start_of_appendix") {
532 par->start_of_appendix = true;
533 } else if (token == "\\paragraph_separation") {
534 int tmpret = lex.FindToken(string_paragraph_separation);
535 if (tmpret == -1) ++tmpret;
536 if (tmpret != LYX_LAYOUT_DEFAULT)
537 params.paragraph_separation =
538 static_cast<BufferParams::PARSEP>(tmpret);
539 } else if (token == "\\defskip") {
541 params.defskip = VSpace(lex.GetString());
542 } else if (token == "\\epsfig") { // obsolete
543 // Indeed it is obsolete, but we HAVE to be backwards
544 // compatible until 0.14, because otherwise all figures
545 // in existing documents are irretrivably lost. (Asger)
546 params.readGraphicsDriver(lex);
547 } else if (token == "\\quotes_language") {
548 int tmpret = lex.FindToken(string_quotes_language);
549 if (tmpret == -1) ++tmpret;
550 if (tmpret != LYX_LAYOUT_DEFAULT) {
551 InsetQuotes::quote_language tmpl =
552 InsetQuotes::EnglishQ;
555 tmpl = InsetQuotes::EnglishQ;
558 tmpl = InsetQuotes::SwedishQ;
561 tmpl = InsetQuotes::GermanQ;
564 tmpl = InsetQuotes::PolishQ;
567 tmpl = InsetQuotes::FrenchQ;
570 tmpl = InsetQuotes::DanishQ;
573 params.quotes_language = tmpl;
575 } else if (token == "\\quotes_times") {
577 switch(lex.GetInteger()) {
579 params.quotes_times = InsetQuotes::SingleQ;
582 params.quotes_times = InsetQuotes::DoubleQ;
585 } else if (token == "\\papersize") {
586 int tmpret = lex.FindToken(string_papersize);
590 params.papersize2 = tmpret;
591 } else if (token == "\\paperpackage") {
592 int tmpret = lex.FindToken(string_paperpackages);
595 params.paperpackage = BufferParams::PACKAGE_NONE;
597 params.paperpackage = tmpret;
598 } else if (token == "\\use_geometry") {
600 params.use_geometry = lex.GetInteger();
601 } else if (token == "\\use_amsmath") {
603 params.use_amsmath = lex.GetInteger();
604 } else if (token == "\\paperorientation") {
605 int tmpret = lex.FindToken(string_orientation);
606 if (tmpret == -1) ++tmpret;
607 if (tmpret != LYX_LAYOUT_DEFAULT)
608 params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
609 } else if (token == "\\paperwidth") {
611 params.paperwidth = lex.GetString();
612 } else if (token == "\\paperheight") {
614 params.paperheight = lex.GetString();
615 } else if (token == "\\leftmargin") {
617 params.leftmargin = lex.GetString();
618 } else if (token == "\\topmargin") {
620 params.topmargin = lex.GetString();
621 } else if (token == "\\rightmargin") {
623 params.rightmargin = lex.GetString();
624 } else if (token == "\\bottommargin") {
626 params.bottommargin = lex.GetString();
627 } else if (token == "\\headheight") {
629 params.headheight = lex.GetString();
630 } else if (token == "\\headsep") {
632 params.headsep = lex.GetString();
633 } else if (token == "\\footskip") {
635 params.footskip = lex.GetString();
636 } else if (token == "\\paperfontsize") {
638 params.fontsize = strip(lex.GetString());
639 } else if (token == "\\papercolumns") {
641 params.columns = lex.GetInteger();
642 } else if (token == "\\papersides") {
644 switch(lex.GetInteger()) {
646 case 1: params.sides = LyXTextClass::OneSide; break;
647 case 2: params.sides = LyXTextClass::TwoSides; break;
649 } else if (token == "\\paperpagestyle") {
651 params.pagestyle = strip(lex.GetString());
652 } else if (token == "\\bullet") {
654 int const index = lex.GetInteger();
656 int temp_int = lex.GetInteger();
657 params.user_defined_bullets[index].setFont(temp_int);
658 params.temp_bullets[index].setFont(temp_int);
660 temp_int = lex.GetInteger();
661 params.user_defined_bullets[index].setCharacter(temp_int);
662 params.temp_bullets[index].setCharacter(temp_int);
664 temp_int = lex.GetInteger();
665 params.user_defined_bullets[index].setSize(temp_int);
666 params.temp_bullets[index].setSize(temp_int);
668 string const temp_str = lex.GetString();
669 if (temp_str != "\\end_bullet") {
670 // this element isn't really necessary for
671 // parsing but is easier for humans
672 // to understand bullets. Put it back and
673 // set a debug message?
674 lex.printError("\\end_bullet expected, got" + temp_str);
675 //how can I put it back?
677 } else if (token == "\\bulletLaTeX") {
679 int const index = lex.GetInteger();
681 string temp_str = lex.GetString();
683 while (temp_str != "\\end_bullet") {
684 // this loop structure is needed when user
685 // enters an empty string since the first
686 // thing returned will be the \\end_bullet
688 // if the LaTeX entry has spaces. Each element
689 // therefore needs to be read in turn
692 temp_str = lex.GetString();
694 params.user_defined_bullets[index].setText(sum_str);
695 params.temp_bullets[index].setText(sum_str);
696 } else if (token == "\\secnumdepth") {
698 params.secnumdepth = lex.GetInteger();
699 } else if (token == "\\tocdepth") {
701 params.tocdepth = lex.GetInteger();
702 } else if (token == "\\spacing") {
704 string const tmp = strip(lex.GetString());
705 Spacing::Space tmp_space = Spacing::Default;
707 if (tmp == "single") {
708 tmp_space = Spacing::Single;
709 } else if (tmp == "onehalf") {
710 tmp_space = Spacing::Onehalf;
711 } else if (tmp == "double") {
712 tmp_space = Spacing::Double;
713 } else if (tmp == "other") {
715 tmp_space = Spacing::Other;
716 tmp_val = lex.GetFloat();
718 lex.printError("Unknown spacing token: '$$Token'");
720 // Small hack so that files written with klyx will be
723 par->spacing.set(tmp_space, tmp_val);
725 params.spacing.set(tmp_space, tmp_val);
727 } else if (token == "\\paragraph_spacing") {
729 string const tmp = strip(lex.GetString());
730 if (tmp == "single") {
731 par->spacing.set(Spacing::Single);
732 } else if (tmp == "onehalf") {
733 par->spacing.set(Spacing::Onehalf);
734 } else if (tmp == "double") {
735 par->spacing.set(Spacing::Double);
736 } else if (tmp == "other") {
738 par->spacing.set(Spacing::Other,
741 lex.printError("Unknown spacing token: '$$Token'");
743 } else if (token == "\\float_placement") {
745 params.float_placement = lex.GetString();
746 } else if (token == "\\family") {
748 font.setLyXFamily(lex.GetString());
749 } else if (token == "\\series") {
751 font.setLyXSeries(lex.GetString());
752 } else if (token == "\\shape") {
754 font.setLyXShape(lex.GetString());
755 } else if (token == "\\size") {
757 font.setLyXSize(lex.GetString());
758 } else if (token == "\\latex") {
760 string const tok = lex.GetString();
761 // This is dirty, but gone with LyX3. (Asger)
762 if (tok == "no_latex")
763 font.setLatex(LyXFont::OFF);
764 else if (tok == "latex")
765 font.setLatex(LyXFont::ON);
766 else if (tok == "default")
767 font.setLatex(LyXFont::INHERIT);
769 lex.printError("Unknown LaTeX font flag "
771 } else if (token == "\\lang") {
773 string const tok = lex.GetString();
774 Languages::iterator lit = languages.find(tok);
775 if (lit != languages.end()) {
776 font.setLanguage(&(*lit).second);
778 font.setLanguage(params.language_info);
779 lex.printError("Unknown language `$$Token'");
781 } else if (token == "\\emph") {
783 font.setEmph(font.setLyXMisc(lex.GetString()));
784 } else if (token == "\\bar") {
786 string const tok = lex.GetString();
787 // This is dirty, but gone with LyX3. (Asger)
789 font.setUnderbar(LyXFont::ON);
790 else if (tok == "no")
791 font.setUnderbar(LyXFont::OFF);
792 else if (tok == "default")
793 font.setUnderbar(LyXFont::INHERIT);
795 lex.printError("Unknown bar font flag "
797 } else if (token == "\\noun") {
799 font.setNoun(font.setLyXMisc(lex.GetString()));
800 } else if (token == "\\color") {
802 font.setLyXColor(lex.GetString());
803 } else if (token == "\\align") {
804 int tmpret = lex.FindToken(string_align);
805 if (tmpret == -1) ++tmpret;
806 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
808 for (; tmpret > 0; --tmpret)
809 tmpret2 = tmpret2 * 2;
810 par->align = LyXAlignment(tmpret2);
812 } else if (token == "\\added_space_top") {
814 par->added_space_top = VSpace(lex.GetString());
815 } else if (token == "\\added_space_bottom") {
817 par->added_space_bottom = VSpace(lex.GetString());
818 } else if (token == "\\pextra_type") {
820 par->pextra_type = lex.GetInteger();
821 } else if (token == "\\pextra_width") {
823 par->pextra_width = lex.GetString();
824 } else if (token == "\\pextra_widthp") {
826 par->pextra_widthp = lex.GetString();
827 } else if (token == "\\pextra_alignment") {
829 par->pextra_alignment = lex.GetInteger();
830 } else if (token == "\\pextra_hfill") {
832 par->pextra_hfill = lex.GetInteger();
833 } else if (token == "\\pextra_start_minipage") {
835 par->pextra_start_minipage = lex.GetInteger();
836 } else if (token == "\\labelwidthstring") {
838 par->labelwidthstring = lex.GetString();
839 // do not delete this token, it is still needed!
840 } else if (token == "\\end_inset") {
841 lyxerr << "Solitary \\end_inset. Missing \\begin_inset?.\n"
842 << "Last inset read was: " << last_inset_read
844 // Simply ignore this. The insets do not have
846 // But insets should read it, it is a part of
847 // the inset isn't it? Lgb.
848 } else if (token == "\\begin_inset") {
849 readInset(lex, par, pos, font);
850 } else if (token == "\\SpecialChar") {
851 LyXLayout const & layout =
852 textclasslist.Style(params.textclass,
855 // Insets don't make sense in a free-spacing context! ---Kayvan
856 if (layout.free_spacing) {
859 string next_token = lex.GetString();
860 if (next_token == "\\-") {
861 par->InsertChar(pos, '-', font);
862 } else if (next_token == "\\protected_separator"
863 || next_token == "~") {
864 par->InsertChar(pos, ' ', font);
866 lex.printError("Token `$$Token' "
868 "paragraph layout!");
873 Inset * inset = new InsetSpecialChar;
874 inset->Read(this, lex);
875 par->InsertInset(pos, inset, font);
878 } else if (token == "\\newline") {
879 par->InsertChar(pos, LyXParagraph::META_NEWLINE, font);
881 } else if (token == "\\LyXTable") {
882 Inset * inset = new InsetTabular(this);
883 inset->Read(this, lex);
884 par->InsertInset(pos, inset, font);
886 } else if (token == "\\hfill") {
887 par->InsertChar(pos, LyXParagraph::META_HFILL, font);
889 } else if (token == "\\protected_separator") { // obsolete
890 // This is a backward compability thingie. (Lgb)
891 // Remove it later some time...introduced with fileformat
893 LyXLayout const & layout =
894 textclasslist.Style(params.textclass,
897 if (layout.free_spacing) {
898 par->InsertChar(pos, ' ', font);
900 Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
901 par->InsertInset(pos, inset, font);
904 } else if (token == "\\bibitem") { // ale970302
906 InsetCommandParams p( "bibitem" );
907 par->bibkey = new InsetBibKey(p);
909 par->bibkey->Read(this, lex);
910 } else if (token == "\\backslash") {
911 par->InsertChar(pos, '\\', font);
913 } else if (token == "\\the_end") {
916 // This should be insurance for the future: (Asger)
917 lex.printError("Unknown token `$$Token'. "
918 "Inserting as text.");
919 string::const_iterator cit = token.begin();
920 string::const_iterator end = token.end();
921 for(; cit != end; ++cit) {
922 par->InsertChar(pos, (*cit), font);
930 void Buffer::readInset(LyXLex & lex, LyXParagraph *& par,
931 int & pos, LyXFont & font)
934 if (lex.GetString() != "\\begin_inset") {
935 lyxerr << "Buffer::readInset: Consistency check failed."
942 string const tmptok = lex.GetString();
943 last_inset_read = tmptok;
945 // test the different insets
946 if (tmptok == "LatexCommand") {
947 InsetCommandParams inscmd;
950 if (inscmd.getCmdName() == "cite") {
951 inset = new InsetCitation(inscmd);
952 } else if (inscmd.getCmdName() == "bibitem") {
953 lex.printError("Wrong place for bibitem");
954 inset = new InsetBibKey(inscmd);
955 } else if (inscmd.getCmdName() == "BibTeX") {
956 inset = new InsetBibtex(inscmd);
957 } else if (inscmd.getCmdName() == "index") {
958 inset = new InsetIndex(inscmd);
959 } else if (inscmd.getCmdName() == "include") {
960 inset = new InsetInclude(inscmd, this);
961 } else if (inscmd.getCmdName() == "label") {
962 inset = new InsetLabel(inscmd);
963 } else if (inscmd.getCmdName() == "url"
964 || inscmd.getCmdName() == "htmlurl") {
965 inset = new InsetUrl(inscmd);
966 } else if (inscmd.getCmdName() == "ref"
967 || inscmd.getCmdName() == "pageref"
968 || inscmd.getCmdName() == "vref"
969 || inscmd.getCmdName() == "vpageref"
970 || inscmd.getCmdName() == "prettyref") {
971 if (!inscmd.getOptions().empty()
972 || !inscmd.getContents().empty()) {
973 inset = new InsetRef(inscmd);
975 } else if (inscmd.getCmdName() == "tableofcontents"
976 || inscmd.getCmdName() == "listofalgorithms"
977 || inscmd.getCmdName() == "listoffigures"
978 || inscmd.getCmdName() == "listoftables") {
979 inset = new InsetTOC(inscmd);
980 } else if (inscmd.getCmdName() == "printindex") {
981 inset = new InsetPrintIndex(inscmd);
982 } else if (inscmd.getCmdName() == "lyxparent") {
983 inset = new InsetParent(inscmd, this);
986 if (tmptok == "Quotes") {
987 inset = new InsetQuotes;
988 } else if (tmptok == "External") {
989 inset = new InsetExternal;
990 } else if (tmptok == "FormulaMacro") {
991 inset = new InsetFormulaMacro;
992 } else if (tmptok == "Formula") {
993 inset = new InsetFormula;
994 } else if (tmptok == "Figure") {
995 inset = new InsetFig(100, 100, this);
996 } else if (tmptok == "Info") {
997 inset = new InsetInfo;
998 } else if (tmptok == "Include") {
999 InsetCommandParams p( "Include" );
1000 inset = new InsetInclude(p, this);
1001 } else if (tmptok == "ERT") {
1002 inset = new InsetERT;
1003 } else if (tmptok == "Tabular") {
1004 inset = new InsetTabular(this);
1005 } else if (tmptok == "Text") {
1006 inset = new InsetText;
1007 } else if (tmptok == "Foot") {
1008 inset = new InsetFoot;
1009 } else if (tmptok == "Marginal") {
1010 inset = new InsetMarginal;
1011 } else if (tmptok == "Minipage") {
1012 inset = new InsetMinipage;
1013 } else if (tmptok == "Float") {
1015 string tmptok = lex.GetString();
1016 inset = new InsetFloat(tmptok);
1017 } else if (tmptok == "List") {
1018 inset = new InsetList;
1019 } else if (tmptok == "Theorem") {
1020 inset = new InsetList;
1021 } else if (tmptok == "Caption") {
1022 inset = new InsetCaption;
1023 } else if (tmptok == "GRAPHICS") {
1024 inset = new InsetGraphics;
1027 if (inset) inset->Read(this, lex);
1031 par->InsertInset(pos, inset, font);
1037 bool Buffer::readFile(LyXLex & lex, LyXParagraph * par)
1041 string const token(lex.GetString());
1042 if (token == "\\lyxformat") { // the first token _must_ be...
1044 format = lex.GetFloat();
1046 if (LYX_FORMAT - format > 0.05) {
1048 printf(_("Warning: need lyxformat %.2f but found %.2f\n"),
1049 LYX_FORMAT, format);
1051 if (format - LYX_FORMAT > 0.05) {
1052 printf(_("ERROR: need lyxformat %.2f but found %.2f\n"),
1053 LYX_FORMAT, format);
1055 bool the_end = readLyXformat2(lex, par);
1056 // Formats >= 2.13 support "\the_end" marker
1063 WriteAlert(_("Warning!"),
1064 _("Reading of document is not complete"),
1065 _("Maybe the document is truncated"));
1066 // We simulate a safe reading anyways to allow
1067 // users to take the chance... (Asger)
1071 WriteAlert(_("ERROR!"),
1072 _("Old LyX file format found. "
1073 "Use LyX 0.10.x to read this!"));
1077 } else { // "\\lyxformat" not found
1078 WriteAlert(_("ERROR!"), _("Not a LyX file!"));
1081 WriteAlert(_("ERROR!"), _("Unable to read file!"));
1087 // Should probably be moved to somewhere else: BufferView? LyXView?
1088 bool Buffer::save() const
1090 // We don't need autosaves in the immediate future. (Asger)
1091 resetAutosaveTimers();
1095 if (lyxrc.make_backup) {
1096 s = fileName() + '~';
1097 if (!lyxrc.backupdir_path.empty())
1098 s = AddName(lyxrc.backupdir_path,
1099 subst(CleanupPath(s),'/','!'));
1101 // Rename is the wrong way of making a backup,
1102 // this is the correct way.
1103 /* truss cp fil fil2:
1104 lstat("LyXVC3.lyx", 0xEFFFF898) Err#2 ENOENT
1105 stat("LyXVC.lyx", 0xEFFFF688) = 0
1106 open("LyXVC.lyx", O_RDONLY) = 3
1107 open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1108 fstat(4, 0xEFFFF508) = 0
1109 fstat(3, 0xEFFFF508) = 0
1110 read(3, " # T h i s f i l e w".., 8192) = 5579
1111 write(4, " # T h i s f i l e w".., 5579) = 5579
1112 read(3, 0xEFFFD4A0, 8192) = 0
1115 chmod("LyXVC3.lyx", 0100644) = 0
1116 lseek(0, 0, SEEK_CUR) = 46440
1120 // Should proabaly have some more error checking here.
1121 // Should be cleaned up in 0.13, at least a bit.
1122 // Doing it this way, also makes the inodes stay the same.
1123 // This is still not a very good solution, in particular we
1124 // might loose the owner of the backup.
1125 FileInfo finfo(fileName());
1126 if (finfo.exist()) {
1127 mode_t fmode = finfo.getMode();
1128 struct utimbuf times = {
1129 finfo.getAccessTime(),
1130 finfo.getModificationTime() };
1132 ifstream ifs(fileName().c_str());
1133 ofstream ofs(s.c_str(), ios::out|ios::trunc);
1138 ::chmod(s.c_str(), fmode);
1140 if (::utime(s.c_str(), ×)) {
1141 lyxerr << "utime error." << endl;
1144 lyxerr << "LyX was not able to make "
1145 "backupcopy. Beware." << endl;
1150 if (writeFile(fileName(), false)) {
1152 removeAutosaveFile(fileName());
1154 // Saving failed, so backup is not backup
1155 if (lyxrc.make_backup) {
1156 lyx::rename(s, fileName());
1164 // Returns false if unsuccesful
1165 bool Buffer::writeFile(string const & fname, bool flag) const
1167 // if flag is false writeFile will not create any GUI
1168 // warnings, only cerr.
1169 // Needed for autosave in background or panic save (Matthias 120496)
1171 if (read_only && (fname == filename)) {
1172 // Here we should come with a question if we should
1173 // perform the write anyway.
1175 lyxerr << _("Error! Document is read-only: ")
1178 WriteAlert(_("Error! Document is read-only: "),
1183 FileInfo finfo(fname);
1184 if (finfo.exist() && !finfo.writable()) {
1185 // Here we should come with a question if we should
1186 // try to do the save anyway. (i.e. do a chmod first)
1188 lyxerr << _("Error! Cannot write file: ")
1191 WriteFSAlert(_("Error! Cannot write file: "),
1196 ofstream ofs(fname.c_str());
1199 lyxerr << _("Error! Cannot open file: ")
1202 WriteFSAlert(_("Error! Cannot open file: "),
1208 // Use the standard "C" locale for file output.
1209 ofs.imbue(std::locale::classic());
1212 // The top of the file should not be written by params.
1214 // write out a comment in the top of the file
1215 ofs << '#' << LYX_DOCVERSION
1216 << " created this file. For more info see http://www.lyx.org/\n";
1217 ofs.setf(ios::showpoint|ios::fixed);
1220 char dummy_format[512];
1221 sprintf(dummy_format, "%.2f", LYX_FORMAT);
1222 ofs << "\\lyxformat " << dummy_format << "\n";
1224 ofs << "\\lyxformat " << setw(4) << LYX_FORMAT << "\n";
1226 // now write out the buffer paramters.
1227 params.writeFile(ofs);
1229 char footnoteflag = 0;
1232 // this will write out all the paragraphs
1233 // using recursive descent.
1234 paragraph->writeFile(this, ofs, params, footnoteflag, depth);
1236 // Write marker that shows file is complete
1237 ofs << "\n\\the_end" << endl;
1239 // how to check if close went ok?
1245 void Buffer::writeFileAscii(string const & fname, int linelen)
1249 char footnoteflag = 0;
1252 LyXParagraph::size_type i;
1255 int ltype_depth = 0;
1258 int currlinelen = 0;
1260 bool ref_printed = false;
1262 ofstream ofs(fname.c_str());
1264 WriteFSAlert(_("Error: Cannot write file:"), fname);
1268 string const fname1 = TmpFileName();
1269 LyXParagraph * par = paragraph;
1275 par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1279 || par->previous->footnoteflag == LyXParagraph::NO_FOOTNOTE
1284 /* begins a footnote environment ? */
1285 if (footnoteflag != par->footnoteflag) {
1286 footnoteflag = par->footnoteflag;
1288 j = strlen(string_footnotekinds[par->footnotekind])+4;
1289 if (currlinelen + j > linelen)
1292 << string_footnotekinds[par->footnotekind] << "] ";
1298 /* begins or ends a deeper area ?*/
1299 if (depth != par->depth) {
1300 if (par->depth > depth) {
1301 while (par->depth > depth) {
1306 while (par->depth < depth) {
1312 /* First write the layout */
1313 tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1314 if (tmp == "Itemize") {
1316 ltype_depth = depth+1;
1317 } else if (tmp == "Enumerate") {
1319 ltype_depth = depth+1;
1320 } else if (contains(tmp, "ection")) {
1322 ltype_depth = depth+1;
1323 } else if (contains(tmp, "aragraph")) {
1325 ltype_depth = depth+1;
1326 } else if (tmp == "Description") {
1328 ltype_depth = depth+1;
1329 } else if (tmp == "Abstract") {
1332 } else if (tmp == "Bibliography") {
1340 /* maybe some vertical spaces */
1342 /* the labelwidthstring used in lists */
1346 /* some pagebreaks? */
1350 /* what about the alignment */
1353 /* dummy layout, that means a footnote ended */
1354 footnoteflag = LyXParagraph::NO_FOOTNOTE;
1358 lyxerr << "Should this ever happen?" << endl;
1363 LyXFont(LyXFont::ALL_INHERIT, params.language_info);
1365 for (i = 0, actpos = 1; i < par->size(); ++i, ++actpos) {
1366 if (!i && !footnoteflag && !noparbreak){
1368 for(j = 0; j < depth; ++j)
1370 currlinelen = depth * 2;
1372 case 0: /* Standard */
1373 case 4: /* (Sub)Paragraph */
1374 case 5: /* Description */
1376 case 6: /* Abstract */
1377 ofs << "Abstract\n\n";
1379 case 7: /* Bibliography */
1381 ofs << "References\n\n";
1386 ofs << par->labelstring << " ";
1389 if (ltype_depth > depth) {
1390 for(j = ltype_depth - 1; j > depth; --j)
1392 currlinelen += (ltype_depth-depth)*2;
1395 LyXFont font2 = par->GetFontSettings(params, i);
1396 if (font1.latex() != font2.latex()) {
1397 if (font2.latex() == LyXFont::OFF)
1404 c = par->GetChar(i);
1408 case LyXParagraph::META_INSET:
1409 if ((inset = par->GetInset(i))) {
1411 inset->Ascii(this, ofs);
1412 currlinelen += (ofs.tellp() - fpos);
1413 actpos += (ofs.tellp() - fpos) - 1;
1416 case LyXParagraph::META_NEWLINE:
1418 for(j = 0; j < depth; ++j)
1420 currlinelen = depth * 2;
1421 if (ltype_depth > depth) {
1422 for(j = ltype_depth;
1425 currlinelen += (ltype_depth - depth) * 2;
1428 case LyXParagraph::META_HFILL:
1435 if (currlinelen > linelen - 10
1436 && c == ' ' && i + 2 < par->size()) {
1438 for(j = 0; j < depth; ++j)
1440 currlinelen = depth * 2;
1441 if (ltype_depth > depth) {
1442 for(j = ltype_depth;
1445 currlinelen += (ltype_depth-depth)*2;
1447 } else if (c != '\0')
1450 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1460 //----------------------------------------------------------------------------
1462 //----------------------------------------------------------------------------
1463 string const Buffer::asciiParagraph(LyXParagraph const * par,
1464 unsigned int linelen) const
1466 ostringstream buffer;
1469 Inset const * inset;
1471 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1474 int ltype_depth = 0;
1475 unsigned int currlinelen = 0;
1476 bool ref_printed = false;
1482 par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1486 || par->previous->footnoteflag == LyXParagraph::NO_FOOTNOTE
1490 /* begins a footnote environment ? */
1491 if (footnoteflag != par->footnoteflag) {
1492 footnoteflag = par->footnoteflag;
1494 size_t const j = strlen(string_footnotekinds[par->footnotekind]) + 4;
1495 if ((linelen > 0) &&
1496 ((currlinelen + j) > linelen)) {
1501 << string_footnotekinds[par->footnotekind]
1507 /* begins or ends a deeper area ?*/
1508 if (depth != par->depth) {
1509 if (par->depth > depth) {
1510 while (par->depth > depth) {
1515 while (par->depth < depth) {
1521 /* First write the layout */
1522 string const tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1523 if (tmp == "Itemize") {
1525 ltype_depth = depth+1;
1526 } else if (tmp == "Enumerate") {
1528 ltype_depth = depth+1;
1529 } else if (strstr(tmp.c_str(), "ection")) {
1531 ltype_depth = depth+1;
1532 } else if (strstr(tmp.c_str(), "aragraph")) {
1534 ltype_depth = depth+1;
1535 } else if (tmp == "Description") {
1537 ltype_depth = depth+1;
1538 } else if (tmp == "Abstract") {
1541 } else if (tmp == "Bibliography") {
1549 /* maybe some vertical spaces */
1551 /* the labelwidthstring used in lists */
1555 /* some pagebreaks? */
1559 /* what about the alignment */
1562 /* dummy layout, that means a footnote ended */
1563 footnoteflag = LyXParagraph::NO_FOOTNOTE;
1567 lyxerr << "Should this ever happen?" << endl;
1571 font1 = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
1572 for (LyXParagraph::size_type i = 0; i < par->size(); ++i) {
1573 if (!i && !footnoteflag && !noparbreak){
1575 for(char j = 0; j < depth; ++j)
1577 currlinelen = depth * 2;
1579 case 0: /* Standard */
1580 case 4: /* (Sub)Paragraph */
1581 case 5: /* Description */
1583 case 6: /* Abstract */
1584 buffer << "Abstract\n\n";
1586 case 7: /* Bibliography */
1588 buffer << "References\n\n";
1593 buffer << par->labelstring << " ";
1596 if (ltype_depth > depth) {
1597 for(char j = ltype_depth - 1; j > depth; --j)
1599 currlinelen += (ltype_depth-depth)*2;
1602 font2 = par->GetFontSettings(params, i);
1603 if (font1.latex() != font2.latex()) {
1604 if (font2.latex() == LyXFont::OFF)
1611 c = par->GetChar(i);
1615 case LyXParagraph::META_INSET:
1616 if ((inset = par->GetInset(i))) {
1617 if (!inset->Ascii(this, buffer)) {
1619 string s = rsplit(buffer.str(),
1621 currlinelen += s.length();
1623 // to be sure it breaks paragraph
1624 currlinelen += linelen;
1628 case LyXParagraph::META_NEWLINE:
1630 for(char j = 0; j < depth; ++j)
1632 currlinelen = depth * 2;
1633 if (ltype_depth > depth) {
1634 for(char j = ltype_depth;
1637 currlinelen += (ltype_depth - depth) * 2;
1640 case LyXParagraph::META_HFILL:
1647 if ((linelen > 0) && (currlinelen > (linelen - 10)) &&
1648 (c == ' ') && ((i + 2) < par->size()))
1651 for(char j = 0; j < depth; ++j)
1653 currlinelen = depth * 2;
1654 if (ltype_depth > depth) {
1655 for(char j = ltype_depth;
1658 currlinelen += (ltype_depth-depth)*2;
1660 } else if (c != '\0')
1663 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1668 return buffer.str();
1672 void Buffer::writeFileAscii(string const & fname, int linelen)
1674 ofstream ofs(fname.c_str());
1676 WriteFSAlert(_("Error: Cannot write file:"), fname);
1679 writeFileAscii(ofs, linelen);
1683 void Buffer::writeFileAscii(ostream & ofs, int linelen)
1685 LyXParagraph * par = paragraph;
1687 ofs << asciiParagraph(par, linelen);
1694 void Buffer::makeLaTeXFile(string const & fname,
1695 string const & original_path,
1696 bool nice, bool only_body)
1698 lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1700 niceFile = nice; // this will be used by Insetincludes.
1702 tex_code_break_column = lyxrc.ascii_linelen;
1704 LyXTextClass const & tclass =
1705 textclasslist.TextClass(params.textclass);
1707 ofstream ofs(fname.c_str());
1709 WriteFSAlert(_("Error: Cannot open file: "), fname);
1713 // validate the buffer.
1714 lyxerr[Debug::LATEX] << " Validating buffer..." << endl;
1715 LaTeXFeatures features(params, tclass.numLayouts());
1717 lyxerr[Debug::LATEX] << " Buffer validation done." << endl;
1720 // The starting paragraph of the coming rows is the
1721 // first paragraph of the document. (Asger)
1722 texrow.start(paragraph, 0);
1724 if (!only_body && nice) {
1725 ofs << "%% " LYX_DOCVERSION " created this file. "
1726 "For more info, see http://www.lyx.org/.\n"
1727 "%% Do not edit unless you really know what "
1732 lyxerr.debug() << "lyx header finished" << endl;
1733 // There are a few differences between nice LaTeX and usual files:
1734 // usual is \batchmode and has a
1735 // special input@path to allow the including of figures
1736 // with either \input or \includegraphics (what figinsets do).
1737 // batchmode is not set if there is a tex_code_break_column.
1738 // In this case somebody is interested in the generated LaTeX,
1739 // so this is OK. input@path is set when the actual parameter
1740 // original_path is set. This is done for usual tex-file, but not
1741 // for nice-latex-file. (Matthias 250696)
1744 // code for usual, NOT nice-latex-file
1745 ofs << "\\batchmode\n"; // changed
1746 // from \nonstopmode
1749 if (!original_path.empty()) {
1750 ofs << "\\makeatletter\n"
1751 << "\\def\\input@path{{"
1752 << original_path << "/}}\n"
1753 << "\\makeatother\n";
1759 ofs << "\\documentclass";
1761 string options; // the document class options.
1763 if (tokenPos(tclass.opt_fontsize(),
1764 '|', params.fontsize) >= 0) {
1765 // only write if existing in list (and not default)
1766 options += params.fontsize;
1771 if (!params.use_geometry &&
1772 (params.paperpackage == BufferParams::PACKAGE_NONE)) {
1773 switch (params.papersize) {
1774 case BufferParams::PAPER_A4PAPER:
1775 options += "a4paper,";
1777 case BufferParams::PAPER_USLETTER:
1778 options += "letterpaper,";
1780 case BufferParams::PAPER_A5PAPER:
1781 options += "a5paper,";
1783 case BufferParams::PAPER_B5PAPER:
1784 options += "b5paper,";
1786 case BufferParams::PAPER_EXECUTIVEPAPER:
1787 options += "executivepaper,";
1789 case BufferParams::PAPER_LEGALPAPER:
1790 options += "legalpaper,";
1796 if (params.sides != tclass.sides()) {
1797 switch (params.sides) {
1798 case LyXTextClass::OneSide:
1799 options += "oneside,";
1801 case LyXTextClass::TwoSides:
1802 options += "twoside,";
1809 if (params.columns != tclass.columns()) {
1810 if (params.columns == 2)
1811 options += "twocolumn,";
1813 options += "onecolumn,";
1816 if (!params.use_geometry
1817 && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1818 options += "landscape,";
1820 // language should be a parameter to \documentclass
1821 bool use_babel = false;
1822 if (params.language_info->lang() == "hebrew") // This seems necessary
1823 features.UsedLanguages.insert(default_language);
1824 if (params.language != "default" ||
1825 !features.UsedLanguages.empty() ) {
1827 for (LaTeXFeatures::LanguageList::const_iterator cit =
1828 features.UsedLanguages.begin();
1829 cit != features.UsedLanguages.end(); ++cit)
1830 options += (*cit)->lang() + ",";
1831 options += params.language_info->lang() + ',';
1834 // the user-defined options
1835 if (!params.options.empty()) {
1836 options += params.options + ',';
1839 if (!options.empty()){
1840 options = strip(options, ',');
1841 ofs << '[' << options << ']';
1845 << textclasslist.LatexnameOfClass(params.textclass)
1848 // end of \documentclass defs
1850 // font selection must be done before loading fontenc.sty
1851 if (params.fonts != "default") {
1852 ofs << "\\usepackage{" << params.fonts << "}\n";
1855 // this one is not per buffer
1856 if (lyxrc.fontenc != "default") {
1857 ofs << "\\usepackage[" << lyxrc.fontenc
1862 if (params.inputenc == "auto") {
1863 string const doc_encoding =
1864 params.language_info->encoding()->LatexName();
1866 // Create a list with all the input encodings used
1868 set<string> encodings;
1869 for (LaTeXFeatures::LanguageList::const_iterator it =
1870 features.UsedLanguages.begin();
1871 it != features.UsedLanguages.end(); ++it)
1872 if ((*it)->encoding()->LatexName() != doc_encoding)
1873 encodings.insert((*it)->encoding()->LatexName());
1875 ofs << "\\usepackage[";
1876 for (set<string>::const_iterator it = encodings.begin();
1877 it != encodings.end(); ++it)
1879 ofs << doc_encoding << "]{inputenc}\n";
1881 } else if (params.inputenc != "default") {
1882 ofs << "\\usepackage[" << params.inputenc
1887 // At the very beginning the text parameters.
1888 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
1889 switch (params.paperpackage) {
1890 case BufferParams::PACKAGE_A4:
1891 ofs << "\\usepackage{a4}\n";
1894 case BufferParams::PACKAGE_A4WIDE:
1895 ofs << "\\usepackage{a4wide}\n";
1898 case BufferParams::PACKAGE_WIDEMARGINSA4:
1899 ofs << "\\usepackage[widemargins]{a4}\n";
1904 if (params.use_geometry) {
1905 ofs << "\\usepackage{geometry}\n";
1907 ofs << "\\geometry{verbose";
1908 if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1909 ofs << ",landscape";
1910 switch (params.papersize2) {
1911 case BufferParams::VM_PAPER_CUSTOM:
1912 if (!params.paperwidth.empty())
1913 ofs << ",paperwidth="
1914 << params.paperwidth;
1915 if (!params.paperheight.empty())
1916 ofs << ",paperheight="
1917 << params.paperheight;
1919 case BufferParams::VM_PAPER_USLETTER:
1920 ofs << ",letterpaper";
1922 case BufferParams::VM_PAPER_USLEGAL:
1923 ofs << ",legalpaper";
1925 case BufferParams::VM_PAPER_USEXECUTIVE:
1926 ofs << ",executivepaper";
1928 case BufferParams::VM_PAPER_A3:
1931 case BufferParams::VM_PAPER_A4:
1934 case BufferParams::VM_PAPER_A5:
1937 case BufferParams::VM_PAPER_B3:
1940 case BufferParams::VM_PAPER_B4:
1943 case BufferParams::VM_PAPER_B5:
1947 // default papersize ie BufferParams::VM_PAPER_DEFAULT
1948 switch (lyxrc.default_papersize) {
1949 case BufferParams::PAPER_DEFAULT: // keep compiler happy
1950 case BufferParams::PAPER_USLETTER:
1951 ofs << ",letterpaper";
1953 case BufferParams::PAPER_LEGALPAPER:
1954 ofs << ",legalpaper";
1956 case BufferParams::PAPER_EXECUTIVEPAPER:
1957 ofs << ",executivepaper";
1959 case BufferParams::PAPER_A3PAPER:
1962 case BufferParams::PAPER_A4PAPER:
1965 case BufferParams::PAPER_A5PAPER:
1968 case BufferParams::PAPER_B5PAPER:
1973 if (!params.topmargin.empty())
1974 ofs << ",tmargin=" << params.topmargin;
1975 if (!params.bottommargin.empty())
1976 ofs << ",bmargin=" << params.bottommargin;
1977 if (!params.leftmargin.empty())
1978 ofs << ",lmargin=" << params.leftmargin;
1979 if (!params.rightmargin.empty())
1980 ofs << ",rmargin=" << params.rightmargin;
1981 if (!params.headheight.empty())
1982 ofs << ",headheight=" << params.headheight;
1983 if (!params.headsep.empty())
1984 ofs << ",headsep=" << params.headsep;
1985 if (!params.footskip.empty())
1986 ofs << ",footskip=" << params.footskip;
1990 if (params.use_amsmath
1991 && !tclass.provides(LyXTextClass::amsmath)) {
1992 ofs << "\\usepackage{amsmath}\n";
1996 if (tokenPos(tclass.opt_pagestyle(),
1997 '|', params.pagestyle) >= 0) {
1998 if (params.pagestyle == "fancy") {
1999 ofs << "\\usepackage{fancyhdr}\n";
2002 ofs << "\\pagestyle{" << params.pagestyle << "}\n";
2006 // We try to load babel late, in case it interferes
2007 // with other packages.
2009 ofs << lyxrc.language_package << endl;
2013 if (params.secnumdepth != tclass.secnumdepth()) {
2014 ofs << "\\setcounter{secnumdepth}{"
2015 << params.secnumdepth
2019 if (params.tocdepth != tclass.tocdepth()) {
2020 ofs << "\\setcounter{tocdepth}{"
2026 if (params.paragraph_separation) {
2027 switch (params.defskip.kind()) {
2028 case VSpace::SMALLSKIP:
2029 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
2031 case VSpace::MEDSKIP:
2032 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2034 case VSpace::BIGSKIP:
2035 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
2037 case VSpace::LENGTH:
2038 ofs << "\\setlength\\parskip{"
2039 << params.defskip.length().asLatexString()
2042 default: // should never happen // Then delete it.
2043 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2048 ofs << "\\setlength\\parindent{0pt}\n";
2052 // Now insert the LyX specific LaTeX commands...
2054 // The optional packages;
2055 string preamble(features.getPackages());
2057 // this might be useful...
2058 preamble += "\n\\makeatletter\n";
2060 // Some macros LyX will need
2061 string tmppreamble(features.getMacros());
2063 if (!tmppreamble.empty()) {
2064 preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2065 "LyX specific LaTeX commands.\n"
2066 + tmppreamble + '\n';
2069 // the text class specific preamble
2070 tmppreamble = features.getTClassPreamble();
2071 if (!tmppreamble.empty()) {
2072 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2073 "Textclass specific LaTeX commands.\n"
2074 + tmppreamble + '\n';
2077 /* the user-defined preamble */
2078 if (!params.preamble.empty()) {
2079 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2080 "User specified LaTeX commands.\n"
2081 + params.preamble + '\n';
2084 preamble += "\\makeatother\n";
2086 // Itemize bullet settings need to be last in case the user
2087 // defines their own bullets that use a package included
2088 // in the user-defined preamble -- ARRae
2089 // Actually it has to be done much later than that
2090 // since some packages like frenchb make modifications
2091 // at \begin{document} time -- JMarc
2093 for (int i = 0; i < 4; ++i) {
2094 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
2095 if (bullets_def.empty())
2096 bullets_def="\\AtBeginDocument{\n";
2097 bullets_def += " \\renewcommand{\\labelitemi";
2099 // `i' is one less than the item to modify
2106 bullets_def += "ii";
2112 bullets_def += "}{" +
2113 params.user_defined_bullets[i].getText()
2118 if (!bullets_def.empty())
2119 preamble += bullets_def + "}\n\n";
2121 for (int j = countChar(preamble, '\n'); j-- ;) {
2128 ofs << "\\begin{document}\n";
2131 lyxerr.debug() << "preamble finished, now the body." << endl;
2132 if (!lyxrc.language_auto_begin && params.language != "default") {
2133 ofs << subst(lyxrc.language_command_begin, "$$lang",
2139 latexParagraphs(ofs, paragraph, 0, texrow);
2141 // add this just in case after all the paragraphs
2145 if (!lyxrc.language_auto_end && params.language != "default") {
2146 ofs << subst(lyxrc.language_command_end, "$$lang",
2153 ofs << "\\end{document}\n";
2156 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2158 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2162 // Just to be sure. (Asger)
2165 // tex_code_break_column's value is used to decide
2166 // if we are in batchmode or not (within mathed_write()
2167 // in math_write.C) so we must set it to a non-zero
2168 // value when we leave otherwise we save incorrect .lyx files.
2169 tex_code_break_column = lyxrc.ascii_linelen;
2173 lyxerr << "File was not closed properly." << endl;
2176 lyxerr.debug() << "Finished making latex file." << endl;
2181 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2183 void Buffer::latexParagraphs(ostream & ofs, LyXParagraph * par,
2184 LyXParagraph * endpar, TexRow & texrow) const
2186 bool was_title = false;
2187 bool already_title = false;
2188 std::ostringstream ftnote;
2193 while (par != endpar) {
2196 lyxerr[Debug::LATEX] << "Error in latexParagraphs."
2199 LyXLayout const & layout =
2200 textclasslist.Style(params.textclass,
2203 if (layout.intitle) {
2204 if (already_title) {
2205 lyxerr <<"Error in latexParagraphs: You"
2206 " should not mix title layouts"
2207 " with normal ones." << endl;
2210 } else if (was_title && !already_title) {
2211 ofs << "\\maketitle\n";
2213 already_title = true;
2216 // We are at depth 0 so we can just use
2217 // ordinary \footnote{} generation
2218 // flag this with ftcount
2220 if (layout.isEnvironment()
2221 || par->pextra_type != LyXParagraph::PEXTRA_NONE) {
2222 par = par->TeXEnvironment(this, params, ofs, texrow
2224 ,ftnote, ft_texrow, ftcount
2228 par = par->TeXOnePar(this, params, ofs, texrow, false
2231 ftnote, ft_texrow, ftcount
2236 // Write out what we've generated...
2239 ofs << "\\addtocounter{footnote}{-"
2243 ofs << ftnote.str();
2244 texrow += ft_texrow;
2246 // The extra .c_str() is needed when we use
2247 // lyxstring instead of the STL string class.
2248 ftnote.str(string().c_str());
2253 // It might be that we only have a title in this document
2254 if (was_title && !already_title) {
2255 ofs << "\\maketitle\n";
2261 bool Buffer::isLatex() const
2263 return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2267 bool Buffer::isLinuxDoc() const
2269 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2273 bool Buffer::isLiterate() const
2275 return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2279 bool Buffer::isDocBook() const
2281 return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2285 bool Buffer::isSGML() const
2287 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2288 textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2292 void Buffer::sgmlOpenTag(ostream & os, int depth,
2293 string const & latexname) const
2295 os << string(depth, ' ') << "<" << latexname << ">\n";
2299 void Buffer::sgmlCloseTag(ostream & os, int depth,
2300 string const & latexname) const
2302 os << string(depth, ' ') << "</" << latexname << ">\n";
2306 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2308 LyXParagraph * par = paragraph;
2310 niceFile = nice; // this will be used by Insetincludes.
2312 string top_element = textclasslist.LatexnameOfClass(params.textclass);
2313 string environment_stack[10];
2316 int depth = 0; // paragraph depth
2318 ofstream ofs(fname.c_str());
2321 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2325 LyXTextClass const & tclass =
2326 textclasslist.TextClass(params.textclass);
2328 LaTeXFeatures features(params, tclass.numLayouts());
2332 tex_code_break_column = lyxrc.ascii_linelen;
2334 //tex_code_break_column = 0;
2339 string sgml_includedfiles=features.getIncludedFiles();
2341 if (params.preamble.empty() && sgml_includedfiles.empty()) {
2342 ofs << "<!doctype linuxdoc system>\n\n";
2344 ofs << "<!doctype linuxdoc system [ "
2345 << params.preamble << sgml_includedfiles << " \n]>\n\n";
2348 if(params.options.empty())
2349 sgmlOpenTag(ofs, 0, top_element);
2351 string top = top_element;
2353 top += params.options;
2354 sgmlOpenTag(ofs, 0, top);
2358 ofs << "<!-- " << LYX_DOCVERSION
2359 << " created this file. For more info see http://www.lyx.org/"
2363 int desc_on = 0; // description mode
2364 LyXLayout const & style =
2365 textclasslist.Style(params.textclass,
2368 // treat <toc> as a special case for compatibility with old code
2369 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2370 Inset * inset = par->GetInset(0);
2371 Inset::Code lyx_code = inset->LyxCode();
2372 if (lyx_code == Inset::TOC_CODE){
2373 string const temp = "toc";
2374 sgmlOpenTag(ofs, depth, temp);
2378 linuxDocHandleFootnote(ofs, par, depth);
2384 // environment tag closing
2385 for (; depth > par->depth; --depth) {
2386 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2387 environment_stack[depth].erase();
2390 // write opening SGML tags
2391 switch (style.latextype) {
2392 case LATEX_PARAGRAPH:
2393 if(depth == par->depth
2394 && !environment_stack[depth].empty()) {
2395 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2396 environment_stack[depth].erase();
2402 sgmlOpenTag(ofs, depth, style.latexname());
2407 LinuxDocError(par, 0,
2408 _("Error : Wrong depth for"
2409 " LatexType Command.\n"));
2411 if (!environment_stack[depth].empty()){
2412 sgmlCloseTag(ofs, depth,
2413 environment_stack[depth]);
2417 environment_stack[depth].erase();
2418 sgmlOpenTag(ofs, depth, style.latexname());
2421 case LATEX_ENVIRONMENT:
2422 case LATEX_ITEM_ENVIRONMENT:
2423 if (depth == par->depth
2424 && environment_stack[depth] != style.latexname()
2425 && !environment_stack[depth].empty()) {
2427 sgmlCloseTag(ofs, depth,
2428 environment_stack[depth]);
2429 environment_stack[depth].erase();
2431 if (depth < par->depth) {
2433 environment_stack[depth].erase();
2435 if (environment_stack[depth] != style.latexname()) {
2437 string const temp = "p";
2438 sgmlOpenTag(ofs, depth, temp);
2440 environment_stack[depth] = style.latexname();
2441 sgmlOpenTag(ofs, depth,
2442 environment_stack[depth]);
2444 if(style.latextype == LATEX_ENVIRONMENT) break;
2446 desc_on = (style.labeltype == LABEL_MANUAL);
2453 sgmlOpenTag(ofs, depth + 1, item_name);
2456 sgmlOpenTag(ofs, depth, style.latexname());
2463 SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2467 linuxDocHandleFootnote(ofs, par, depth);
2469 while(par && par->IsDummy());
2473 // write closing SGML tags
2474 switch(style.latextype) {
2476 case LATEX_ENVIRONMENT:
2477 case LATEX_ITEM_ENVIRONMENT:
2480 sgmlCloseTag(ofs, depth, style.latexname());
2486 for(; depth > 0; --depth)
2487 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2489 if(!environment_stack[depth].empty())
2490 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2494 sgmlCloseTag(ofs, 0, top_element);
2498 // How to check for successful close
2503 void Buffer::linuxDocHandleFootnote(ostream & os, LyXParagraph * & par,
2506 string const tag = "footnote";
2508 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2509 sgmlOpenTag(os, depth + 1, tag);
2510 SimpleLinuxDocOnePar(os, par, 0, depth + 1);
2511 sgmlCloseTag(os, depth + 1, tag);
2518 void Buffer::DocBookHandleCaption(ostream & os, string & inner_tag,
2519 int depth, int desc_on,
2520 LyXParagraph * & par)
2522 LyXParagraph * tpar = par;
2525 && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE)
2527 && (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2531 tpar->layout == textclasslist.NumberOfLayout(params.textclass,
2532 "Caption").second) {
2533 sgmlOpenTag(os, depth + 1, inner_tag);
2535 SimpleDocBookOnePar(os, extra_par, tpar,
2536 desc_on, depth + 2);
2537 sgmlCloseTag(os, depth+1, inner_tag);
2538 if(!extra_par.empty())
2545 void Buffer::DocBookHandleFootnote(ostream & os, LyXParagraph * & par,
2548 string tag, inner_tag;
2549 string tmp_par, extra_par;
2550 bool inner_span = false;
2553 // Someone should give this enum a proper name (Lgb)
2561 SOME_ENUM last = NO_ONE;
2562 SOME_ENUM present = FOOTNOTE_LIKE;
2564 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2565 if (last == present) {
2567 if (!tmp_par.empty()) {
2570 sgmlCloseTag(os, depth + 1, inner_tag);
2571 sgmlOpenTag(os, depth + 1, inner_tag);
2578 if (!inner_tag.empty()) sgmlCloseTag(os, depth + 1,
2580 if (!extra_par.empty()) os << extra_par;
2581 if (!tag.empty()) sgmlCloseTag(os, depth, tag);
2584 switch (par->footnotekind) {
2585 case LyXParagraph::FOOTNOTE:
2586 case LyXParagraph::ALGORITHM:
2589 present = FOOTNOTE_LIKE;
2592 case LyXParagraph::MARGIN:
2595 present = MARGIN_LIKE;
2598 case LyXParagraph::FIG:
2599 case LyXParagraph::WIDE_FIG:
2601 inner_tag = "title";
2605 case LyXParagraph::TAB:
2606 case LyXParagraph::WIDE_TAB:
2608 inner_tag = "title";
2613 sgmlOpenTag(os, depth, tag);
2614 if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2615 DocBookHandleCaption(os, inner_tag, depth,
2619 sgmlOpenTag(os, depth + 1, inner_tag);
2622 // ignore all caption here, we processed them above!!!
2623 if (par->layout != textclasslist
2624 .NumberOfLayout(params.textclass,
2625 "Caption").second) {
2626 std::ostringstream ost;
2627 SimpleDocBookOnePar(ost, extra_par, par,
2628 desc_on, depth + 2);
2629 tmp_par += ost.str().c_str();
2631 tmp_par = frontStrip(strip(tmp_par));
2637 if(!inner_tag.empty()) sgmlCloseTag(os, depth + 1, inner_tag);
2638 if(!extra_par.empty()) os << extra_par;
2639 if(!tag.empty()) sgmlCloseTag(os, depth, tag);
2644 // push a tag in a style stack
2645 void Buffer::push_tag(ostream & os, string const & tag,
2646 int & pos, char stack[5][3])
2648 #warning Use a real stack! (Lgb)
2649 // pop all previous tags
2650 for (int j = pos; j >= 0; --j)
2651 os << "</" << stack[j] << ">";
2654 sprintf(stack[++pos], "%s", tag.c_str());
2657 for (int i = 0; i <= pos; ++i)
2658 os << "<" << stack[i] << ">";
2662 void Buffer::pop_tag(ostream & os, string const & tag,
2663 int & pos, char stack[5][3])
2665 #ifdef WITH_WARNINGS
2666 #warning Use a real stack! (Lgb)
2668 // Please, Lars, do not remove the global variable. I already
2669 // had to reintroduce it twice! (JMarc)
2672 // pop all tags till specified one
2673 for (j = pos; (j >= 0) && (strcmp(stack[j], tag.c_str())); --j)
2674 os << "</" << stack[j] << ">";
2677 os << "</" << tag << ">";
2679 // push all tags, but the specified one
2680 for (j = j + 1; j <= pos; ++j) {
2681 os << "<" << stack[j] << ">";
2682 strcpy(stack[j-1], stack[j]);
2688 // Handle internal paragraph parsing -- layout already processed.
2690 // checks, if newcol chars should be put into this line
2691 // writes newline, if necessary.
2693 void linux_doc_line_break(ostream & os, string::size_type & colcount,
2694 string::size_type newcol)
2697 if (colcount > lyxrc.ascii_linelen) {
2699 colcount = newcol; // assume write after this call
2704 void Buffer::SimpleLinuxDocOnePar(ostream & os, LyXParagraph * par,
2705 int desc_on, int /*depth*/)
2710 LyXParagraph::size_type main_body;
2712 LyXLayout const & style = textclasslist.Style(params.textclass,
2715 char family_type = 0; // family font flag
2716 bool is_bold = false; // series font flag
2717 char shape_type = 0; // shape font flag
2718 bool is_em = false; // emphasis (italic) font flag
2720 int stack_num = -1; // style stack position
2721 // Can this be rewritten to use a std::stack, please. (Lgb)
2722 char stack[5][3]; // style stack
2723 string::size_type char_line_count = 5; // Heuristic choice ;-)
2725 if (style.labeltype != LABEL_MANUAL)
2728 main_body = par->BeginningOfMainBody();
2730 // gets paragraph main font
2732 font1 = style.labelfont;
2737 // parsing main loop
2738 for (LyXParagraph::size_type i = 0;
2739 i < par->size(); ++i) {
2751 LyXFont const font2 = par->getFont(params, i);
2753 if (font1.family() != font2.family()) {
2754 switch(family_type) {
2756 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2757 push_tag(os, "tt", stack_num, stack);
2760 else if (font2.family() == LyXFont::SANS_FAMILY) {
2761 push_tag(os, "sf", stack_num, stack);
2766 pop_tag(os, "tt", stack_num, stack);
2767 if (font2.family() == LyXFont::SANS_FAMILY) {
2768 push_tag(os, "sf", stack_num, stack);
2775 pop_tag(os, "sf", stack_num, stack);
2776 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2777 push_tag(os, "tt", stack_num, stack);
2786 if (font1.series() != font2.series()) {
2787 if (font2.series() == LyXFont::BOLD_SERIES) {
2788 push_tag(os, "bf", stack_num, stack);
2790 } else if (is_bold) {
2791 pop_tag(os, "bf", stack_num, stack);
2796 // handle italic and slanted fonts
2797 if (font1.shape() != font2.shape()) {
2798 switch(shape_type) {
2800 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2801 push_tag(os, "it", stack_num, stack);
2803 } else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2804 push_tag(os, "sl", stack_num, stack);
2809 pop_tag(os, "it", stack_num, stack);
2810 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2811 push_tag(os, "sl", stack_num, stack);
2818 pop_tag(os, "sl", stack_num, stack);
2819 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2820 push_tag(os, "it", stack_num, stack);
2828 if (font1.emph() != font2.emph()) {
2829 if (font2.emph() == LyXFont::ON) {
2830 push_tag(os, "em", stack_num, stack);
2833 pop_tag(os, "em", stack_num, stack);
2838 c = par->GetChar(i);
2840 if (c == LyXParagraph::META_INSET) {
2841 inset = par->GetInset(i);
2842 inset->Linuxdoc(this, os);
2845 if (font2.latex() == LyXFont::ON) {
2846 // "TeX"-Mode on == > SGML-Mode on.
2848 os << c; // see LaTeX-Generation...
2852 if (par->linuxDocConvertChar(c, sgml_string)
2853 && !style.free_spacing) { // in freespacing
2855 // non-breaking characters
2859 linux_doc_line_break(os, char_line_count, 6);
2863 linux_doc_line_break(os, char_line_count, 1);
2868 char_line_count += sgml_string.length();
2874 // needed if there is an optional argument but no contents
2875 if (main_body > 0 && main_body == par->size()) {
2879 // pop all defined Styles
2880 for (j = stack_num; j >= 0; --j) {
2881 linux_doc_line_break(os,
2883 3 + strlen(stack[j]));
2884 os << "</" << stack[j] << ">";
2887 // resets description flag correctly
2890 // <tag> not closed...
2891 linux_doc_line_break(os, char_line_count, 6);
2895 // fprintf(file, "</p>");
2901 // Print an error message.
2902 void Buffer::LinuxDocError(LyXParagraph * par, int pos,
2903 string const & message)
2905 // insert an error marker in text
2906 InsetError * new_inset = new InsetError(message);
2907 par->InsertInset(pos, new_inset);
2910 // This constant defines the maximum number of
2911 // environment layouts that can be nesteded.
2912 // The same applies for command layouts.
2913 // These values should be more than enough.
2914 // José Matos (1999/07/22)
2916 enum { MAX_NEST_LEVEL = 25};
2918 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
2920 LyXParagraph * par = paragraph;
2922 niceFile = nice; // this will be used by Insetincludes.
2924 string top_element= textclasslist.LatexnameOfClass(params.textclass);
2925 // Please use a real stack.
2926 string environment_stack[MAX_NEST_LEVEL];
2927 string environment_inner[MAX_NEST_LEVEL];
2928 // Please use a real stack.
2929 string command_stack[MAX_NEST_LEVEL];
2930 bool command_flag= false;
2931 int command_depth= 0, command_base= 0, cmd_depth= 0;
2933 string item_name, command_name;
2934 string c_depth, c_params, tmps;
2936 int depth = 0; // paragraph depth
2937 LyXTextClass const & tclass =
2938 textclasslist.TextClass(params.textclass);
2940 LaTeXFeatures features(params, tclass.numLayouts());
2944 tex_code_break_column = lyxrc.ascii_linelen;
2946 //tex_code_break_column = 0;
2948 ofstream ofs(fname.c_str());
2950 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2957 string sgml_includedfiles=features.getIncludedFiles();
2959 ofs << "<!doctype " << top_element
2960 << " public \"-//OASIS//DTD DocBook V3.1//EN\"";
2962 if (params.preamble.empty() && sgml_includedfiles.empty())
2965 ofs << "\n [ " << params.preamble
2966 << sgml_includedfiles << " \n]>\n\n";
2968 if(params.options.empty())
2969 sgmlOpenTag(ofs, 0, top_element);
2971 string top = top_element;
2973 top += params.options;
2974 sgmlOpenTag(ofs, 0, top);
2978 ofs << "<!-- DocBook file was created by " << LYX_DOCVERSION
2979 << "\n See http://www.lyx.org/ for more information -->\n";
2982 int desc_on = 0; // description mode
2983 LyXLayout const & style =
2984 textclasslist.Style(params.textclass,
2987 // environment tag closing
2988 for( ; depth > par->depth; --depth) {
2989 if(environment_inner[depth] != "!-- --") {
2990 item_name= "listitem";
2991 sgmlCloseTag(ofs, command_depth + depth,
2993 if( environment_inner[depth] == "varlistentry")
2994 sgmlCloseTag(ofs, depth+command_depth,
2995 environment_inner[depth]);
2997 sgmlCloseTag(ofs, depth + command_depth,
2998 environment_stack[depth]);
2999 environment_stack[depth].erase();
3000 environment_inner[depth].erase();
3003 if(depth == par->depth
3004 && environment_stack[depth] != style.latexname()
3005 && !environment_stack[depth].empty()) {
3006 if(environment_inner[depth] != "!-- --") {
3007 item_name= "listitem";
3008 sgmlCloseTag(ofs, command_depth+depth,
3010 if( environment_inner[depth] == "varlistentry")
3012 depth + command_depth,
3013 environment_inner[depth]);
3016 sgmlCloseTag(ofs, depth + command_depth,
3017 environment_stack[depth]);
3019 environment_stack[depth].erase();
3020 environment_inner[depth].erase();
3023 // Write opening SGML tags.
3024 switch(style.latextype) {
3025 case LATEX_PARAGRAPH:
3026 if(style.latexname() != "dummy")
3027 sgmlOpenTag(ofs, depth+command_depth,
3033 LinuxDocError(par, 0,
3034 _("Error : Wrong depth for "
3035 "LatexType Command.\n"));
3037 command_name = style.latexname();
3039 tmps = style.latexparam();
3040 c_params = split(tmps, c_depth,'|');
3042 cmd_depth= lyx::atoi(c_depth);
3045 if(cmd_depth<command_base) {
3046 for(int j = command_depth;
3047 j >= command_base; --j)
3048 if(!command_stack[j].empty())
3049 sgmlCloseTag(ofs, j, command_stack[j]);
3050 command_depth= command_base= cmd_depth;
3051 } else if(cmd_depth <= command_depth) {
3052 for(int j = command_depth;
3053 j >= cmd_depth; --j)
3055 if(!command_stack[j].empty())
3056 sgmlCloseTag(ofs, j, command_stack[j]);
3057 command_depth= cmd_depth;
3059 command_depth= cmd_depth;
3061 command_depth = command_base = cmd_depth;
3062 command_flag = true;
3064 command_stack[command_depth]= command_name;
3066 // treat label as a special case for
3067 // more WYSIWYM handling.
3068 if (par->GetChar(0) == LyXParagraph::META_INSET) {
3069 Inset * inset = par->GetInset(0);
3070 Inset::Code lyx_code = inset->LyxCode();
3071 if (lyx_code == Inset::LABEL_CODE){
3072 command_name += " id=\"";
3073 command_name += (static_cast<InsetCommand *>(inset))->getContents();
3074 command_name += "\"";
3079 sgmlOpenTag(ofs, depth + command_depth, command_name);
3080 item_name = "title";
3081 sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
3084 case LATEX_ENVIRONMENT:
3085 case LATEX_ITEM_ENVIRONMENT:
3086 if (depth < par->depth) {
3088 environment_stack[depth].erase();
3091 if (environment_stack[depth] != style.latexname()) {
3092 environment_stack[depth] = style.latexname();
3093 environment_inner[depth] = "!-- --";
3094 sgmlOpenTag(ofs, depth + command_depth,
3095 environment_stack[depth]);
3097 if(environment_inner[depth] != "!-- --") {
3098 item_name= "listitem";
3100 command_depth + depth,
3102 if (environment_inner[depth] == "varlistentry")
3104 depth + command_depth,
3105 environment_inner[depth]);
3109 if(style.latextype == LATEX_ENVIRONMENT) {
3110 if(!style.latexparam().empty())
3111 sgmlOpenTag(ofs, depth + command_depth,
3112 style.latexparam());
3116 desc_on = (style.labeltype == LABEL_MANUAL);
3119 environment_inner[depth]= "varlistentry";
3121 environment_inner[depth]= "listitem";
3123 sgmlOpenTag(ofs, depth + 1 + command_depth,
3124 environment_inner[depth]);
3128 sgmlOpenTag(ofs, depth + 1 + command_depth,
3132 sgmlOpenTag(ofs, depth + 1 + command_depth,
3137 sgmlOpenTag(ofs, depth + command_depth,
3146 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3147 depth + 1 + command_depth);
3150 DocBookHandleFootnote(ofs, par,
3151 depth + 1 + command_depth);
3153 while(par && par->IsDummy());
3156 // write closing SGML tags
3157 switch(style.latextype) {
3160 sgmlCloseTag(ofs, depth + command_depth, end_tag);
3162 case LATEX_ENVIRONMENT:
3163 if(!style.latexparam().empty())
3164 sgmlCloseTag(ofs, depth + command_depth,
3165 style.latexparam());
3167 case LATEX_ITEM_ENVIRONMENT:
3168 if(desc_on == 1) break;
3170 sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
3172 case LATEX_PARAGRAPH:
3173 if(style.latexname() != "dummy")
3174 sgmlCloseTag(ofs, depth + command_depth,
3178 sgmlCloseTag(ofs, depth + command_depth,
3185 for(; depth >= 0; --depth) {
3186 if(!environment_stack[depth].empty()) {
3187 if(environment_inner[depth] != "!-- --") {
3188 item_name= "listitem";
3189 sgmlCloseTag(ofs, command_depth + depth,
3191 if( environment_inner[depth] == "varlistentry")
3192 sgmlCloseTag(ofs, depth + command_depth,
3193 environment_inner[depth]);
3196 sgmlCloseTag(ofs, depth + command_depth,
3197 environment_stack[depth]);
3201 for(int j = command_depth; j >= command_base; --j)
3202 if(!command_stack[j].empty())
3203 sgmlCloseTag(ofs, j, command_stack[j]);
3207 sgmlCloseTag(ofs, 0, top_element);
3211 // How to check for successful close
3215 void Buffer::SimpleDocBookOnePar(ostream & os, string & extra,
3216 LyXParagraph * par, int & desc_on,
3219 bool emph_flag = false;
3221 LyXLayout const & style = textclasslist.Style(params.textclass,
3224 LyXParagraph::size_type main_body;
3225 if (style.labeltype != LABEL_MANUAL)
3228 main_body = par->BeginningOfMainBody();
3230 // gets paragraph main font
3231 LyXFont font1 = main_body > 0 ? style.labelfont : style.font;
3233 int char_line_count = depth;
3234 if(!style.free_spacing)
3235 for (int j = 0; j < depth; ++j)
3238 // parsing main loop
3239 for (LyXParagraph::size_type i = 0;
3240 i < par->size(); ++i) {
3241 LyXFont font2 = par->getFont(params, i);
3243 // handle <emphasis> tag
3244 if (font1.emph() != font2.emph() && i) {
3245 if (font2.emph() == LyXFont::ON) {
3249 os << "</emphasis>";
3254 char c = par->GetChar(i);
3256 if (c == LyXParagraph::META_INSET) {
3257 Inset * inset = par->GetInset(i);
3258 std::ostringstream ost;
3259 inset->DocBook(this, ost);
3260 string tmp_out = ost.str().c_str();
3263 // This code needs some explanation:
3264 // Two insets are treated specially
3265 // label if it is the first element in a command paragraph
3267 // graphics inside tables or figure floats can't go on
3268 // title (the equivalente in latex for this case is caption
3269 // and title should come first
3272 if(desc_on!= 3 || i!= 0) {
3273 if(!tmp_out.empty() && tmp_out[0] == '@') {
3275 extra += frontStrip(tmp_out, '@');
3277 os << frontStrip(tmp_out, '@');
3282 } else if (font2.latex() == LyXFont::ON) {
3283 // "TeX"-Mode on ==> SGML-Mode on.
3289 if (par->linuxDocConvertChar(c, sgml_string)
3290 && !style.free_spacing) { // in freespacing
3292 // non-breaking characters
3296 os << "\n</term><listitem><para>";
3308 // needed if there is an optional argument but no contents
3309 if (main_body > 0 && main_body == par->size()) {
3313 os << "</emphasis>";
3316 // resets description flag correctly
3319 // <term> not closed...
3327 // This should be enabled when the Chktex class is implemented. (Asger)
3328 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3329 // Other flags: -wall -v0 -x
3330 int Buffer::runChktex()
3332 if (!users->text) return 0;
3334 ProhibitInput(users);
3336 // get LaTeX-Filename
3337 string const name = getLatexName();
3338 string path = OnlyPath(filename);
3340 string const org_path = path;
3341 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3345 Path p(path); // path to LaTeX file
3346 users->owner()->getMiniBuffer()->Set(_("Running chktex..."));
3348 // Remove all error insets
3349 bool const removedErrorInsets = users->removeAutoInsets();
3351 // Generate the LaTeX file if neccessary
3352 makeLaTeXFile(name, org_path, false);
3355 Chktex chktex(lyxrc.chktex_command, name, filepath);
3356 int res = chktex.run(terr); // run chktex
3359 WriteAlert(_("chktex did not work!"),
3360 _("Could not run with file:"), name);
3361 } else if (res > 0) {
3362 // Insert all errors as errors boxes
3363 users->insertErrors(terr);
3366 // if we removed error insets before we ran chktex or if we inserted
3367 // error insets after we ran chktex, this must be run:
3368 if (removedErrorInsets || res){
3370 users->fitCursor(users->text);
3378 void Buffer::validate(LaTeXFeatures & features) const
3380 LyXParagraph * par = paragraph;
3381 LyXTextClass const & tclass =
3382 textclasslist.TextClass(params.textclass);
3384 // AMS Style is at document level
3386 features.amsstyle = (params.use_amsmath ||
3387 tclass.provides(LyXTextClass::amsmath));
3390 // We don't use "lyxerr.debug" because of speed. (Asger)
3391 if (lyxerr.debugging(Debug::LATEX))
3392 lyxerr << "Paragraph: " << par << endl;
3394 // Now just follow the list of paragraphs and run
3395 // validate on each of them.
3396 par->validate(features);
3398 // and then the next paragraph
3402 // the bullet shapes are buffer level not paragraph level
3403 // so they are tested here
3404 for (int i = 0; i < 4; ++i) {
3405 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3406 int const font = params.user_defined_bullets[i].getFont();
3408 int const c = params
3409 .user_defined_bullets[i]
3416 features.latexsym = true;
3418 } else if (font == 1) {
3419 features.amssymb = true;
3420 } else if ((font >= 2 && font <= 5)) {
3421 features.pifont = true;
3426 if (lyxerr.debugging(Debug::LATEX)) {
3427 features.showStruct();
3432 void Buffer::setPaperStuff()
3434 params.papersize = BufferParams::PAPER_DEFAULT;
3435 char const c1 = params.paperpackage;
3436 if (c1 == BufferParams::PACKAGE_NONE) {
3437 char const c2 = params.papersize2;
3438 if (c2 == BufferParams::VM_PAPER_USLETTER)
3439 params.papersize = BufferParams::PAPER_USLETTER;
3440 else if (c2 == BufferParams::VM_PAPER_USLEGAL)
3441 params.papersize = BufferParams::PAPER_LEGALPAPER;
3442 else if (c2 == BufferParams::VM_PAPER_USEXECUTIVE)
3443 params.papersize = BufferParams::PAPER_EXECUTIVEPAPER;
3444 else if (c2 == BufferParams::VM_PAPER_A3)
3445 params.papersize = BufferParams::PAPER_A3PAPER;
3446 else if (c2 == BufferParams::VM_PAPER_A4)
3447 params.papersize = BufferParams::PAPER_A4PAPER;
3448 else if (c2 == BufferParams::VM_PAPER_A5)
3449 params.papersize = BufferParams::PAPER_A5PAPER;
3450 else if ((c2 == BufferParams::VM_PAPER_B3) || (c2 == BufferParams::VM_PAPER_B4) ||
3451 (c2 == BufferParams::VM_PAPER_B5))
3452 params.papersize = BufferParams::PAPER_B5PAPER;
3453 } else if ((c1 == BufferParams::PACKAGE_A4) || (c1 == BufferParams::PACKAGE_A4WIDE) ||
3454 (c1 == BufferParams::PACKAGE_WIDEMARGINSA4))
3455 params.papersize = BufferParams::PAPER_A4PAPER;
3459 // This function should be in Buffer because it's a buffer's property (ale)
3460 string const Buffer::getIncludeonlyList(char delim)
3463 for (inset_iterator it = inset_iterator_begin();
3464 it != inset_iterator_end(); ++it) {
3465 if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3466 InsetInclude * insetinc =
3467 static_cast<InsetInclude *>(*it);
3468 if (insetinc->isInclude()
3469 && insetinc->isNoLoad()) {
3472 lst += OnlyFilename(ChangeExtension(insetinc->getContents(), string()));
3476 lyxerr.debug() << "Includeonly(" << lst << ')' << endl;
3481 vector<string> const Buffer::getLabelList()
3483 /// if this is a child document and the parent is already loaded
3484 /// Use the parent's list instead [ale990407]
3485 if (!params.parentname.empty()
3486 && bufferlist.exists(params.parentname)) {
3487 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3489 return tmp->getLabelList();
3492 vector<string> label_list;
3493 for (inset_iterator it = inset_iterator_begin();
3494 it != inset_iterator_end(); ++it) {
3495 vector<string> const l = (*it)->getLabelList();
3496 label_list.insert(label_list.end(), l.begin(), l.end());
3502 vector<vector<Buffer::TocItem> > const Buffer::getTocList()
3504 vector<vector<TocItem> > l(4);
3505 LyXParagraph * par = paragraph;
3508 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3509 if (textclasslist.Style(params.textclass,
3510 par->GetLayout()).labeltype
3511 == LABEL_SENSITIVE) {
3515 tmp.str = par->String(this, false);
3516 switch (par->footnotekind) {
3517 case LyXParagraph::FIG:
3518 case LyXParagraph::WIDE_FIG:
3519 l[TOC_LOF].push_back(tmp);
3521 case LyXParagraph::TAB:
3522 case LyXParagraph::WIDE_TAB:
3523 l[TOC_LOT].push_back(tmp);
3525 case LyXParagraph::ALGORITHM:
3526 l[TOC_LOA].push_back(tmp);
3528 case LyXParagraph::FOOTNOTE:
3529 case LyXParagraph::MARGIN:
3533 } else if (!par->IsDummy()) {
3535 char const labeltype =
3536 textclasslist.Style(params.textclass,
3537 par->GetLayout()).labeltype;
3539 if (labeltype >= LABEL_COUNTER_CHAPTER
3540 && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3541 // insert this into the table of contents
3546 textclasslist.TextClass(params.textclass).maxcounter());
3547 tmp.str = par->String(this, true);
3548 l[TOC_TOC].push_back(tmp);
3559 // This is also a buffer property (ale)
3560 vector<pair<string,string> > const Buffer::getBibkeyList()
3562 /// if this is a child document and the parent is already loaded
3563 /// Use the parent's list instead [ale990412]
3564 if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3565 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3567 return tmp->getBibkeyList();
3570 vector<pair<string, string> > keys;
3571 LyXParagraph * par = paragraph;
3574 keys.push_back(pair<string, string>(par->bibkey->getContents(),
3575 par->String(this, false)));
3579 // Might be either using bibtex or a child has bibliography
3581 for (inset_iterator it = inset_iterator_begin();
3582 it != inset_iterator_end(); ++it) {
3583 // Search for Bibtex or Include inset
3584 if ((*it)->LyxCode() == Inset::BIBTEX_CODE) {
3585 vector<pair<string,string> > tmp =
3586 static_cast<InsetBibtex*>(*it)->getKeys(this);
3587 keys.insert(keys.end(), tmp.begin(), tmp.end());
3588 } else if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3589 vector<pair<string,string> > const tmp =
3590 static_cast<InsetInclude*>(*it)->getKeys();
3591 keys.insert(keys.end(), tmp.begin(), tmp.end());
3600 bool Buffer::isDepClean(string const & name) const
3602 DEPCLEAN * item = dep_clean;
3603 while (item && item->master != name)
3605 if (!item) return true;
3610 void Buffer::markDepClean(string const & name)
3613 dep_clean = new DEPCLEAN;
3614 dep_clean->clean = true;
3615 dep_clean->master = name;
3616 dep_clean->next = 0;
3618 DEPCLEAN * item = dep_clean;
3619 while (item && item->master != name)
3624 item = new DEPCLEAN;
3626 item->master = name;
3633 bool Buffer::Dispatch(string const & command)
3635 // Split command string into command and argument
3637 string line = frontStrip(command);
3638 string const arg = strip(frontStrip(split(line, cmd, ' ')));
3640 return Dispatch(lyxaction.LookupFunc(cmd), arg);
3644 bool Buffer::Dispatch(int action, string const & argument)
3646 bool dispatched = true;
3649 Exporter::Export(this, argument, false);
3659 void Buffer::resize()
3661 /// resize the BufferViews!
3667 void Buffer::resizeInsets(BufferView * bv)
3669 /// then remove all LyXText in text-insets
3670 LyXParagraph * par = paragraph;
3671 for(; par; par = par->next) {
3672 par->resizeInsetsLyXText(bv);
3676 void Buffer::ChangeLanguage(Language const * from, Language const * to)
3679 LyXParagraph * par = paragraph;
3681 par->ChangeLanguage(params, from, to);
3687 bool Buffer::isMultiLingual()
3689 LyXParagraph * par = paragraph;
3691 if (par->isMultiLingual(params))
3699 Buffer::inset_iterator::inset_iterator(LyXParagraph * paragraph,
3700 LyXParagraph::size_type pos)
3703 it = par->InsetIterator(pos);
3704 if (it == par->inset_iterator_end()) {
3711 void Buffer::inset_iterator::SetParagraph()
3714 it = par->inset_iterator_begin();
3715 if (it != par->inset_iterator_end())
3720 // We maintain an invariant that whenever par = 0 then it = 0