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>
28 #pragma implementation "buffer.h"
32 #include "bufferlist.h"
34 #include "lyx_gui_misc.h"
35 #include "LyXAction.h"
38 #include "tex-strings.h"
40 #include "bufferview_funcs.h"
41 #include "minibuffer.h"
44 #include "mathed/formulamacro.h"
45 #include "insets/lyxinset.h"
46 #include "insets/inseterror.h"
47 #include "insets/insetlabel.h"
48 #include "insets/insetref.h"
49 #include "insets/inseturl.h"
50 #include "insets/insetinfo.h"
51 #include "insets/insetquotes.h"
52 #include "insets/insetlatexaccent.h"
53 #include "insets/insetbib.h"
54 #include "insets/insetcite.h"
55 #include "insets/insetexternal.h"
56 #include "insets/insetindex.h"
57 #include "insets/insetinclude.h"
58 #include "insets/insettoc.h"
59 #include "insets/insetlof.h"
60 #include "insets/insetlot.h"
61 #include "insets/insetloa.h"
62 #include "insets/insetparent.h"
63 #include "insets/insetspecialchar.h"
64 #include "insets/figinset.h"
65 #include "insets/insettext.h"
66 #include "insets/insetert.h"
67 #include "insets/insetgraphics.h"
68 #include "insets/insetfoot.h"
69 #include "insets/insetmarginal.h"
70 #include "insets/insetminipage.h"
71 #include "insets/insetfloat.h"
72 #include "insets/insetlist.h"
73 #include "insets/insettabular.h"
74 #include "insets/insettheorem.h"
75 #include "support/filetools.h"
76 #include "support/path.h"
82 #include "LaTeXFeatures.h"
83 #include "support/syscall.h"
84 #include "support/lyxlib.h"
85 #include "support/FileInfo.h"
89 #include "lyx_gui_misc.h" // WarnReadonly()
90 #include "frontends/Dialogs.h"
105 // all these externs should eventually be removed.
106 extern BufferList bufferlist;
108 extern void MenuExport(Buffer *, string const &);
109 extern LyXAction lyxaction;
112 static const float LYX_FORMAT = 2.16;
114 extern int tex_code_break_column;
117 Buffer::Buffer(string const & file, bool ronly)
119 lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
121 filepath = OnlyPath(file);
129 if (read_only || (lyxrc.use_tempdir)) {
130 tmppath = CreateBufferTmpDir();
131 } else tmppath.erase();
137 lyxerr[Debug::INFO] << "Buffer::~Buffer()" << endl;
138 // here the buffer should take care that it is
139 // saved properly, before it goes into the void.
141 // make sure that views using this buffer
146 if (!tmppath.empty()) {
147 DestroyBufferTmpDir(tmppath);
150 LyXParagraph * par = paragraph;
151 LyXParagraph * tmppar;
161 string Buffer::getLatexName(bool no_path) const
164 return OnlyFilename(ChangeExtension(MakeLatexName(filename),
167 return ChangeExtension(MakeLatexName(filename),
172 void Buffer::setReadonly(bool flag)
174 if (read_only != flag) {
177 users->owner()->getDialogs()->updateBufferDependent();
180 WarnReadonly(filename);
185 bool Buffer::saveParamsAsDefaults()
187 string fname = AddName(AddPath(user_lyxdir, "templates/"),
189 Buffer defaults = Buffer(fname);
191 // Use the current buffer's parameters as default
192 defaults.params = params;
194 // add an empty paragraph. Is this enough?
195 defaults.paragraph = new LyXParagraph;
197 return defaults.writeFile(defaults.filename, false);
201 /// Update window titles of all users
202 // Should work on a list
203 void Buffer::updateTitles() const
205 if (users) users->owner()->updateWindowTitle();
209 /// Reset autosave timer of all users
210 // Should work on a list
211 void Buffer::resetAutosaveTimers() const
213 if (users) users->owner()->resetAutosaveTimer();
217 void Buffer::fileName(string const & newfile)
219 filename = MakeAbsPath(newfile);
220 filepath = OnlyPath(filename);
221 setReadonly(IsFileWriteable(filename) == 0);
226 // candidate for move to BufferView
227 // (at least some parts in the beginning of the func)
230 // changed to be public and have one parameter
231 // if par = 0 normal behavior
232 // else insert behavior
233 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
234 #define USE_PARSE_FUNCTION 1
235 //#define USE_TABULAR_INSETS 1
236 bool Buffer::readLyXformat2(LyXLex & lex, LyXParagraph * par)
240 char depth = 0; // signed or unsigned?
241 LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
242 LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
243 bool the_end_read = false;
245 LyXParagraph * return_par = 0;
246 LyXFont font(LyXFont::ALL_INHERIT, params.language_info);
247 if (format < 2.16 && params.language == "hebrew")
248 font.setLanguage(default_language);
250 // If we are inserting, we cheat and get a token in advance
251 bool has_token = false;
255 par = new LyXParagraph;
257 users->text->BreakParagraph(users);
258 return_par = users->text->FirstParagraph();
261 // We don't want to adopt the parameters from the
262 // document we insert, so we skip until the text begins:
265 pretoken = lex.GetString();
266 if (pretoken == "\\layout") {
278 pretoken = lex.GetString();
281 // Profiling show this should give a lot: (Asger)
282 string const token = pretoken;
286 the_end_read = parseSingleLyXformat2Token(lex, par, return_par,
295 paragraph = return_par;
302 Buffer::parseSingleLyXformat2Token(LyXLex & lex, LyXParagraph *& par,
303 LyXParagraph *& return_par,
304 string const & token, int & pos,
305 char & depth, LyXFont & font,
306 LyXParagraph::footnote_flag & footnoteflag,
307 LyXParagraph::footnote_kind & footnotekind)
309 bool the_end_read = false;
311 if (token[0] != '\\') {
312 for (string::const_iterator cit = token.begin();
313 cit != token.end(); ++cit) {
314 par->InsertChar(pos, (*cit), font);
317 } else if (token == "\\i") {
318 Inset * inset = new InsetLatexAccent;
319 inset->Read(this, lex);
320 par->InsertInset(pos, inset, font);
322 } else if (token == "\\layout") {
327 par = new LyXParagraph(par);
331 string layoutname = lex.GetString();
332 pair<bool, LyXTextClass::LayoutList::size_type> pp
333 = textclasslist.NumberOfLayout(params.textclass,
336 par->layout = pp.second;
337 } else { // layout not found
338 // use default layout "Standard" (0)
341 // Test whether the layout is obsolete.
342 LyXLayout const & layout =
343 textclasslist.Style(params.textclass,
345 if (!layout.obsoleted_by().empty())
347 textclasslist.NumberOfLayout(params.textclass,
348 layout.obsoleted_by()).second;
349 par->footnoteflag = footnoteflag;
350 par->footnotekind = footnotekind;
352 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
353 if (format < 2.16 && params.language == "hebrew")
354 font.setLanguage(default_language);
356 } else if (token == "\\end_float") {
361 par = new LyXParagraph(par);
363 footnotekind = LyXParagraph::FOOTNOTE;
364 footnoteflag = LyXParagraph::NO_FOOTNOTE;
367 par->layout = LYX_DUMMY_LAYOUT;
368 font = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
369 if (format < 2.16 && params.language == "hebrew")
370 font.setLanguage(default_language);
371 } else if (token == "\\begin_float") {
372 int tmpret = lex.FindToken(string_footnotekinds);
373 if (tmpret == -1) ++tmpret;
374 if (tmpret != LYX_LAYOUT_DEFAULT)
375 footnotekind = static_cast<LyXParagraph::footnote_kind>(tmpret); // bad
376 if (footnotekind == LyXParagraph::FOOTNOTE
377 || footnotekind == LyXParagraph::MARGIN)
378 footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
380 footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
382 } else if (token == "\\begin_float") {
383 // This is the compability reader, unfinished but tested.
386 string tmptok = lex.GetString();
387 //lyxerr << "old float: " << tmptok << endl;
391 if (tmptok == "footnote") {
392 inset = new InsetFoot;
393 } else if (tmptok == "margin") {
394 inset = new InsetMarginal;
395 } else if (tmptok == "fig") {
396 //inset = new InsetFigure;
397 } else if (tmptok == "tab") {
398 //inset = new InsetTable;
399 } else if (tmptok == "alg") {
400 //inset = new InsetAlgorithm;
401 } else if (tmptok == "wide-fig") {
402 //inset = new InsetFigure(true);
403 } else if (tmptok == "wide-tab") {
404 //inset = new InsetTable(true);
407 if (!inset) return false; // no end read yet
409 string old_float = "\ncollapsed true\n";
410 old_float += lex.getLongString("\\end_float");
411 old_float += "\n\\end_inset\n";
412 lyxerr << "float body: " << old_float << endl;
414 istrstream istr(old_float.c_str());
416 nylex.setStream(istr);
418 inset->Read(this, nylex);
419 par->InsertInset(pos, inset, font);
422 } else if (token == "\\begin_deeper") {
424 } else if (token == "\\end_deeper") {
426 lex.printError("\\end_deeper: "
427 "depth is already null");
431 } else if (token == "\\begin_preamble") {
432 params.readPreamble(lex);
433 } else if (token == "\\textclass") {
435 pair<bool, LyXTextClassList::size_type> pp =
436 textclasslist.NumberOfClass(lex.GetString());
438 params.textclass = pp.second;
440 lex.printError("Unknown textclass `$$Token'");
441 params.textclass = 0;
443 if (!textclasslist.Load(params.textclass)) {
444 // if the textclass wasn't loaded properly
445 // we need to either substitute another
446 // or stop loading the file.
447 // I can substitute but I don't see how I can
448 // stop loading... ideas?? ARRae980418
449 WriteAlert(_("Textclass Loading Error!"),
450 string(_("Can't load textclass ")) +
451 textclasslist.NameOfClass(params.textclass),
452 _("-- substituting default"));
453 params.textclass = 0;
455 } else if (token == "\\options") {
457 params.options = lex.GetString();
458 } else if (token == "\\language") {
459 params.readLanguage(lex);
460 } else if (token == "\\fontencoding") {
462 } else if (token == "\\inputencoding") {
464 params.inputenc = lex.GetString();
465 } else if (token == "\\graphics") {
466 params.readGraphicsDriver(lex);
467 } else if (token == "\\fontscheme") {
469 params.fonts = lex.GetString();
470 } else if (token == "\\noindent") {
471 par->noindent = true;
472 } else if (token == "\\fill_top") {
473 par->added_space_top = VSpace(VSpace::VFILL);
474 } else if (token == "\\fill_bottom") {
475 par->added_space_bottom = VSpace(VSpace::VFILL);
476 } else if (token == "\\line_top") {
477 par->line_top = true;
478 } else if (token == "\\line_bottom") {
479 par->line_bottom = true;
480 } else if (token == "\\pagebreak_top") {
481 par->pagebreak_top = true;
482 } else if (token == "\\pagebreak_bottom") {
483 par->pagebreak_bottom = true;
484 } else if (token == "\\start_of_appendix") {
485 par->start_of_appendix = true;
486 } else if (token == "\\paragraph_separation") {
487 int tmpret = lex.FindToken(string_paragraph_separation);
488 if (tmpret == -1) ++tmpret;
489 if (tmpret != LYX_LAYOUT_DEFAULT)
490 params.paragraph_separation =
491 static_cast<BufferParams::PARSEP>(tmpret);
492 } else if (token == "\\defskip") {
494 params.defskip = VSpace(lex.GetString());
495 } else if (token == "\\epsfig") { // obsolete
496 // Indeed it is obsolete, but we HAVE to be backwards
497 // compatible until 0.14, because otherwise all figures
498 // in existing documents are irretrivably lost. (Asger)
499 params.readGraphicsDriver(lex);
500 } else if (token == "\\quotes_language") {
501 int tmpret = lex.FindToken(string_quotes_language);
502 if (tmpret == -1) ++tmpret;
503 if (tmpret != LYX_LAYOUT_DEFAULT) {
504 InsetQuotes::quote_language tmpl =
505 InsetQuotes::EnglishQ;
508 tmpl = InsetQuotes::EnglishQ;
511 tmpl = InsetQuotes::SwedishQ;
514 tmpl = InsetQuotes::GermanQ;
517 tmpl = InsetQuotes::PolishQ;
520 tmpl = InsetQuotes::FrenchQ;
523 tmpl = InsetQuotes::DanishQ;
526 params.quotes_language = tmpl;
528 } else if (token == "\\quotes_times") {
530 switch(lex.GetInteger()) {
532 params.quotes_times = InsetQuotes::SingleQ;
535 params.quotes_times = InsetQuotes::DoubleQ;
538 } else if (token == "\\papersize") {
539 int tmpret = lex.FindToken(string_papersize);
543 params.papersize2 = tmpret;
544 } else if (token == "\\paperpackage") {
545 int tmpret = lex.FindToken(string_paperpackages);
548 params.paperpackage = BufferParams::PACKAGE_NONE;
550 params.paperpackage = tmpret;
551 } else if (token == "\\use_geometry") {
553 params.use_geometry = lex.GetInteger();
554 } else if (token == "\\use_amsmath") {
556 params.use_amsmath = lex.GetInteger();
557 } else if (token == "\\paperorientation") {
558 int tmpret = lex.FindToken(string_orientation);
559 if (tmpret == -1) ++tmpret;
560 if (tmpret != LYX_LAYOUT_DEFAULT)
561 params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
562 } else if (token == "\\paperwidth") {
564 params.paperwidth = lex.GetString();
565 } else if (token == "\\paperheight") {
567 params.paperheight = lex.GetString();
568 } else if (token == "\\leftmargin") {
570 params.leftmargin = lex.GetString();
571 } else if (token == "\\topmargin") {
573 params.topmargin = lex.GetString();
574 } else if (token == "\\rightmargin") {
576 params.rightmargin = lex.GetString();
577 } else if (token == "\\bottommargin") {
579 params.bottommargin = lex.GetString();
580 } else if (token == "\\headheight") {
582 params.headheight = lex.GetString();
583 } else if (token == "\\headsep") {
585 params.headsep = lex.GetString();
586 } else if (token == "\\footskip") {
588 params.footskip = lex.GetString();
589 } else if (token == "\\paperfontsize") {
591 params.fontsize = strip(lex.GetString());
592 } else if (token == "\\papercolumns") {
594 params.columns = lex.GetInteger();
595 } else if (token == "\\papersides") {
597 switch(lex.GetInteger()) {
599 case 1: params.sides = LyXTextClass::OneSide; break;
600 case 2: params.sides = LyXTextClass::TwoSides; break;
602 } else if (token == "\\paperpagestyle") {
604 params.pagestyle = strip(lex.GetString());
605 } else if (token == "\\bullet") {
607 int index = lex.GetInteger();
609 int temp_int = lex.GetInteger();
610 params.user_defined_bullets[index].setFont(temp_int);
611 params.temp_bullets[index].setFont(temp_int);
613 temp_int = lex.GetInteger();
614 params.user_defined_bullets[index].setCharacter(temp_int);
615 params.temp_bullets[index].setCharacter(temp_int);
617 temp_int = lex.GetInteger();
618 params.user_defined_bullets[index].setSize(temp_int);
619 params.temp_bullets[index].setSize(temp_int);
621 string temp_str = lex.GetString();
622 if (temp_str != "\\end_bullet") {
623 // this element isn't really necessary for
624 // parsing but is easier for humans
625 // to understand bullets. Put it back and
626 // set a debug message?
627 lex.printError("\\end_bullet expected, got" + temp_str);
628 //how can I put it back?
630 } else if (token == "\\bulletLaTeX") {
632 int index = lex.GetInteger();
634 string temp_str = lex.GetString(), sum_str;
635 while (temp_str != "\\end_bullet") {
636 // this loop structure is needed when user
637 // enters an empty string since the first
638 // thing returned will be the \\end_bullet
640 // if the LaTeX entry has spaces. Each element
641 // therefore needs to be read in turn
644 temp_str = lex.GetString();
646 params.user_defined_bullets[index].setText(sum_str);
647 params.temp_bullets[index].setText(sum_str);
648 } else if (token == "\\secnumdepth") {
650 params.secnumdepth = lex.GetInteger();
651 } else if (token == "\\tocdepth") {
653 params.tocdepth = lex.GetInteger();
654 } else if (token == "\\spacing") {
656 string tmp = strip(lex.GetString());
657 Spacing::Space tmp_space = Spacing::Default;
659 if (tmp == "single") {
660 tmp_space = Spacing::Single;
661 } else if (tmp == "onehalf") {
662 tmp_space = Spacing::Onehalf;
663 } else if (tmp == "double") {
664 tmp_space = Spacing::Double;
665 } else if (tmp == "other") {
667 tmp_space = Spacing::Other;
668 tmp_val = lex.GetFloat();
670 lex.printError("Unknown spacing token: '$$Token'");
672 // Small hack so that files written with klyx will be
675 par->spacing.set(tmp_space, tmp_val);
677 params.spacing.set(tmp_space, tmp_val);
679 } else if (token == "\\paragraph_spacing") {
681 string tmp = strip(lex.GetString());
682 if (tmp == "single") {
683 par->spacing.set(Spacing::Single);
684 } else if (tmp == "onehalf") {
685 par->spacing.set(Spacing::Onehalf);
686 } else if (tmp == "double") {
687 par->spacing.set(Spacing::Double);
688 } else if (tmp == "other") {
690 par->spacing.set(Spacing::Other,
693 lex.printError("Unknown spacing token: '$$Token'");
695 } else if (token == "\\float_placement") {
697 params.float_placement = lex.GetString();
698 } else if (token == "\\family") {
700 font.setLyXFamily(lex.GetString());
701 } else if (token == "\\series") {
703 font.setLyXSeries(lex.GetString());
704 } else if (token == "\\shape") {
706 font.setLyXShape(lex.GetString());
707 } else if (token == "\\size") {
709 font.setLyXSize(lex.GetString());
710 } else if (token == "\\latex") {
712 string tok = lex.GetString();
713 // This is dirty, but gone with LyX3. (Asger)
714 if (tok == "no_latex")
715 font.setLatex(LyXFont::OFF);
716 else if (tok == "latex")
717 font.setLatex(LyXFont::ON);
718 else if (tok == "default")
719 font.setLatex(LyXFont::INHERIT);
721 lex.printError("Unknown LaTeX font flag "
723 } else if (token == "\\lang") {
725 string tok = lex.GetString();
726 Languages::iterator lit = languages.find(tok);
727 if (lit != languages.end()) {
728 font.setLanguage(&(*lit).second);
730 font.setLanguage(params.language_info);
731 lex.printError("Unknown language `$$Token'");
733 } else if (token == "\\emph") {
735 font.setEmph(font.setLyXMisc(lex.GetString()));
736 } else if (token == "\\bar") {
738 string tok = lex.GetString();
739 // This is dirty, but gone with LyX3. (Asger)
741 font.setUnderbar(LyXFont::ON);
742 else if (tok == "no")
743 font.setUnderbar(LyXFont::OFF);
744 else if (tok == "default")
745 font.setUnderbar(LyXFont::INHERIT);
747 lex.printError("Unknown bar font flag "
749 } else if (token == "\\noun") {
751 font.setNoun(font.setLyXMisc(lex.GetString()));
752 } else if (token == "\\color") {
754 font.setLyXColor(lex.GetString());
755 } else if (token == "\\align") {
756 int tmpret = lex.FindToken(string_align);
757 if (tmpret == -1) ++tmpret;
758 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
760 for (; tmpret > 0; --tmpret)
761 tmpret2 = tmpret2 * 2;
762 par->align = LyXAlignment(tmpret2);
764 } else if (token == "\\added_space_top") {
766 par->added_space_top = VSpace(lex.GetString());
767 } else if (token == "\\added_space_bottom") {
769 par->added_space_bottom = VSpace(lex.GetString());
770 } else if (token == "\\pextra_type") {
772 par->pextra_type = lex.GetInteger();
773 } else if (token == "\\pextra_width") {
775 par->pextra_width = lex.GetString();
776 } else if (token == "\\pextra_widthp") {
778 par->pextra_widthp = lex.GetString();
779 } else if (token == "\\pextra_alignment") {
781 par->pextra_alignment = lex.GetInteger();
782 } else if (token == "\\pextra_hfill") {
784 par->pextra_hfill = lex.GetInteger();
785 } else if (token == "\\pextra_start_minipage") {
787 par->pextra_start_minipage = lex.GetInteger();
788 } else if (token == "\\labelwidthstring") {
790 par->labelwidthstring = lex.GetString();
791 // do not delete this token, it is still needed!
792 } else if (token == "\\end_inset") {
793 // Simply ignore this. The insets do not have
795 // But insets should read it, it is a part of
796 // the inset isn't it? Lgb.
797 } else if (token == "\\begin_inset") {
798 // Should be moved out into its own function/method. (Lgb)
800 string tmptok = lex.GetString();
801 // test the different insets
802 if (tmptok == "Quotes") {
803 Inset * inset = new InsetQuotes;
804 inset->Read(this, lex);
805 par->InsertInset(pos, inset, font);
807 } else if (tmptok == "External") {
808 Inset * inset = new InsetExternal;
809 inset->Read(this, lex);
810 par->InsertInset(pos, inset, font);
812 } else if (tmptok == "FormulaMacro") {
813 Inset * inset = new InsetFormulaMacro;
814 inset->Read(this, lex);
815 par->InsertInset(pos, inset, font);
817 } else if (tmptok == "Formula") {
818 Inset * inset = new InsetFormula;
819 inset->Read(this, lex);
820 par->InsertInset(pos, inset, font);
822 } else if (tmptok == "Figure") {
823 Inset * inset = new InsetFig(100, 100, this);
824 inset->Read(this, lex);
825 par->InsertInset(pos, inset, font);
827 } else if (tmptok == "Info") {
828 Inset * inset = new InsetInfo;
829 inset->Read(this, lex);
830 par->InsertInset(pos, inset, font);
832 } else if (tmptok == "Include") {
833 Inset * inset = new InsetInclude(string(), this);
834 inset->Read(this, lex);
835 par->InsertInset(pos, inset, font);
837 } else if (tmptok == "ERT") {
838 Inset * inset = new InsetERT;
839 inset->Read(this, lex);
840 par->InsertInset(pos, inset, font);
842 } else if (tmptok == "Tabular") {
843 Inset * inset = new InsetTabular(this);
844 inset->Read(this, lex);
845 par->InsertInset(pos, inset, font);
847 } else if (tmptok == "Text") {
848 Inset * inset = new InsetText;
849 inset->Read(this, lex);
850 par->InsertInset(pos, inset, font);
852 } else if (tmptok == "Foot") {
853 Inset * inset = new InsetFoot;
854 inset->Read(this, lex);
855 par->InsertInset(pos, inset, font);
857 } else if (tmptok == "Marginal") {
858 Inset * inset = new InsetMarginal;
859 inset->Read(this, lex);
860 par->InsertInset(pos, inset, font);
862 } else if (tmptok == "Minipage") {
863 Inset * inset = new InsetMinipage;
864 inset->Read(this, lex);
865 par->InsertInset(pos, inset, font);
867 } else if (tmptok == "Float") {
868 Inset * inset = new InsetFloat;
869 inset->Read(this, lex);
870 par->InsertInset(pos, inset, font);
872 } else if (tmptok == "List") {
873 Inset * inset = new InsetList;
874 inset->Read(this, lex);
875 par->InsertInset(pos, inset, font);
877 } else if (tmptok == "Theorem") {
878 Inset * inset = new InsetList;
879 inset->Read(this, lex);
880 par->InsertInset(pos, inset, font);
882 } else if (tmptok == "GRAPHICS") {
883 Inset * inset = new InsetGraphics;
884 //inset->Read(this, lex);
885 par->InsertInset(pos, inset, font);
886 } else if (tmptok == "LatexCommand") {
888 inscmd.Read(this, lex);
890 if (inscmd.getCmdName() == "cite") {
891 inset = new InsetCitation(inscmd.getContents(), inscmd.getOptions());
892 } else if (inscmd.getCmdName() == "bibitem") {
893 lex.printError("Wrong place for bibitem");
894 inset = inscmd.Clone();
895 } else if (inscmd.getCmdName() == "BibTeX") {
896 inset = new InsetBibtex(inscmd.getContents(), inscmd.getOptions(), this);
897 } else if (inscmd.getCmdName() == "index") {
898 inset = new InsetIndex(inscmd.getContents());
899 } else if (inscmd.getCmdName() == "include") {
900 inset = new InsetInclude(inscmd.getContents(), this);
901 } else if (inscmd.getCmdName() == "label") {
902 inset = new InsetLabel(inscmd.getCommand());
903 } else if (inscmd.getCmdName() == "url"
904 || inscmd.getCmdName() == "htmlurl") {
905 inset = new InsetUrl(inscmd.getCommand());
906 } else if (inscmd.getCmdName() == "ref"
907 || inscmd.getCmdName() == "pageref"
908 || inscmd.getCmdName() == "vref"
909 || inscmd.getCmdName() == "vpageref"
910 || inscmd.getCmdName() == "prettyref") {
911 if (!inscmd.getOptions().empty() || !inscmd.getContents().empty()) {
912 inset = new InsetRef(inscmd, this);
914 } else if (inscmd.getCmdName() == "tableofcontents") {
915 inset = new InsetTOC(this);
916 } else if (inscmd.getCmdName() == "listoffigures") {
917 inset = new InsetLOF(this);
918 } else if (inscmd.getCmdName() == "listofalgorithms") {
919 inset = new InsetLOA(this);
920 } else if (inscmd.getCmdName() == "listoftables") {
921 inset = new InsetLOT(this);
922 } else if (inscmd.getCmdName() == "printindex") {
923 inset = new InsetPrintIndex(this);
924 } else if (inscmd.getCmdName() == "lyxparent") {
925 inset = new InsetParent(inscmd.getContents(), this);
929 par->InsertInset(pos, inset, font);
933 } else if (token == "\\SpecialChar") {
934 LyXLayout const & layout =
935 textclasslist.Style(params.textclass,
938 // Insets don't make sense in a free-spacing context! ---Kayvan
939 if (layout.free_spacing) {
943 next_token = lex.GetString();
944 if (next_token == "\\-") {
945 par->InsertChar(pos, '-', font);
946 } else if (next_token == "\\protected_separator"
947 || next_token == "~") {
948 par->InsertChar(pos, ' ', font);
950 lex.printError("Token `$$Token' "
952 "paragraph layout!");
957 Inset * inset = new InsetSpecialChar;
958 inset->Read(this, lex);
959 par->InsertInset(pos, inset, font);
962 } else if (token == "\\newline") {
963 par->InsertChar(pos, LyXParagraph::META_NEWLINE, font);
965 } else if (token == "\\LyXTable") {
966 #ifdef USE_TABULAR_INSETS
967 Inset * inset = new InsetTabular(this);
968 inset->Read(this, lex);
969 par->InsertInset(pos, inset, font);
972 par->table = new LyXTable(lex);
974 } else if (token == "\\hfill") {
975 par->InsertChar(pos, LyXParagraph::META_HFILL, font);
977 } else if (token == "\\protected_separator") { // obsolete
978 // This is a backward compability thingie. (Lgb)
979 // Remove it later some time...introduced with fileformat
981 LyXLayout const & layout =
982 textclasslist.Style(params.textclass,
985 if (layout.free_spacing) {
986 par->InsertChar(pos, ' ', font);
988 Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
989 par->InsertInset(pos, inset, font);
992 } else if (token == "\\bibitem") { // ale970302
994 par->bibkey = new InsetBibKey;
995 par->bibkey->Read(this, lex);
996 }else if (token == "\\backslash") {
997 par->InsertChar(pos, '\\', font);
999 }else if (token == "\\the_end") {
1000 the_end_read = true;
1002 // This should be insurance for the future: (Asger)
1003 lex.printError("Unknown token `$$Token'. "
1004 "Inserting as text.");
1005 for(string::const_iterator cit = token.begin();
1006 cit != token.end(); ++cit) {
1007 par->InsertChar(pos, (*cit), font);
1011 return the_end_read;
1014 bool Buffer::readFile(LyXLex & lex, LyXParagraph * par)
1020 token = lex.GetString();
1021 if (token == "\\lyxformat") { // the first token _must_ be...
1023 format = lex.GetFloat();
1025 if (LYX_FORMAT - format > 0.05) {
1026 printf(_("Warning: need lyxformat %.2f but found %.2f\n"),
1027 LYX_FORMAT, format);
1029 if (format - LYX_FORMAT > 0.05) {
1030 printf(_("ERROR: need lyxformat %.2f but found %.2f\n"),
1031 LYX_FORMAT, format);
1033 bool the_end = readLyXformat2(lex, par);
1034 // Formats >= 2.13 support "\the_end" marker
1041 WriteAlert(_("Warning!"),
1042 _("Reading of document is not complete"),
1043 _("Maybe the document is truncated"));
1044 // We simulate a safe reading anyways to allow
1045 // users to take the chance... (Asger)
1049 WriteAlert(_("ERROR!"),
1050 _("Old LyX file format found. "
1051 "Use LyX 0.10.x to read this!"));
1055 } else { // "\\lyxformat" not found
1056 WriteAlert(_("ERROR!"), _("Not a LyX file!"));
1059 WriteAlert(_("ERROR!"), _("Unable to read file!"));
1065 // Should probably be moved to somewhere else: BufferView? LyXView?
1066 bool Buffer::save() const
1068 // We don't need autosaves in the immediate future. (Asger)
1069 resetAutosaveTimers();
1073 if (lyxrc.make_backup) {
1074 s = fileName() + '~';
1075 if (!lyxrc.backupdir_path.empty())
1076 s = AddName(lyxrc.backupdir_path,
1077 subst(CleanupPath(s),'/','!'));
1079 // Rename is the wrong way of making a backup,
1080 // this is the correct way.
1081 /* truss cp fil fil2:
1082 lstat("LyXVC3.lyx", 0xEFFFF898) Err#2 ENOENT
1083 stat("LyXVC.lyx", 0xEFFFF688) = 0
1084 open("LyXVC.lyx", O_RDONLY) = 3
1085 open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1086 fstat(4, 0xEFFFF508) = 0
1087 fstat(3, 0xEFFFF508) = 0
1088 read(3, " # T h i s f i l e w".., 8192) = 5579
1089 write(4, " # T h i s f i l e w".., 5579) = 5579
1090 read(3, 0xEFFFD4A0, 8192) = 0
1093 chmod("LyXVC3.lyx", 0100644) = 0
1094 lseek(0, 0, SEEK_CUR) = 46440
1098 // Should proabaly have some more error checking here.
1099 // Should be cleaned up in 0.13, at least a bit.
1100 // Doing it this way, also makes the inodes stay the same.
1101 // This is still not a very good solution, in particular we
1102 // might loose the owner of the backup.
1103 FileInfo finfo(fileName());
1104 if (finfo.exist()) {
1105 mode_t fmode = finfo.getMode();
1106 struct utimbuf times = {
1107 finfo.getAccessTime(),
1108 finfo.getModificationTime() };
1110 ifstream ifs(fileName().c_str());
1111 ofstream ofs(s.c_str(), ios::out|ios::trunc);
1116 ::chmod(s.c_str(), fmode);
1118 if (::utime(s.c_str(), ×)) {
1119 lyxerr << "utime error." << endl;
1122 lyxerr << "LyX was not able to make "
1123 "backupcopy. Beware." << endl;
1128 if (writeFile(fileName(), false)) {
1131 // now delete the autosavefile
1132 string a = OnlyPath(fileName());
1134 a += OnlyFilename(fileName());
1136 FileInfo fileinfo(a);
1137 if (fileinfo.exist()) {
1138 if (::remove(a.c_str()) != 0) {
1139 WriteFSAlert(_("Could not delete "
1140 "auto-save file!"), a);
1144 // Saving failed, so backup is not backup
1145 if (lyxrc.make_backup) {
1146 ::rename(s.c_str(), fileName().c_str());
1154 // Returns false if unsuccesful
1155 bool Buffer::writeFile(string const & fname, bool flag) const
1157 // if flag is false writeFile will not create any GUI
1158 // warnings, only cerr.
1159 // Needed for autosave in background or panic save (Matthias 120496)
1161 if (read_only && (fname == filename)) {
1162 // Here we should come with a question if we should
1163 // perform the write anyway.
1165 lyxerr << _("Error! Document is read-only: ")
1168 WriteAlert(_("Error! Document is read-only: "),
1173 FileInfo finfo(fname);
1174 if (finfo.exist() && !finfo.writable()) {
1175 // Here we should come with a question if we should
1176 // try to do the save anyway. (i.e. do a chmod first)
1178 lyxerr << _("Error! Cannot write file: ")
1181 WriteFSAlert(_("Error! Cannot write file: "),
1186 ofstream ofs(fname.c_str());
1189 lyxerr << _("Error! Cannot open file: ")
1192 WriteFSAlert(_("Error! Cannot open file: "),
1196 // The top of the file should not be written by params.
1198 // write out a comment in the top of the file
1199 ofs << '#' << LYX_DOCVERSION
1200 << " created this file. For more info see http://www.lyx.org/\n";
1201 ofs.setf(ios::showpoint|ios::fixed);
1203 ofs << "\\lyxformat " << setw(4) << LYX_FORMAT << "\n";
1205 // now write out the buffer paramters.
1206 params.writeFile(ofs);
1208 char footnoteflag = 0;
1211 // this will write out all the paragraphs
1212 // using recursive descent.
1213 paragraph->writeFile(this, ofs, params, footnoteflag, depth);
1215 // Write marker that shows file is complete
1216 ofs << "\n\\the_end" << endl;
1218 // how to check if close went ok?
1223 void Buffer::writeFileAscii(string const & fname, int linelen)
1225 LyXFont font1, font2;
1227 char c, footnoteflag = 0, depth = 0;
1229 LyXParagraph::size_type i;
1230 int j, h, ltype = 0, ltype_depth = 0,
1231 * clen = 0, actcell = 0, actpos = 0, cell = 0, cells = 0,
1234 bool ref_printed = false;
1236 ofstream ofs(fname.c_str());
1238 WriteFSAlert(_("Error: Cannot write file:"), fname);
1242 string fname1 = TmpFileName();
1243 LyXParagraph * par = paragraph;
1247 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE ||
1249 par->previous->footnoteflag == LyXParagraph::NO_FOOTNOTE){
1251 /* begins a footnote environment ? */
1252 if (footnoteflag != par->footnoteflag) {
1253 footnoteflag = par->footnoteflag;
1255 j = strlen(string_footnotekinds[par->footnotekind])+4;
1256 if (currlinelen + j > linelen)
1259 << string_footnotekinds[par->footnotekind] << "] ";
1264 /* begins or ends a deeper area ?*/
1265 if (depth != par->depth) {
1266 if (par->depth > depth) {
1267 while (par->depth > depth) {
1272 while (par->depth < depth) {
1278 /* First write the layout */
1279 tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1280 if (tmp == "Itemize") {
1282 ltype_depth = depth+1;
1283 } else if (tmp == "Enumerate") {
1285 ltype_depth = depth+1;
1286 } else if (strstr(tmp.c_str(), "ection")) {
1288 ltype_depth = depth+1;
1289 } else if (strstr(tmp.c_str(), "aragraph")) {
1291 ltype_depth = depth+1;
1292 } else if (tmp == "Description") {
1294 ltype_depth = depth+1;
1295 } else if (tmp == "Abstract") {
1298 } else if (tmp == "Bibliography") {
1306 /* maybe some vertical spaces */
1308 /* the labelwidthstring used in lists */
1312 /* some pagebreaks? */
1316 /* what about the alignment */
1318 /* dummy layout, that means a footnote ended */
1319 footnoteflag = LyXParagraph::NO_FOOTNOTE;
1324 //LyXLayout const & layout =
1325 // textclasslist.Style(params.textclass,
1326 // par->GetLayout()); // unused
1327 //bool free_spc = layout.free_spacing; //unused
1330 /* It might be a table */
1334 cells = par->table->columns;
1335 clen = new int [cells];
1336 memset(clen, 0, sizeof(int) * cells);
1338 for (i = 0, j = 0, h = 1; i < par->size(); ++i, ++h) {
1339 c = par->GetChar(i);
1340 if (c == LyXParagraph::META_INSET) {
1341 if ((inset = par->GetInset(i))) {
1343 std::ostringstream ost;
1344 inset->Ascii(this, ost);
1345 h += ost.str().length();
1348 inset->Ascii(this, ost);
1350 char * tmp = ost.str();
1356 } else if (c == LyXParagraph::META_NEWLINE) {
1360 j = (++j) % par->table->NumberOfCellsInRow(actcell);
1368 font1 = LyXFont(LyXFont::ALL_INHERIT, params.language_info);
1370 for (i = 0, actpos = 1; i < par->size(); ++i, ++actpos) {
1371 if (!i && !footnoteflag && !noparbreak){
1373 for(j = 0; j < depth; ++j)
1375 currlinelen = depth * 2;
1377 case 0: /* Standard */
1378 case 4: /* (Sub)Paragraph */
1379 case 5: /* Description */
1381 case 6: /* Abstract */
1382 ofs << "Abstract\n\n";
1384 case 7: /* Bibliography */
1386 ofs << "References\n\n";
1391 ofs << par->labelstring << " ";
1394 if (ltype_depth > depth) {
1395 for(j = ltype_depth - 1; j > depth; --j)
1397 currlinelen += (ltype_depth-depth)*2;
1401 for(j = 0; j < cells; ++j) {
1403 for(h = 0; h < (clen[j] + 1);
1408 for(j = 0; j < depth; ++j)
1410 currlinelen = depth * 2;
1411 if (ltype_depth > depth) {
1412 for(j = ltype_depth;
1415 currlinelen += (ltype_depth-depth)*2;
1421 font2 = par->GetFontSettings(params, i);
1422 if (font1.latex() != font2.latex()) {
1423 if (font2.latex() == LyXFont::OFF)
1430 c = par->GetChar(i);
1434 case LyXParagraph::META_INSET:
1435 if ((inset = par->GetInset(i))) {
1437 inset->Ascii(this, ofs);
1438 currlinelen += (ofs.tellp() - fpos);
1439 actpos += (ofs.tellp() - fpos) - 1;
1442 case LyXParagraph::META_NEWLINE:
1445 if (par->table->NumberOfCellsInRow(actcell) <= cell) {
1446 for(j = actpos; j < clen[cell - 1]; ++j)
1449 for(j = 0; j < depth; ++j)
1451 currlinelen = depth*2;
1452 if (ltype_depth > depth) {
1453 for(j = ltype_depth; j > depth; --j)
1455 currlinelen += (ltype_depth-depth) * 2;
1457 for(j = 0; j < cells; ++j) {
1459 for(h = 0; h < (clen[j] + 1); ++h)
1463 for(j = 0; j < depth; ++j)
1465 currlinelen = depth * 2;
1466 if (ltype_depth > depth) {
1467 for(j = ltype_depth;
1470 currlinelen += (ltype_depth-depth)*2;
1476 j < clen[cell - 1]; ++j)
1482 currlinelen = actpos = 0;
1486 for(j = 0; j < depth; ++j)
1488 currlinelen = depth * 2;
1489 if (ltype_depth > depth) {
1490 for(j = ltype_depth;
1493 currlinelen += (ltype_depth - depth) * 2;
1499 case LyXParagraph::META_HFILL:
1506 if (currlinelen > linelen - 10
1507 && c == ' ' && i + 2 < par->size()) {
1509 for(j = 0; j < depth; ++j)
1511 currlinelen = depth * 2;
1512 if (ltype_depth > depth) {
1513 for(j = ltype_depth;
1516 currlinelen += (ltype_depth-depth)*2;
1518 } else if (c != '\0')
1521 lyxerr.debug() << "writeAsciiFile: NULL char in structure." << endl;
1528 for(j = actpos; j < clen[cell - 1]; ++j)
1531 for(j = 0; j < depth; ++j)
1533 currlinelen = depth * 2;
1534 if (ltype_depth > depth) {
1535 for(j = ltype_depth; j > depth; --j)
1537 currlinelen += (ltype_depth - depth) * 2;
1539 for(j = 0; j < cells; ++j) {
1541 for(h = 0; h < (clen[j] + 1); ++h)
1555 void Buffer::makeLaTeXFile(string const & fname,
1556 string const & original_path,
1557 bool nice, bool only_body)
1559 lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
1561 niceFile = nice; // this will be used by Insetincludes.
1563 tex_code_break_column = lyxrc.ascii_linelen;
1565 LyXTextClass const & tclass =
1566 textclasslist.TextClass(params.textclass);
1568 ofstream ofs(fname.c_str());
1570 WriteFSAlert(_("Error: Cannot open file: "), fname);
1574 // validate the buffer.
1575 lyxerr[Debug::LATEX] << " Validating buffer..." << endl;
1576 LaTeXFeatures features(params, tclass.numLayouts());
1578 lyxerr[Debug::LATEX] << " Buffer validation done." << endl;
1581 // The starting paragraph of the coming rows is the
1582 // first paragraph of the document. (Asger)
1583 texrow.start(paragraph, 0);
1585 if (!only_body && nice) {
1586 ofs << "%% " LYX_DOCVERSION " created this file. "
1587 "For more info, see http://www.lyx.org/.\n"
1588 "%% Do not edit unless you really know what "
1593 lyxerr.debug() << "lyx header finished" << endl;
1594 // There are a few differences between nice LaTeX and usual files:
1595 // usual is \batchmode and has a
1596 // special input@path to allow the including of figures
1597 // with either \input or \includegraphics (what figinsets do).
1598 // batchmode is not set if there is a tex_code_break_column.
1599 // In this case somebody is interested in the generated LaTeX,
1600 // so this is OK. input@path is set when the actual parameter
1601 // original_path is set. This is done for usual tex-file, but not
1602 // for nice-latex-file. (Matthias 250696)
1605 // code for usual, NOT nice-latex-file
1606 ofs << "\\batchmode\n"; // changed
1607 // from \nonstopmode
1610 if (!original_path.empty()) {
1611 ofs << "\\makeatletter\n"
1612 << "\\def\\input@path{{"
1613 << original_path << "/}}\n"
1614 << "\\makeatother\n";
1620 ofs << "\\documentclass";
1622 string options; // the document class options.
1624 if (tokenPos(tclass.opt_fontsize(),
1625 '|', params.fontsize) >= 0) {
1626 // only write if existing in list (and not default)
1627 options += params.fontsize;
1632 if (!params.use_geometry &&
1633 (params.paperpackage == BufferParams::PACKAGE_NONE)) {
1634 switch (params.papersize) {
1635 case BufferParams::PAPER_A4PAPER:
1636 options += "a4paper,";
1638 case BufferParams::PAPER_USLETTER:
1639 options += "letterpaper,";
1641 case BufferParams::PAPER_A5PAPER:
1642 options += "a5paper,";
1644 case BufferParams::PAPER_B5PAPER:
1645 options += "b5paper,";
1647 case BufferParams::PAPER_EXECUTIVEPAPER:
1648 options += "executivepaper,";
1650 case BufferParams::PAPER_LEGALPAPER:
1651 options += "legalpaper,";
1657 if (params.sides != tclass.sides()) {
1658 switch (params.sides) {
1659 case LyXTextClass::OneSide:
1660 options += "oneside,";
1662 case LyXTextClass::TwoSides:
1663 options += "twoside,";
1670 if (params.columns != tclass.columns()) {
1671 if (params.columns == 2)
1672 options += "twocolumn,";
1674 options += "onecolumn,";
1677 if (!params.use_geometry
1678 && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1679 options += "landscape,";
1681 // language should be a parameter to \documentclass
1682 bool use_babel = false;
1683 if (params.language_info->lang() == "hebrew") // This seems necessary
1684 features.UsedLanguages.insert(default_language);
1685 if (params.language != "default" ||
1686 !features.UsedLanguages.empty() ) {
1688 for (LaTeXFeatures::LanguageList::const_iterator cit =
1689 features.UsedLanguages.begin();
1690 cit != features.UsedLanguages.end(); ++cit)
1691 options += (*cit)->lang() + ",";
1692 options += params.language_info->lang() + ',';
1695 // the user-defined options
1696 if (!params.options.empty()) {
1697 options += params.options + ',';
1700 if (!options.empty()){
1701 options = strip(options, ',');
1702 ofs << '[' << options << ']';
1706 << textclasslist.LatexnameOfClass(params.textclass)
1709 // end of \documentclass defs
1711 // font selection must be done before loading fontenc.sty
1712 if (params.fonts != "default") {
1713 ofs << "\\usepackage{" << params.fonts << "}\n";
1716 // this one is not per buffer
1717 if (lyxrc.fontenc != "default") {
1718 ofs << "\\usepackage[" << lyxrc.fontenc
1723 if (params.inputenc == "auto") {
1724 string doc_encoding =
1725 params.language_info->encoding()->LatexName();
1727 // Create a list with all the input encodings used
1729 set<string> encodings;
1730 for (LaTeXFeatures::LanguageList::const_iterator it =
1731 features.UsedLanguages.begin();
1732 it != features.UsedLanguages.end(); ++it)
1733 if ((*it)->encoding()->LatexName() != doc_encoding)
1734 encodings.insert((*it)->encoding()->LatexName());
1736 ofs << "\\usepackage[";
1737 for (set<string>::const_iterator it = encodings.begin();
1738 it != encodings.end(); ++it)
1740 ofs << doc_encoding << "]{inputenc}\n";
1742 } else if (params.inputenc != "default") {
1743 ofs << "\\usepackage[" << params.inputenc
1748 // At the very beginning the text parameters.
1749 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
1750 switch (params.paperpackage) {
1751 case BufferParams::PACKAGE_A4:
1752 ofs << "\\usepackage{a4}\n";
1755 case BufferParams::PACKAGE_A4WIDE:
1756 ofs << "\\usepackage{a4wide}\n";
1759 case BufferParams::PACKAGE_WIDEMARGINSA4:
1760 ofs << "\\usepackage[widemargins]{a4}\n";
1765 if (params.use_geometry) {
1766 ofs << "\\usepackage{geometry}\n";
1768 ofs << "\\geometry{verbose";
1769 if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
1770 ofs << ",landscape";
1771 switch (params.papersize2) {
1772 case BufferParams::VM_PAPER_CUSTOM:
1773 if (!params.paperwidth.empty())
1774 ofs << ",paperwidth="
1775 << params.paperwidth;
1776 if (!params.paperheight.empty())
1777 ofs << ",paperheight="
1778 << params.paperheight;
1780 case BufferParams::VM_PAPER_USLETTER:
1781 ofs << ",letterpaper";
1783 case BufferParams::VM_PAPER_USLEGAL:
1784 ofs << ",legalpaper";
1786 case BufferParams::VM_PAPER_USEXECUTIVE:
1787 ofs << ",executivepaper";
1789 case BufferParams::VM_PAPER_A3:
1792 case BufferParams::VM_PAPER_A4:
1795 case BufferParams::VM_PAPER_A5:
1798 case BufferParams::VM_PAPER_B3:
1801 case BufferParams::VM_PAPER_B4:
1804 case BufferParams::VM_PAPER_B5:
1808 // default papersize ie BufferParams::VM_PAPER_DEFAULT
1809 switch (lyxrc.default_papersize) {
1810 case BufferParams::PAPER_DEFAULT: // keep compiler happy
1811 case BufferParams::PAPER_USLETTER:
1812 ofs << ",letterpaper";
1814 case BufferParams::PAPER_LEGALPAPER:
1815 ofs << ",legalpaper";
1817 case BufferParams::PAPER_EXECUTIVEPAPER:
1818 ofs << ",executivepaper";
1820 case BufferParams::PAPER_A3PAPER:
1823 case BufferParams::PAPER_A4PAPER:
1826 case BufferParams::PAPER_A5PAPER:
1829 case BufferParams::PAPER_B5PAPER:
1834 if (!params.topmargin.empty())
1835 ofs << ",tmargin=" << params.topmargin;
1836 if (!params.bottommargin.empty())
1837 ofs << ",bmargin=" << params.bottommargin;
1838 if (!params.leftmargin.empty())
1839 ofs << ",lmargin=" << params.leftmargin;
1840 if (!params.rightmargin.empty())
1841 ofs << ",rmargin=" << params.rightmargin;
1842 if (!params.headheight.empty())
1843 ofs << ",headheight=" << params.headheight;
1844 if (!params.headsep.empty())
1845 ofs << ",headsep=" << params.headsep;
1846 if (!params.footskip.empty())
1847 ofs << ",footskip=" << params.footskip;
1851 if (params.use_amsmath
1852 && !tclass.provides(LyXTextClass::amsmath)) {
1853 ofs << "\\usepackage{amsmath}\n";
1857 if (tokenPos(tclass.opt_pagestyle(),
1858 '|', params.pagestyle) >= 0) {
1859 if (params.pagestyle == "fancy") {
1860 ofs << "\\usepackage{fancyhdr}\n";
1863 ofs << "\\pagestyle{" << params.pagestyle << "}\n";
1867 // We try to load babel late, in case it interferes
1868 // with other packages.
1870 ofs << lyxrc.language_package << endl;
1874 if (params.secnumdepth != tclass.secnumdepth()) {
1875 ofs << "\\setcounter{secnumdepth}{"
1876 << params.secnumdepth
1880 if (params.tocdepth != tclass.tocdepth()) {
1881 ofs << "\\setcounter{tocdepth}{"
1887 if (params.paragraph_separation) {
1888 switch (params.defskip.kind()) {
1889 case VSpace::SMALLSKIP:
1890 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
1892 case VSpace::MEDSKIP:
1893 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1895 case VSpace::BIGSKIP:
1896 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
1898 case VSpace::LENGTH:
1899 ofs << "\\setlength\\parskip{"
1900 << params.defskip.length().asLatexString()
1903 default: // should never happen // Then delete it.
1904 ofs << "\\setlength\\parskip{\\medskipamount}\n";
1909 ofs << "\\setlength\\parindent{0pt}\n";
1913 // Now insert the LyX specific LaTeX commands...
1915 // The optional packages;
1916 string preamble(features.getPackages());
1918 // this might be useful...
1919 preamble += "\n\\makeatletter\n";
1921 // Some macros LyX will need
1922 string tmppreamble(features.getMacros());
1924 if (!tmppreamble.empty()) {
1925 preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1926 "LyX specific LaTeX commands.\n"
1927 + tmppreamble + '\n';
1930 // the text class specific preamble
1931 tmppreamble = features.getTClassPreamble();
1932 if (!tmppreamble.empty()) {
1933 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1934 "Textclass specific LaTeX commands.\n"
1935 + tmppreamble + '\n';
1938 /* the user-defined preamble */
1939 if (!params.preamble.empty()) {
1940 preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1941 "User specified LaTeX commands.\n"
1942 + params.preamble + '\n';
1945 preamble += "\\makeatother\n";
1947 // Itemize bullet settings need to be last in case the user
1948 // defines their own bullets that use a package included
1949 // in the user-defined preamble -- ARRae
1950 // Actually it has to be done much later than that
1951 // since some packages like frenchb make modifications
1952 // at \begin{document} time -- JMarc
1954 for (int i = 0; i < 4; ++i) {
1955 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
1956 if (bullets_def.empty())
1957 bullets_def="\\AtBeginDocument{\n";
1958 bullets_def += " \\renewcommand{\\labelitemi";
1960 // `i' is one less than the item to modify
1967 bullets_def += "ii";
1973 bullets_def += "}{" +
1974 params.user_defined_bullets[i].getText()
1979 if (!bullets_def.empty())
1980 preamble += bullets_def + "}\n\n";
1982 for (int j = countChar(preamble, '\n'); j-- ;) {
1989 ofs << "\\begin{document}\n";
1992 lyxerr.debug() << "preamble finished, now the body." << endl;
1993 if (!lyxrc.language_auto_begin && params.language != "default") {
1994 ofs << subst(lyxrc.language_command_begin, "$$lang",
2000 latexParagraphs(ofs, paragraph, 0, texrow);
2002 // add this just in case after all the paragraphs
2006 if (!lyxrc.language_auto_end && params.language != "default") {
2007 ofs << subst(lyxrc.language_command_end, "$$lang",
2014 ofs << "\\end{document}\n";
2017 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2019 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2023 // Just to be sure. (Asger)
2026 // tex_code_break_column's value is used to decide
2027 // if we are in batchmode or not (within mathed_write()
2028 // in math_write.C) so we must set it to a non-zero
2029 // value when we leave otherwise we save incorrect .lyx files.
2030 tex_code_break_column = lyxrc.ascii_linelen;
2034 lyxerr << "File was not closed properly." << endl;
2037 lyxerr.debug() << "Finished making latex file." << endl;
2042 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2044 void Buffer::latexParagraphs(ostream & ofs, LyXParagraph * par,
2045 LyXParagraph * endpar, TexRow & texrow) const
2047 bool was_title = false;
2048 bool already_title = false;
2050 std::ostringstream ftnote;
2052 char * tmpholder = 0;
2058 while (par != endpar) {
2059 #ifndef HAVE_SSTREAM
2062 ftnote << tmpholder;
2063 delete [] tmpholder;
2068 lyxerr[Debug::LATEX] << "Error in latexParagraphs."
2070 LyXLayout const & layout =
2071 textclasslist.Style(params.textclass,
2074 if (layout.intitle) {
2075 if (already_title) {
2076 lyxerr <<"Error in latexParagraphs: You"
2077 " should not mix title layouts"
2078 " with normal ones." << endl;
2081 } else if (was_title && !already_title) {
2082 ofs << "\\maketitle\n";
2084 already_title = true;
2087 // We are at depth 0 so we can just use
2088 // ordinary \footnote{} generation
2089 // flag this with ftcount
2091 if (layout.isEnvironment()
2092 || par->pextra_type != LyXParagraph::PEXTRA_NONE) {
2093 par = par->TeXEnvironment(this, params, ofs, texrow,
2094 ftnote, ft_texrow, ftcount);
2096 par = par->TeXOnePar(this, params, ofs, texrow, false,
2097 ftnote, ft_texrow, ftcount);
2100 // Write out what we've generated...
2103 ofs << "\\addtocounter{footnote}{-"
2107 ofs << ftnote.str();
2108 texrow += ft_texrow;
2110 // The extra .c_str() is needed when we use
2111 // lyxstring instead of the STL string class.
2112 ftnote.str(string().c_str());
2114 delete [] ftnote.str();
2119 #ifndef HAVE_SSTREAM
2121 // I hate strstreams
2122 tmpholder = ftnote.str();
2126 #ifndef HAVE_SSTREAM
2127 delete [] tmpholder;
2129 // It might be that we only have a title in this document
2130 if (was_title && !already_title) {
2131 ofs << "\\maketitle\n";
2137 bool Buffer::isLatex() const
2139 return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2143 bool Buffer::isLinuxDoc() const
2145 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2149 bool Buffer::isLiterate() const
2151 return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2155 bool Buffer::isDocBook() const
2157 return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2161 bool Buffer::isSGML() const
2163 return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2164 textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2168 void Buffer::sgmlOpenTag(ostream & os, int depth,
2169 string const & latexname) const
2171 os << string(depth, ' ') << "<" << latexname << ">\n";
2175 void Buffer::sgmlCloseTag(ostream & os, int depth,
2176 string const & latexname) const
2178 os << string(depth, ' ') << "</" << latexname << ">\n";
2182 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2184 LyXParagraph * par = paragraph;
2186 niceFile = nice; // this will be used by Insetincludes.
2188 string top_element = textclasslist.LatexnameOfClass(params.textclass);
2189 string environment_stack[10];
2192 int depth = 0; // paragraph depth
2194 ofstream ofs(fname.c_str());
2197 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2201 LyXTextClass const & tclass =
2202 textclasslist.TextClass(params.textclass);
2204 LaTeXFeatures features(params, tclass.numLayouts());
2208 tex_code_break_column = lyxrc.ascii_linelen;
2210 //tex_code_break_column = 0;
2215 string sgml_includedfiles=features.getIncludedFiles();
2217 if (params.preamble.empty() && sgml_includedfiles.empty()) {
2218 ofs << "<!doctype linuxdoc system>\n\n";
2220 ofs << "<!doctype linuxdoc system [ "
2221 << params.preamble << sgml_includedfiles << " \n]>\n\n";
2224 if(params.options.empty())
2225 sgmlOpenTag(ofs, 0, top_element);
2227 string top = top_element;
2229 top += params.options;
2230 sgmlOpenTag(ofs, 0, top);
2234 ofs << "<!-- " << LYX_DOCVERSION
2235 << " created this file. For more info see http://www.lyx.org/"
2239 int desc_on = 0; // description mode
2240 LyXLayout const & style =
2241 textclasslist.Style(params.textclass,
2244 // treat <toc> as a special case for compatibility with old code
2245 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2246 Inset * inset = par->GetInset(0);
2247 Inset::Code lyx_code = inset->LyxCode();
2248 if (lyx_code == Inset::TOC_CODE){
2249 string temp = "toc";
2250 sgmlOpenTag(ofs, depth, temp);
2253 linuxDocHandleFootnote(ofs, par, depth);
2258 // environment tag closing
2259 for( ; depth > par->depth; --depth) {
2260 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2261 environment_stack[depth].erase();
2264 // write opening SGML tags
2265 switch(style.latextype) {
2266 case LATEX_PARAGRAPH:
2267 if(depth == par->depth
2268 && !environment_stack[depth].empty()) {
2269 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2270 environment_stack[depth].erase();
2276 sgmlOpenTag(ofs, depth, style.latexname());
2281 LinuxDocError(par, 0,
2282 _("Error : Wrong depth for"
2283 " LatexType Command.\n"));
2285 if (!environment_stack[depth].empty()){
2286 sgmlCloseTag(ofs, depth,
2287 environment_stack[depth]);
2291 environment_stack[depth].erase();
2292 sgmlOpenTag(ofs, depth, style.latexname());
2295 case LATEX_ENVIRONMENT:
2296 case LATEX_ITEM_ENVIRONMENT:
2297 if(depth == par->depth
2298 && environment_stack[depth] != style.latexname()
2299 && !environment_stack[depth].empty()) {
2301 sgmlCloseTag(ofs, depth,
2302 environment_stack[depth]);
2303 environment_stack[depth].erase();
2305 if (depth < par->depth) {
2307 environment_stack[depth].erase();
2309 if (environment_stack[depth] != style.latexname()) {
2312 sgmlOpenTag(ofs, depth, temp);
2314 environment_stack[depth] = style.latexname();
2315 sgmlOpenTag(ofs, depth,
2316 environment_stack[depth]);
2318 if(style.latextype == LATEX_ENVIRONMENT) break;
2320 desc_on = (style.labeltype == LABEL_MANUAL);
2327 sgmlOpenTag(ofs, depth + 1, item_name);
2330 sgmlOpenTag(ofs, depth, style.latexname());
2335 SimpleLinuxDocOnePar(ofs, par, desc_on, depth);
2338 linuxDocHandleFootnote(ofs, par, depth);
2340 while(par && par->IsDummy());
2343 // write closing SGML tags
2344 switch(style.latextype) {
2346 case LATEX_ENVIRONMENT:
2347 case LATEX_ITEM_ENVIRONMENT:
2350 sgmlCloseTag(ofs, depth, style.latexname());
2356 for(; depth > 0; --depth)
2357 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2359 if(!environment_stack[depth].empty())
2360 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2364 sgmlCloseTag(ofs, 0, top_element);
2368 // How to check for successful close
2372 void Buffer::linuxDocHandleFootnote(ostream & os, LyXParagraph * & par,
2375 string tag = "footnote";
2377 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2378 sgmlOpenTag(os, depth + 1, tag);
2379 SimpleLinuxDocOnePar(os, par, 0, depth + 1);
2380 sgmlCloseTag(os, depth + 1, tag);
2386 void Buffer::DocBookHandleCaption(ostream & os, string & inner_tag,
2387 int const depth, int desc_on,
2388 LyXParagraph * & par)
2390 LyXParagraph * tpar = par;
2391 while (tpar && (tpar->footnoteflag != LyXParagraph::NO_FOOTNOTE) &&
2392 (tpar->layout != textclasslist.NumberOfLayout(params.textclass,
2396 tpar->layout == textclasslist.NumberOfLayout(params.textclass,
2397 "Caption").second) {
2398 sgmlOpenTag(os, depth + 1, inner_tag);
2400 SimpleDocBookOnePar(os, extra_par, tpar,
2401 desc_on, depth + 2);
2402 sgmlCloseTag(os, depth+1, inner_tag);
2403 if(!extra_par.empty())
2409 void Buffer::DocBookHandleFootnote(ostream & os, LyXParagraph * & par,
2412 string tag, inner_tag;
2413 string tmp_par, extra_par;
2414 bool inner_span = false;
2417 // Someone should give this enum a proper name (Lgb)
2425 SOME_ENUM last = NO_ONE;
2426 SOME_ENUM present = FOOTNOTE_LIKE;
2428 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2429 if(last == present) {
2431 if(!tmp_par.empty()) {
2434 sgmlCloseTag(os, depth + 1, inner_tag);
2435 sgmlOpenTag(os, depth + 1, inner_tag);
2442 if(!inner_tag.empty()) sgmlCloseTag(os, depth + 1,
2444 if(!extra_par.empty()) os << extra_par;
2445 if(!tag.empty()) sgmlCloseTag(os, depth, tag);
2448 switch (par->footnotekind) {
2449 case LyXParagraph::FOOTNOTE:
2450 case LyXParagraph::ALGORITHM:
2453 present = FOOTNOTE_LIKE;
2456 case LyXParagraph::MARGIN:
2459 present = MARGIN_LIKE;
2462 case LyXParagraph::FIG:
2463 case LyXParagraph::WIDE_FIG:
2465 inner_tag = "title";
2469 case LyXParagraph::TAB:
2470 case LyXParagraph::WIDE_TAB:
2472 inner_tag = "title";
2477 sgmlOpenTag(os, depth, tag);
2478 if ((present == TAB_LIKE) || (present == FIG_LIKE)) {
2479 DocBookHandleCaption(os, inner_tag, depth,
2483 sgmlOpenTag(os, depth + 1, inner_tag);
2486 // ignore all caption here, we processed them above!!!
2487 if (par->layout != textclasslist
2488 .NumberOfLayout(params.textclass,
2489 "Caption").second) {
2491 std::ostringstream ost;
2495 SimpleDocBookOnePar(ost, extra_par, par,
2496 desc_on, depth + 2);
2498 tmp_par += ost.str().c_str();
2501 char * ctmp = ost.str();
2506 tmp_par = frontStrip(strip(tmp_par));
2512 if(!inner_tag.empty()) sgmlCloseTag(os, depth + 1, inner_tag);
2513 if(!extra_par.empty()) os << extra_par;
2514 if(!tag.empty()) sgmlCloseTag(os, depth, tag);
2518 // push a tag in a style stack
2519 void Buffer::push_tag(ostream & os, char const * tag,
2520 int & pos, char stack[5][3])
2522 // pop all previous tags
2523 for (int j = pos; j >= 0; --j)
2524 os << "</" << stack[j] << ">";
2527 sprintf(stack[++pos], "%s", tag);
2530 for (int i = 0; i <= pos; ++i)
2531 os << "<" << stack[i] << ">";
2535 void Buffer::pop_tag(ostream & os, char const * tag,
2536 int & pos, char stack[5][3])
2540 // pop all tags till specified one
2541 for (j = pos; (j >= 0) && (strcmp(stack[j], tag)); --j)
2542 os << "</" << stack[j] << ">";
2545 os << "</" << tag << ">";
2547 // push all tags, but the specified one
2548 for (j = j + 1; j <= pos; ++j) {
2549 os << "<" << stack[j] << ">";
2550 strcpy(stack[j-1], stack[j]);
2556 // Handle internal paragraph parsing -- layout already processed.
2558 // checks, if newcol chars should be put into this line
2559 // writes newline, if necessary.
2561 void linux_doc_line_break(ostream & os, unsigned int & colcount,
2562 const unsigned int newcol)
2565 if (colcount > lyxrc.ascii_linelen) {
2567 colcount = newcol; // assume write after this call
2572 void Buffer::SimpleLinuxDocOnePar(ostream & os, LyXParagraph * par,
2573 int desc_on, int const /*depth*/)
2575 LyXFont font1, font2;
2578 LyXParagraph::size_type main_body;
2580 LyXLayout const & style = textclasslist.Style(params.textclass,
2583 char family_type = 0; // family font flag
2584 bool is_bold = false; // series font flag
2585 char shape_type = 0; // shape font flag
2586 bool is_em = false; // emphasis (italic) font flag
2588 int stack_num = -1; // style stack position
2589 // Can this be rewritten to use a std::stack, please. (Lgb)
2590 char stack[5][3]; // style stack
2591 unsigned int char_line_count = 5; // Heuristic choice ;-)
2593 if (style.labeltype != LABEL_MANUAL)
2596 main_body = par->BeginningOfMainBody();
2598 // gets paragraph main font
2600 font1 = style.labelfont;
2605 // parsing main loop
2606 for (LyXParagraph::size_type i = 0;
2607 i < par->size(); ++i) {
2610 if (i == main_body && !par->IsDummy()) {
2615 font2 = par->getFont(params, i);
2617 if (font1.family() != font2.family()) {
2618 switch(family_type) {
2620 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2621 push_tag(os, "tt", stack_num, stack);
2624 else if (font2.family() == LyXFont::SANS_FAMILY) {
2625 push_tag(os, "sf", stack_num, stack);
2630 pop_tag(os, "tt", stack_num, stack);
2631 if (font2.family() == LyXFont::SANS_FAMILY) {
2632 push_tag(os, "sf", stack_num, stack);
2639 pop_tag(os, "sf", stack_num, stack);
2640 if (font2.family() == LyXFont::TYPEWRITER_FAMILY) {
2641 push_tag(os, "tt", stack_num, stack);
2650 if (font1.series() != font2.series()) {
2651 if (font2.series() == LyXFont::BOLD_SERIES) {
2652 push_tag(os, "bf", stack_num, stack);
2654 } else if (is_bold) {
2655 pop_tag(os, "bf", stack_num, stack);
2660 // handle italic and slanted fonts
2661 if (font1.shape() != font2.shape()) {
2662 switch(shape_type) {
2664 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2665 push_tag(os, "it", stack_num, stack);
2667 } else if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2668 push_tag(os, "sl", stack_num, stack);
2673 pop_tag(os, "it", stack_num, stack);
2674 if (font2.shape() == LyXFont::SLANTED_SHAPE) {
2675 push_tag(os, "sl", stack_num, stack);
2682 pop_tag(os, "sl", stack_num, stack);
2683 if (font2.shape() == LyXFont::ITALIC_SHAPE) {
2684 push_tag(os, "it", stack_num, stack);
2692 if (font1.emph() != font2.emph()) {
2693 if (font2.emph() == LyXFont::ON) {
2694 push_tag(os, "em", stack_num, stack);
2697 pop_tag(os, "em", stack_num, stack);
2702 c = par->GetChar(i);
2704 if (c == LyXParagraph::META_INSET) {
2705 inset = par->GetInset(i);
2706 inset->Linuxdoc(this, os);
2709 if (font2.latex() == LyXFont::ON) {
2710 // "TeX"-Mode on == > SGML-Mode on.
2712 os << c; // see LaTeX-Generation...
2716 if (par->linuxDocConvertChar(c, sgml_string)
2717 && !style.free_spacing) { // in freespacing
2719 // non-breaking characters
2723 linux_doc_line_break(os, char_line_count, 6);
2727 linux_doc_line_break(os, char_line_count, 1);
2732 char_line_count += sgml_string.length();
2738 // needed if there is an optional argument but no contents
2739 if (main_body > 0 && main_body == par->size()) {
2743 // pop all defined Styles
2744 for (j = stack_num; j >= 0; --j) {
2745 linux_doc_line_break(os,
2747 3 + strlen(stack[j]));
2748 os << "</" << stack[j] << ">";
2751 // resets description flag correctly
2754 // <tag> not closed...
2755 linux_doc_line_break(os, char_line_count, 6);
2759 // fprintf(file, "</p>");
2765 // Print an error message.
2766 void Buffer::LinuxDocError(LyXParagraph * par, int pos,
2767 char const * message)
2769 // insert an error marker in text
2770 InsetError * new_inset = new InsetError(message);
2771 par->InsertInset(pos, new_inset);
2774 // This constant defines the maximum number of
2775 // environment layouts that can be nesteded.
2776 // The same applies for command layouts.
2777 // These values should be more than enough.
2778 // José Matos (1999/07/22)
2780 enum { MAX_NEST_LEVEL = 25};
2782 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
2784 LyXParagraph * par = paragraph;
2786 niceFile = nice; // this will be used by Insetincludes.
2788 string top_element= textclasslist.LatexnameOfClass(params.textclass);
2789 // Please use a real stack.
2790 string environment_stack[MAX_NEST_LEVEL];
2791 string environment_inner[MAX_NEST_LEVEL];
2792 // Please use a real stack.
2793 string command_stack[MAX_NEST_LEVEL];
2794 bool command_flag= false;
2795 int command_depth= 0, command_base= 0, cmd_depth= 0;
2797 string item_name, command_name;
2798 string c_depth, c_params, tmps;
2800 int depth = 0; // paragraph depth
2801 LyXTextClass const & tclass =
2802 textclasslist.TextClass(params.textclass);
2804 LaTeXFeatures features(params, tclass.numLayouts());
2808 tex_code_break_column = lyxrc.ascii_linelen;
2810 //tex_code_break_column = 0;
2812 ofstream ofs(fname.c_str());
2814 WriteAlert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2821 string sgml_includedfiles=features.getIncludedFiles();
2823 ofs << "<!doctype " << top_element
2824 << " public \"-//OASIS//DTD DocBook V3.1//EN\"";
2826 if (params.preamble.empty() && sgml_includedfiles.empty())
2829 ofs << "\n [ " << params.preamble
2830 << sgml_includedfiles << " \n]>\n\n";
2832 if(params.options.empty())
2833 sgmlOpenTag(ofs, 0, top_element);
2835 string top = top_element;
2837 top += params.options;
2838 sgmlOpenTag(ofs, 0, top);
2842 ofs << "<!-- DocBook file was created by " << LYX_DOCVERSION
2843 << "\n See http://www.lyx.org/ for more information -->\n";
2846 int desc_on = 0; // description mode
2847 LyXLayout const & style =
2848 textclasslist.Style(params.textclass,
2851 // environment tag closing
2852 for( ; depth > par->depth; --depth) {
2853 if(environment_inner[depth] != "!-- --") {
2854 item_name= "listitem";
2855 sgmlCloseTag(ofs, command_depth + depth,
2857 if( environment_inner[depth] == "varlistentry")
2858 sgmlCloseTag(ofs, depth+command_depth,
2859 environment_inner[depth]);
2861 sgmlCloseTag(ofs, depth + command_depth,
2862 environment_stack[depth]);
2863 environment_stack[depth].erase();
2864 environment_inner[depth].erase();
2867 if(depth == par->depth
2868 && environment_stack[depth] != style.latexname()
2869 && !environment_stack[depth].empty()) {
2870 if(environment_inner[depth] != "!-- --") {
2871 item_name= "listitem";
2872 sgmlCloseTag(ofs, command_depth+depth,
2874 if( environment_inner[depth] == "varlistentry")
2876 depth + command_depth,
2877 environment_inner[depth]);
2880 sgmlCloseTag(ofs, depth + command_depth,
2881 environment_stack[depth]);
2883 environment_stack[depth].erase();
2884 environment_inner[depth].erase();
2887 // Write opening SGML tags.
2888 switch(style.latextype) {
2889 case LATEX_PARAGRAPH:
2890 if(style.latexname() != "dummy")
2891 sgmlOpenTag(ofs, depth+command_depth,
2897 LinuxDocError(par, 0,
2898 _("Error : Wrong depth for "
2899 "LatexType Command.\n"));
2901 command_name = style.latexname();
2903 tmps = style.latexparam();
2904 c_params = split(tmps, c_depth,'|');
2906 cmd_depth= atoi(c_depth.c_str());
2909 if(cmd_depth<command_base) {
2910 for(int j = command_depth;
2911 j >= command_base; --j)
2912 if(!command_stack[j].empty())
2913 sgmlCloseTag(ofs, j, command_stack[j]);
2914 command_depth= command_base= cmd_depth;
2915 } else if(cmd_depth <= command_depth) {
2916 for(int j = command_depth;
2917 j >= cmd_depth; --j)
2919 if(!command_stack[j].empty())
2920 sgmlCloseTag(ofs, j, command_stack[j]);
2921 command_depth= cmd_depth;
2923 command_depth= cmd_depth;
2925 command_depth = command_base = cmd_depth;
2926 command_flag = true;
2928 command_stack[command_depth]= command_name;
2930 // treat label as a special case for
2931 // more WYSIWYM handling.
2932 if (par->GetChar(0) == LyXParagraph::META_INSET) {
2933 Inset * inset = par->GetInset(0);
2934 Inset::Code lyx_code = inset->LyxCode();
2935 if (lyx_code == Inset::LABEL_CODE){
2936 command_name += " id=\"";
2937 command_name += (static_cast<InsetCommand *>(inset))->getContents();
2938 command_name += "\"";
2943 sgmlOpenTag(ofs, depth + command_depth, command_name);
2944 item_name = "title";
2945 sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
2948 case LATEX_ENVIRONMENT:
2949 case LATEX_ITEM_ENVIRONMENT:
2950 if (depth < par->depth) {
2952 environment_stack[depth].erase();
2955 if (environment_stack[depth] != style.latexname()) {
2956 environment_stack[depth] = style.latexname();
2957 environment_inner[depth] = "!-- --";
2958 sgmlOpenTag(ofs, depth + command_depth,
2959 environment_stack[depth]);
2961 if(environment_inner[depth] != "!-- --") {
2962 item_name= "listitem";
2964 command_depth + depth,
2966 if (environment_inner[depth] == "varlistentry")
2968 depth + command_depth,
2969 environment_inner[depth]);
2973 if(style.latextype == LATEX_ENVIRONMENT) {
2974 if(!style.latexparam().empty())
2975 sgmlOpenTag(ofs, depth + command_depth,
2976 style.latexparam());
2980 desc_on = (style.labeltype == LABEL_MANUAL);
2983 environment_inner[depth]= "varlistentry";
2985 environment_inner[depth]= "listitem";
2987 sgmlOpenTag(ofs, depth + 1 + command_depth,
2988 environment_inner[depth]);
2992 sgmlOpenTag(ofs, depth + 1 + command_depth,
2996 sgmlOpenTag(ofs, depth + 1 + command_depth,
3001 sgmlOpenTag(ofs, depth + command_depth,
3008 SimpleDocBookOnePar(ofs, extra_par, par, desc_on,
3009 depth + 1 + command_depth);
3011 DocBookHandleFootnote(ofs, par,
3012 depth + 1 + command_depth);
3014 while(par && par->IsDummy());
3017 // write closing SGML tags
3018 switch(style.latextype) {
3021 sgmlCloseTag(ofs, depth + command_depth, end_tag);
3023 case LATEX_ENVIRONMENT:
3024 if(!style.latexparam().empty())
3025 sgmlCloseTag(ofs, depth + command_depth,
3026 style.latexparam());
3028 case LATEX_ITEM_ENVIRONMENT:
3029 if(desc_on == 1) break;
3031 sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
3033 case LATEX_PARAGRAPH:
3034 if(style.latexname() != "dummy")
3035 sgmlCloseTag(ofs, depth + command_depth,
3039 sgmlCloseTag(ofs, depth + command_depth,
3046 for(; depth >= 0; --depth) {
3047 if(!environment_stack[depth].empty()) {
3048 if(environment_inner[depth] != "!-- --") {
3049 item_name= "listitem";
3050 sgmlCloseTag(ofs, command_depth + depth,
3052 if( environment_inner[depth] == "varlistentry")
3053 sgmlCloseTag(ofs, depth + command_depth,
3054 environment_inner[depth]);
3057 sgmlCloseTag(ofs, depth + command_depth,
3058 environment_stack[depth]);
3062 for(int j = command_depth; j >= command_base; --j)
3063 if(!command_stack[j].empty())
3064 sgmlCloseTag(ofs, j, command_stack[j]);
3068 sgmlCloseTag(ofs, 0, top_element);
3072 // How to check for successful close
3076 void Buffer::SimpleDocBookOnePar(ostream & os, string & extra,
3077 LyXParagraph * par, int & desc_on,
3082 par->SimpleDocBookOneTablePar(this,
3083 os, extra, desc_on, depth);
3088 bool emph_flag = false;
3090 LyXLayout const & style = textclasslist.Style(params.textclass,
3093 LyXParagraph::size_type main_body;
3094 if (style.labeltype != LABEL_MANUAL)
3097 main_body = par->BeginningOfMainBody();
3099 // gets paragraph main font
3100 LyXFont font1 = main_body > 0 ? style.labelfont : style.font;
3102 int char_line_count = depth;
3103 if(!style.free_spacing)
3104 for (int j = 0; j < depth; ++j)
3107 // parsing main loop
3108 for (LyXParagraph::size_type i = 0;
3109 i < par->size(); ++i) {
3110 LyXFont font2 = par->getFont(params, i);
3112 // handle <emphasis> tag
3113 if (font1.emph() != font2.emph() && i) {
3114 if (font2.emph() == LyXFont::ON) {
3118 os << "</emphasis>";
3123 char c = par->GetChar(i);
3125 if (c == LyXParagraph::META_INSET) {
3126 Inset * inset = par->GetInset(i);
3128 std::ostringstream ost;
3129 inset->DocBook(this, ost);
3130 string tmp_out = ost.str().c_str();
3133 inset->DocBook(this, ost);
3135 char * ctmp = ost.str();
3136 string tmp_out(ctmp);
3140 // This code needs some explanation:
3141 // Two insets are treated specially
3142 // label if it is the first element in a command paragraph
3144 // graphics inside tables or figure floats can't go on
3145 // title (the equivalente in latex for this case is caption
3146 // and title should come first
3149 if(desc_on!= 3 || i!= 0) {
3150 if(!tmp_out.empty() && tmp_out[0] == '@') {
3152 extra += frontStrip(tmp_out, '@');
3154 os << frontStrip(tmp_out, '@');
3159 } else if (font2.latex() == LyXFont::ON) {
3160 // "TeX"-Mode on ==> SGML-Mode on.
3166 if (par->linuxDocConvertChar(c, sgml_string)
3167 && !style.free_spacing) { // in freespacing
3169 // non-breaking characters
3173 os << "\n</term><listitem><para>";
3185 // needed if there is an optional argument but no contents
3186 if (main_body > 0 && main_body == par->size()) {
3190 os << "</emphasis>";
3193 // resets description flag correctly
3196 // <term> not closed...
3204 int Buffer::runLaTeX()
3206 if (!users->text) return 0;
3208 ProhibitInput(users);
3210 // get LaTeX-Filename
3211 string name = getLatexName();
3213 string path = OnlyPath(filename);
3215 string org_path = path;
3216 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3220 Path p(path); // path to LaTeX file
3221 users->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
3223 // Remove all error insets
3224 bool a = users->removeAutoInsets();
3226 // Always generate the LaTeX file
3227 makeLaTeXFile(name, org_path, false);
3229 // do the LaTex run(s)
3231 string latex_command = lyxrc.pdf_mode ?
3232 lyxrc.pdflatex_command : lyxrc.latex_command;
3233 LaTeX latex(latex_command, name, filepath);
3234 int res = latex.run(terr,
3235 users->owner()->getMiniBuffer()); // running latex
3237 // check return value from latex.run().
3238 if ((res & LaTeX::NO_LOGFILE)) {
3239 WriteAlert(_("LaTeX did not work!"),
3240 _("Missing log file:"), name);
3241 } else if ((res & LaTeX::ERRORS)) {
3242 users->owner()->getMiniBuffer()->Set(_("Done"));
3243 // Insert all errors as errors boxes
3244 users->insertErrors(terr);
3246 // Dvi should also be kept dirty if the latex run
3247 // ends up with errors. However it should be possible
3248 // to view a dirty dvi too.
3250 //no errors or any other things to think about so:
3251 users->owner()->getMiniBuffer()->Set(_("Done"));
3254 // if we removed error insets before we ran LaTeX or if we inserted
3255 // error insets after we ran LaTeX this must be run:
3256 if (a || (res & LaTeX::ERRORS)){
3259 //users->updateScrollbar();
3263 return latex.getNumErrors();
3267 int Buffer::runLiterate()
3269 if (!users->text) return 0;
3271 ProhibitInput(users);
3273 // get LaTeX-Filename
3274 string name = getLatexName();
3275 // get Literate-Filename
3276 string lit_name = OnlyFilename(ChangeExtension (getLatexName(),
3277 lyxrc.literate_extension));
3279 string path = OnlyPath(filename);
3281 string org_path = path;
3282 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3286 Path p(path); // path to Literate file
3287 users->owner()->getMiniBuffer()->Set(_("Running Literate..."));
3289 // Remove all error insets
3290 bool a = users->removeAutoInsets();
3292 // generate the Literate file if necessary
3293 makeLaTeXFile(lit_name, org_path, false);
3295 string latex_command = lyxrc.pdf_mode ?
3296 lyxrc.pdflatex_command : lyxrc.latex_command;
3297 Literate literate(latex_command, name, filepath,
3299 lyxrc.literate_command, lyxrc.literate_error_filter,
3300 lyxrc.build_command, lyxrc.build_error_filter);
3302 int res = literate.weave(terr, users->owner()->getMiniBuffer());
3304 // check return value from literate.weave().
3305 if ((res & Literate::NO_LOGFILE)) {
3306 WriteAlert(_("Literate command did not work!"),
3307 _("Missing log file:"), name);
3308 } else if ((res & Literate::ERRORS)) {
3309 users->owner()->getMiniBuffer()->Set(_("Done"));
3310 // Insert all errors as errors boxes
3311 users->insertErrors(terr);
3313 // Dvi should also be kept dirty if the latex run
3314 // ends up with errors. However it should be possible
3315 // to view a dirty dvi too.
3317 //no errors or any other things to think about so:
3318 users->owner()->getMiniBuffer()->Set(_("Done"));
3321 // if we removed error insets before we ran LaTeX or if we inserted
3322 // error insets after we ran LaTeX this must be run:
3323 if (a || (res & Literate::ERRORS)){
3326 //users->updateScrollbar();
3330 return literate.getNumErrors();
3334 int Buffer::buildProgram()
3336 if (!users->text) return 0;
3338 ProhibitInput(users);
3340 // get LaTeX-Filename
3341 string name = getLatexName();
3342 // get Literate-Filename
3343 string lit_name = OnlyFilename(ChangeExtension(getLatexName(),
3344 lyxrc.literate_extension));
3346 string path = OnlyPath(filename);
3348 string org_path = path;
3349 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3353 Path p(path); // path to Literate file
3354 users->owner()->getMiniBuffer()->Set(_("Building Program..."));
3356 // Remove all error insets
3357 bool a = users->removeAutoInsets();
3359 // generate the LaTeX file if necessary
3360 if (!isNwClean() || a) {
3361 makeLaTeXFile(lit_name, org_path, false);
3365 string latex_command = lyxrc.pdf_mode ?
3366 lyxrc.pdflatex_command : lyxrc.latex_command;
3367 Literate literate(latex_command, name, filepath,
3369 lyxrc.literate_command, lyxrc.literate_error_filter,
3370 lyxrc.build_command, lyxrc.build_error_filter);
3372 int res = literate.build(terr, users->owner()->getMiniBuffer());
3374 // check return value from literate.build().
3375 if ((res & Literate::NO_LOGFILE)) {
3376 WriteAlert(_("Build did not work!"),
3377 _("Missing log file:"), name);
3378 } else if ((res & Literate::ERRORS)) {
3379 users->owner()->getMiniBuffer()->Set(_("Done"));
3380 // Insert all errors as errors boxes
3381 users->insertErrors(terr);
3383 // Literate files should also be kept dirty if the literate
3384 // command run ends up with errors.
3386 //no errors or any other things to think about so:
3387 users->owner()->getMiniBuffer()->Set(_("Done"));
3391 // if we removed error insets before we ran Literate/Build or
3392 // if we inserted error insets after we ran Literate/Build this
3394 if (a || (res & Literate::ERRORS)){
3397 //users->updateScrollbar();
3401 return literate.getNumErrors();
3405 // This should be enabled when the Chktex class is implemented. (Asger)
3406 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3407 // Other flags: -wall -v0 -x
3408 int Buffer::runChktex()
3410 if (!users->text) return 0;
3412 ProhibitInput(users);
3414 // get LaTeX-Filename
3415 string name = getLatexName();
3416 string path = OnlyPath(filename);
3418 string org_path = path;
3419 if (lyxrc.use_tempdir || (IsDirWriteable(path) < 1)) {
3423 Path p(path); // path to LaTeX file
3424 users->owner()->getMiniBuffer()->Set(_("Running chktex..."));
3426 // Remove all error insets
3427 bool removedErrorInsets = users->removeAutoInsets();
3429 // Generate the LaTeX file if neccessary
3430 makeLaTeXFile(name, org_path, false);
3433 Chktex chktex(lyxrc.chktex_command, name, filepath);
3434 int res = chktex.run(terr); // run chktex
3437 WriteAlert(_("chktex did not work!"),
3438 _("Could not run with file:"), name);
3439 } else if (res > 0) {
3440 // Insert all errors as errors boxes
3441 users->insertErrors(terr);
3444 // if we removed error insets before we ran chktex or if we inserted
3445 // error insets after we ran chktex, this must be run:
3446 if (removedErrorInsets || res){
3449 //users->updateScrollbar();
3457 void Buffer::validate(LaTeXFeatures & features) const
3459 LyXParagraph * par = paragraph;
3460 LyXTextClass const & tclass =
3461 textclasslist.TextClass(params.textclass);
3463 // AMS Style is at document level
3465 features.amsstyle = (params.use_amsmath ||
3466 tclass.provides(LyXTextClass::amsmath));
3469 // We don't use "lyxerr.debug" because of speed. (Asger)
3470 if (lyxerr.debugging(Debug::LATEX))
3471 lyxerr << "Paragraph: " << par << endl;
3473 // Now just follow the list of paragraphs and run
3474 // validate on each of them.
3475 par->validate(features);
3477 // and then the next paragraph
3481 // the bullet shapes are buffer level not paragraph level
3482 // so they are tested here
3483 for (int i = 0; i < 4; ++i) {
3484 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3485 int font = params.user_defined_bullets[i].getFont();
3488 .user_defined_bullets[i]
3495 features.latexsym = true;
3499 features.amssymb = true;
3501 else if ((font >= 2 && font <= 5)) {
3502 features.pifont = true;
3507 if (lyxerr.debugging(Debug::LATEX)) {
3508 features.showStruct();
3513 void Buffer::setPaperStuff()
3515 params.papersize = BufferParams::PAPER_DEFAULT;
3516 char c1 = params.paperpackage;
3517 if (c1 == BufferParams::PACKAGE_NONE) {
3518 char c2 = params.papersize2;
3519 if (c2 == BufferParams::VM_PAPER_USLETTER)
3520 params.papersize = BufferParams::PAPER_USLETTER;
3521 else if (c2 == BufferParams::VM_PAPER_USLEGAL)
3522 params.papersize = BufferParams::PAPER_LEGALPAPER;
3523 else if (c2 == BufferParams::VM_PAPER_USEXECUTIVE)
3524 params.papersize = BufferParams::PAPER_EXECUTIVEPAPER;
3525 else if (c2 == BufferParams::VM_PAPER_A3)
3526 params.papersize = BufferParams::PAPER_A3PAPER;
3527 else if (c2 == BufferParams::VM_PAPER_A4)
3528 params.papersize = BufferParams::PAPER_A4PAPER;
3529 else if (c2 == BufferParams::VM_PAPER_A5)
3530 params.papersize = BufferParams::PAPER_A5PAPER;
3531 else if ((c2 == BufferParams::VM_PAPER_B3) || (c2 == BufferParams::VM_PAPER_B4) ||
3532 (c2 == BufferParams::VM_PAPER_B5))
3533 params.papersize = BufferParams::PAPER_B5PAPER;
3534 } else if ((c1 == BufferParams::PACKAGE_A4) || (c1 == BufferParams::PACKAGE_A4WIDE) ||
3535 (c1 == BufferParams::PACKAGE_WIDEMARGINSA4))
3536 params.papersize = BufferParams::PAPER_A4PAPER;
3540 // This function should be in Buffer because it's a buffer's property (ale)
3541 string Buffer::getIncludeonlyList(char delim)
3544 for (inset_iterator it = inset_iterator_begin();
3545 it != inset_iterator_end(); ++it) {
3546 if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3547 InsetInclude * insetinc =
3548 static_cast<InsetInclude *>(*it);
3549 if (insetinc->isInclude()
3550 && insetinc->isNoLoad()) {
3553 lst += OnlyFilename(ChangeExtension(insetinc->getContents(), string()));
3557 lyxerr.debug() << "Includeonly(" << lst << ')' << endl;
3562 vector<string> Buffer::getLabelList()
3564 /// if this is a child document and the parent is already loaded
3565 /// Use the parent's list instead [ale990407]
3566 if (!params.parentname.empty()
3567 && bufferlist.exists(params.parentname)) {
3568 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3570 return tmp->getLabelList();
3573 vector<string> label_list;
3574 for (inset_iterator it = inset_iterator_begin();
3575 it != inset_iterator_end(); ++it) {
3576 vector<string> l = (*it)->getLabelList();
3577 label_list.insert(label_list.end(), l.begin(), l.end());
3583 vector<vector<Buffer::TocItem> > Buffer::getTocList()
3585 vector<vector<TocItem> > l(4);
3586 LyXParagraph * par = paragraph;
3588 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3589 if (textclasslist.Style(params.textclass,
3590 par->GetLayout()).labeltype
3591 == LABEL_SENSITIVE) {
3595 tmp.str = par->String(this, false);
3596 switch (par->footnotekind) {
3597 case LyXParagraph::FIG:
3598 case LyXParagraph::WIDE_FIG:
3599 l[TOC_LOF].push_back(tmp);
3601 case LyXParagraph::TAB:
3602 case LyXParagraph::WIDE_TAB:
3603 l[TOC_LOT].push_back(tmp);
3605 case LyXParagraph::ALGORITHM:
3606 l[TOC_LOA].push_back(tmp);
3608 case LyXParagraph::FOOTNOTE:
3609 case LyXParagraph::MARGIN:
3613 } else if (!par->IsDummy()) {
3614 char labeltype = textclasslist.Style(params.textclass,
3615 par->GetLayout()).labeltype;
3617 if (labeltype >= LABEL_COUNTER_CHAPTER
3618 && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3619 // insert this into the table of contents
3624 textclasslist.TextClass(params.textclass).maxcounter());
3625 tmp.str = par->String(this, true);
3626 l[TOC_TOC].push_back(tmp);
3634 // This is also a buffer property (ale)
3635 vector<pair<string,string> > Buffer::getBibkeyList()
3637 /// if this is a child document and the parent is already loaded
3638 /// Use the parent's list instead [ale990412]
3639 if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3640 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3642 return tmp->getBibkeyList();
3645 vector<pair<string, string> > keys;
3646 LyXParagraph * par = paragraph;
3649 keys.push_back(pair<string,string>(par->bibkey->getContents(),
3650 par->String(this, false)));
3654 // Might be either using bibtex or a child has bibliography
3656 for (inset_iterator it = inset_iterator_begin();
3657 it != inset_iterator_end(); ++it) {
3658 // Search for Bibtex or Include inset
3659 if ((*it)->LyxCode() == Inset::BIBTEX_CODE) {
3660 vector<pair<string,string> > tmp =
3661 static_cast<InsetBibtex*>(*it)->getKeys();
3662 keys.insert(keys.end(), tmp.begin(), tmp.end());
3663 } else if ((*it)->LyxCode() == Inset::INCLUDE_CODE) {
3664 vector<pair<string,string> > tmp =
3665 static_cast<InsetInclude*>(*it)->getKeys();
3666 keys.insert(keys.end(), tmp.begin(), tmp.end());
3675 bool Buffer::isDepClean(string const & name) const
3677 DEPCLEAN * item = dep_clean;
3678 while (item && item->master != name)
3680 if (!item) return true;
3685 void Buffer::markDepClean(string const & name)
3688 dep_clean = new DEPCLEAN;
3689 dep_clean->clean = true;
3690 dep_clean->master = name;
3691 dep_clean->next = 0;
3693 DEPCLEAN* item = dep_clean;
3694 while (item && item->master != name)
3699 item = new DEPCLEAN;
3701 item->master = name;
3708 bool Buffer::Dispatch(string const & command)
3710 // Split command string into command and argument
3711 string cmd, line = frontStrip(command);
3712 string arg = strip(frontStrip(split(line, cmd, ' ')));
3714 return Dispatch(lyxaction.LookupFunc(cmd.c_str()), arg.c_str());
3718 bool Buffer::Dispatch(int action, string const & argument)
3720 bool dispatched = true;
3723 MenuExport(this, argument);
3733 void Buffer::resize()
3735 /// resize the BufferViews!
3741 void Buffer::resizeInsets(BufferView * bv)
3743 /// then remove all LyXText in text-insets
3744 LyXParagraph * par = paragraph;
3745 for(;par;par = par->next) {
3746 par->resizeInsetsLyXText(bv);
3750 void Buffer::ChangeLanguage(Language const * from, Language const * to)
3753 LyXParagraph * par = paragraph;
3755 par->ChangeLanguage(params, from, to);
3761 bool Buffer::isMultiLingual()
3764 LyXParagraph * par = paragraph;
3766 if (par->isMultiLingual(params))
3774 Buffer::inset_iterator::inset_iterator(LyXParagraph * paragraph,
3775 LyXParagraph::size_type pos)
3777 it = par->InsetIterator(pos);
3778 if (it == par->inset_iterator_end()) {
3785 void Buffer::inset_iterator::SetParagraph() {
3787 it = par->inset_iterator_begin();
3788 if (it != par->inset_iterator_end())
3793 // We maintain an invariant that whenever par = 0 then it = 0