]> git.lyx.org Git - features.git/blob - src/buffer.C
cleanups from John and Juergen, bib files parsing fix from Herbert
[features.git] / src / buffer.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team.
8  *
9  *           This file is Copyright 1996-2001
10  *           Lars Gullik Bjønnes
11  *
12  * ====================================================== 
13  */
14
15 #include <config.h>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include "buffer.h"
22 #include "bufferlist.h"
23 #include "lyx_main.h"
24 #include "lyx_gui_misc.h"
25 #include "LyXAction.h"
26 #include "lyxrc.h"
27 #include "lyxlex.h"
28 #include "tex-strings.h"
29 #include "layout.h"
30 #include "bufferview_funcs.h"
31 #include "lyxfont.h"
32 #include "version.h"
33 #include "LaTeX.h"
34 #include "Chktex.h"
35 #include "LyXView.h"
36 #include "debug.h"
37 #include "LaTeXFeatures.h"
38 #include "lyxtext.h"
39 #include "gettext.h"
40 #include "language.h"
41 #include "encoding.h"
42 #include "exporter.h"
43 #include "Lsstream.h"
44 #include "converter.h"
45 #include "BufferView.h"
46 #include "ParagraphParameters.h"
47 #include "iterators.h"
48 #include "lyxtextclasslist.h"
49
50 #include "mathed/formulamacro.h"
51 #include "mathed/formula.h"
52
53 #include "insets/inset.h"
54 #include "insets/inseterror.h"
55 #include "insets/insetlabel.h"
56 #include "insets/insetref.h"
57 #include "insets/inseturl.h"
58 #include "insets/insetnote.h"
59 #include "insets/insetquotes.h"
60 #include "insets/insetlatexaccent.h"
61 #include "insets/insetbib.h" 
62 #include "insets/insetcite.h" 
63 #include "insets/insetexternal.h"
64 #include "insets/insetindex.h" 
65 #include "insets/insetinclude.h"
66 #include "insets/insettoc.h"
67 #include "insets/insetparent.h"
68 #include "insets/insetspecialchar.h"
69 #include "insets/figinset.h"
70 #include "insets/insettext.h"
71 #include "insets/insetert.h"
72 #include "insets/insetgraphics.h"
73 #include "insets/insetfoot.h"
74 #include "insets/insetmarginal.h"
75 #include "insets/insetminipage.h"
76 #include "insets/insetfloat.h"
77 #include "insets/insettabular.h"
78 #if 0
79 #include "insets/insettheorem.h"
80 #include "insets/insetlist.h"
81 #endif
82 #include "insets/insetcaption.h"
83 #include "insets/insetfloatlist.h"
84
85 #include "frontends/Dialogs.h"
86 #include "frontends/Alert.h"
87
88 #include "support/textutils.h"
89 #include "support/filetools.h"
90 #include "support/path.h"
91 #include "support/os.h"
92 #include "support/lyxlib.h"
93 #include "support/FileInfo.h"
94 #include "support/lyxmanip.h"
95 #include "support/lyxalgo.h" // for lyx::count
96
97 #include <fstream>
98 #include <iomanip>
99 #include <map>
100 #include <stack>
101 #include <list>
102 #include <algorithm>
103
104 #include <cstdlib>
105 #include <cmath>
106 #include <unistd.h>
107 #include <sys/types.h>
108 #include <utime.h>
109
110
111 #ifdef HAVE_LOCALE
112 #include <locale>
113 #endif
114
115
116 using std::ostream;
117 using std::ofstream;
118 using std::ifstream;
119 using std::fstream;
120 using std::ios;
121 using std::setw;
122 using std::endl;
123 using std::pair;
124 using std::make_pair;
125 using std::vector;
126 using std::map;
127 using std::max;
128 using std::set;
129 using std::stack;
130 using std::list;
131
132 using lyx::pos_type;
133 using lyx::layout_type;
134 using lyx::textclass_type;
135
136 // all these externs should eventually be removed.
137 extern BufferList bufferlist;
138
139 extern LyXAction lyxaction;
140
141 namespace {
142
143 const int LYX_FORMAT = 220;
144
145 } // namespace anon
146
147 extern int tex_code_break_column;
148
149
150 Buffer::Buffer(string const & file, bool ronly)
151         : paragraph(0), lyx_clean(true), bak_clean(true),
152           unnamed(false), dep_clean(0), read_only(ronly),
153           filename_(file), users(0)
154 {
155         lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
156 //      filename = file;
157         filepath_ = OnlyPath(file);
158 //      paragraph = 0;
159 //      lyx_clean = true;
160 //      bak_clean = true;
161 //      dep_clean = 0;
162 //      read_only = ronly;
163 //      unnamed = false;
164 //      users = 0;
165         lyxvc.buffer(this);
166         if (read_only || lyxrc.use_tempdir) {
167                 tmppath = CreateBufferTmpDir();
168         } else {
169                 tmppath.erase();
170         }
171 }
172
173
174 Buffer::~Buffer()
175 {
176         lyxerr[Debug::INFO] << "Buffer::~Buffer()" << endl;
177         // here the buffer should take care that it is
178         // saved properly, before it goes into the void.
179
180         // make sure that views using this buffer
181         // forgets it.
182         if (users)
183                 users->buffer(0);
184         
185         if (!tmppath.empty()) {
186                 DestroyBufferTmpDir(tmppath);
187         }
188         
189         Paragraph * par = paragraph;
190         Paragraph * tmppar;
191         while (par) {
192                 tmppar = par->next();
193                 delete par;
194                 par = tmppar;
195         }
196         paragraph = 0;
197 }
198
199
200 string const Buffer::getLatexName(bool no_path) const
201 {
202         string const name = ChangeExtension(MakeLatexName(fileName()), ".tex");
203         if (no_path)
204                 return OnlyFilename(name);
205         else
206                 return name;
207 }
208
209
210 pair<Buffer::LogType, string> const Buffer::getLogName(void) const
211 {
212         string const filename = getLatexName(false);
213
214         if (filename.empty())
215                 return make_pair(Buffer::latexlog, string());
216
217         string path = OnlyPath(filename);
218
219         if (lyxrc.use_tempdir || !IsDirWriteable(path))
220                 path = tmppath;
221
222         string const fname = AddName(path,
223                                      OnlyFilename(ChangeExtension(filename,
224                                                                   ".log")));
225         string const bname =
226                 AddName(path, OnlyFilename(
227                         ChangeExtension(filename,
228                                         formats.extension("literate") + ".out")));
229
230         // If no Latex log or Build log is newer, show Build log
231
232         FileInfo const f_fi(fname);
233         FileInfo const b_fi(bname);
234
235         if (b_fi.exist() &&
236             (!f_fi.exist() || f_fi.getModificationTime() < b_fi.getModificationTime())) {
237                 lyxerr[Debug::FILES] << "Log name calculated as : " << bname << endl;
238                 return make_pair(Buffer::buildlog, bname);
239         }
240         lyxerr[Debug::FILES] << "Log name calculated as : " << fname << endl;
241         return make_pair(Buffer::latexlog, fname);
242 }
243
244
245 void Buffer::setReadonly(bool flag)
246 {
247         if (read_only != flag) {
248                 read_only = flag; 
249                 updateTitles();
250                 users->owner()->getDialogs()->updateBufferDependent(false);
251         }
252 }
253
254
255 /// Update window titles of all users
256 // Should work on a list
257 void Buffer::updateTitles() const
258 {
259         if (users)
260                 users->owner()->updateWindowTitle();
261 }
262
263
264 /// Reset autosave timer of all users
265 // Should work on a list
266 void Buffer::resetAutosaveTimers() const
267 {
268         if (users)
269                 users->owner()->resetAutosaveTimer();
270 }
271
272
273 void Buffer::setFileName(string const & newfile)
274 {
275         filename_ = MakeAbsPath(newfile);
276         filepath_ = OnlyPath(filename_);
277         setReadonly(IsFileWriteable(filename_) == 0);
278         updateTitles();
279 }
280
281
282 // We'll remove this later. (Lgb)
283 namespace {
284
285 string last_inset_read;
286
287 #ifndef NO_COMPABILITY
288 struct ErtComp 
289 {
290         ErtComp() : active(false), in_tabular(false) {
291         }
292         string contents;
293         bool active;
294         bool in_tabular;
295         LyXFont font;
296 };
297
298 std::stack<ErtComp> ert_stack;
299 ErtComp ert_comp;
300 #endif
301
302 #ifdef WITH_WARNINGS
303 #warning And _why_ is this here? (Lgb)
304 #endif
305 int unknown_layouts;
306 int unknown_tokens;
307
308 } // anon
309
310
311 // candidate for move to BufferView
312 // (at least some parts in the beginning of the func)
313 //
314 // Uwe C. Schroeder
315 // changed to be public and have one parameter
316 // if par = 0 normal behavior
317 // else insert behavior
318 // Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
319 bool Buffer::readLyXformat2(LyXLex & lex, Paragraph * par)
320 {
321         unknown_layouts = 0;
322         unknown_tokens = 0;
323 #ifndef NO_COMPABILITY
324         ert_comp.contents.erase();
325         ert_comp.active = false;
326         ert_comp.in_tabular = false;
327 #endif
328         int pos = 0;
329         Paragraph::depth_type depth = 0; 
330         bool the_end_read = false;
331
332         Paragraph * first_par = 0;
333         LyXFont font(LyXFont::ALL_INHERIT, params.language);
334         if (file_format < 216 && params.language->lang() == "hebrew")
335                 font.setLanguage(default_language);
336
337         if (!par) {
338                 par = new Paragraph;
339         } else {
340                 // We are inserting into an existing document
341                 users->text->breakParagraph(users);
342                 first_par = users->text->ownerParagraph();
343                 pos = 0;
344                 markDirty();
345                 // We don't want to adopt the parameters from the
346                 // document we insert, so we skip until the text begins:
347                 while (lex.isOK()) {
348                         lex.nextToken();
349                         string const pretoken = lex.getString();
350                         if (pretoken == "\\layout") {
351                                 lex.pushToken(pretoken);
352                                 break;
353                         }
354                 }
355         }
356
357         while (lex.isOK()) {
358                 lex.nextToken();
359                 string const token = lex.getString();
360
361                 if (token.empty()) continue;
362
363                 lyxerr[Debug::PARSER] << "Handling token: `"
364                                       << token << "'" << endl;
365                 
366                 the_end_read =
367                         parseSingleLyXformat2Token(lex, par, first_par,
368                                                    token, pos, depth,
369                                                    font);
370         }
371    
372         if (!first_par)
373                 first_par = par;
374
375         paragraph = first_par;
376
377         if (unknown_layouts > 0) {
378                 string s = _("Couldn't set the layout for ");
379                 if (unknown_layouts == 1) {
380                         s += _("one paragraph");
381                 } else {
382                         s += tostr(unknown_layouts);
383                         s += _(" paragraphs");
384                 }
385                 Alert::alert(_("Textclass Loading Error!"), s,
386                            _("When reading " + fileName()));
387         }
388
389         if (unknown_tokens > 0) {
390                 string s = _("Encountered ");
391                 if (unknown_tokens == 1) {
392                         s += _("one unknown token");
393                 } else {
394                         s += tostr(unknown_tokens);
395                         s += _(" unknown tokens");
396                 }
397                 Alert::alert(_("Textclass Loading Error!"), s,
398                            _("When reading " + fileName()));
399         }
400
401         return the_end_read;
402 }
403
404
405 #ifndef NO_COMPABILITY
406 void Buffer::insertErtContents(Paragraph * par, int & pos, bool set_inactive) 
407 {
408         if (!ert_comp.contents.empty()) {
409                 lyxerr[Debug::INSETS] << "ERT contents:\n'"
410                                       << ert_comp.contents << "'" << endl;
411                 Inset * inset = new InsetERT(params.language, ert_comp.contents, true);
412                 par->insertInset(pos++, inset, ert_comp.font);
413                 ert_comp.contents.erase();
414         }
415         if (set_inactive) {
416                 ert_comp.active = false;
417         }
418 }
419 #endif
420
421
422 bool
423 Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
424                                    Paragraph *& first_par,
425                                    string const & token, int & pos,
426                                    Paragraph::depth_type & depth, 
427                                    LyXFont & font
428         )
429 {
430         bool the_end_read = false;
431 #ifndef NO_COMPABILITY
432 #ifndef NO_PEXTRA_REALLY
433         // This is super temporary but is needed to get the compability
434         // mode for minipages work correctly together with new tabulars.
435         static int call_depth;
436         ++call_depth;
437         bool checkminipage = false;
438         static Paragraph * minipar;
439         static Paragraph * parBeforeMinipage;
440 #endif
441 #endif
442         if (token[0] != '\\') {
443 #ifndef NO_COMPABILITY
444                 if (ert_comp.active) {
445                         ert_comp.contents += token;
446                 } else {
447 #endif
448                 for (string::const_iterator cit = token.begin();
449                      cit != token.end(); ++cit) {
450                         par->insertChar(pos, (*cit), font);
451                         ++pos;
452                 }
453 #ifndef NO_COMPABILITY
454                 }
455 #endif
456         } else if (token == "\\i") {
457                 Inset * inset = new InsetLatexAccent;
458                 inset->read(this, lex);
459                 par->insertInset(pos, inset, font);
460                 ++pos;
461         } else if (token == "\\layout") {
462 #ifndef NO_COMPABILITY
463                 ert_comp.in_tabular = false;
464                 // Do the insetert.
465                 insertErtContents(par, pos);
466 #endif
467                 lex.eatLine();
468                 string const layoutname = lex.getString();
469                 //lyxerr << "Looking for layout '"
470                 // << layoutname << "'!" << endl;
471                 
472                 pair<bool, layout_type> pp
473                   = textclasslist.NumberOfLayout(params.textclass, layoutname);
474
475                 //lyxerr << "Result: " << pp.first << "/" << pp.second << endl;
476                 
477 #ifndef NO_COMPABILITY
478                 if (compare_no_case(layoutname, "latex") == 0) {
479                         ert_comp.active = true;
480                         ert_comp.font = font;
481                 }
482 #endif
483 #ifdef USE_CAPTION
484                 // The is the compability reading of layout caption.
485                 // It can be removed in LyX version 1.3.0. (Lgb)
486                 if (compare_no_case(layoutname, "caption") == 0) {
487                         // We expect that the par we are now working on is
488                         // really inside a InsetText inside a InsetFloat.
489                         // We also know that captions can only be
490                         // one paragraph. (Lgb)
491                         
492                         // We should now read until the next "\layout"
493                         // is reached.
494                         // This is probably not good enough, what if the
495                         // caption is the last par in the document (Lgb)
496                         istream & ist = lex.getStream();
497                         stringstream ss;
498                         string line;
499                         int begin = 0;
500                         while (true) {
501                                 getline(ist, line);
502                                 if (prefixIs(line, "\\layout")) {
503                                         lex.pushToken(line);
504                                         break;
505                                 }
506                                 if (prefixIs(line, "\\begin_inset"))
507                                         ++begin;
508                                 if (prefixIs(line, "\\end_inset")) {
509                                         if (begin)
510                                                 --begin;
511                                         else {
512                                                 lex.pushToken(line);
513                                                 break;
514                                         }
515                                 }
516                                 
517                                 ss << line << '\n';
518                         }
519                         // Now we should have the whole layout in ss
520                         // we should now be able to give this to the
521                         // caption inset.
522                         ss << "\\end_inset\n";
523                         
524                         // This seems like a bug in stringstream.
525                         // We really should be able to use ss
526                         // directly. (Lgb)
527                         istringstream is(ss.str());
528                         LyXLex tmplex(0, 0);
529                         tmplex.setStream(is);
530                         Inset * inset = new InsetCaption;
531                         inset->Read(this, tmplex);
532                         par->InsertInset(pos, inset, font);
533                         ++pos;
534                 } else {
535 #endif
536                         if (!first_par)
537                                 first_par = par;
538                         else {
539                                 par = new Paragraph(par);
540                         }
541                         pos = 0;
542                         if (pp.first) {
543                                 par->layout = pp.second;
544 #ifndef NO_COMPABILITY
545                         } else if (ert_comp.active) {
546                                 par->layout = 0;
547 #endif
548                         } else {
549                                 // layout not found
550                                 // use default layout "Standard" (0)
551                                 //lyxerr << "Layout '" << layoutname
552                                 //       << "' was not found!" << endl;
553                                 
554                                 par->layout = 0;
555                                 ++unknown_layouts;
556                                 string const s = _("Layout had to be changed from\n")
557                                         + layoutname + _(" to ")
558                                         + textclasslist.NameOfLayout(params.textclass, par->layout);
559                                 InsetError * new_inset = new InsetError(s);
560                                 par->insertInset(0, new_inset, 
561                                                  LyXFont(LyXFont::ALL_INHERIT,
562                                                          params.language));
563                         }
564                         // Test whether the layout is obsolete.
565                         LyXLayout const & layout =
566                                 textclasslist.Style(params.textclass,
567                                                     par->layout);
568                         if (!layout.obsoleted_by().empty())
569                                 par->layout = textclasslist
570                                         .NumberOfLayout(params.textclass,
571                                                         layout.obsoleted_by())
572                                         .second;
573                         par->params().depth(depth);
574                         font = LyXFont(LyXFont::ALL_INHERIT, params.language);
575                         if (file_format < 216
576                             && params.language->lang() == "hebrew")
577                                 font.setLanguage(default_language);
578 #if USE_CAPTION
579                 }
580 #endif
581
582 #ifndef NO_COMPABILITY
583         } else if (token == "\\begin_float") {
584                 insertErtContents(par, pos);
585                 //insertErtContents(par, pos, false);
586                 //ert_stack.push(ert_comp);
587                 //ert_comp = ErtComp();
588                 
589                 // This is the compability reader. It can be removed in
590                 // LyX version 1.3.0. (Lgb)
591                 lex.next();
592                 string const tmptok = lex.getString();
593                 //lyxerr << "old float: " << tmptok << endl;
594                 
595                 Inset * inset = 0;
596                 stringstream old_float;
597                 
598                 if (tmptok == "footnote") {
599                         inset = new InsetFoot;
600                         old_float << "collapsed true\n";
601                 } else if (tmptok == "margin") {
602                         inset = new InsetMarginal;
603                         old_float << "collapsed true\n";
604                 } else if (tmptok == "fig") {
605                         inset = new InsetFloat("figure");
606                         old_float << "placement htbp\n"
607                                   << "wide false\n"
608                                   << "collapsed false\n";
609                 } else if (tmptok == "tab") {
610                         inset = new InsetFloat("table");
611                         old_float << "placement htbp\n"
612                                   << "wide false\n"
613                                   << "collapsed false\n";
614                 } else if (tmptok == "alg") {
615                         inset = new InsetFloat("algorithm");
616                         old_float << "placement htbp\n"
617                                   << "wide false\n"
618                                   << "collapsed false\n";
619                 } else if (tmptok == "wide-fig") {
620                         inset = new InsetFloat("figure");
621                         //InsetFloat * tmp = new InsetFloat("figure");
622                         //tmp->wide(true);
623                         //inset = tmp;
624                         old_float << "placement htbp\n"
625                                   << "wide true\n"
626                                   << "collapsed false\n";
627                 } else if (tmptok == "wide-tab") {
628                         inset = new InsetFloat("table");
629                         //InsetFloat * tmp = new InsetFloat("table");
630                         //tmp->wide(true);
631                         //inset = tmp;
632                         old_float << "placement htbp\n"
633                                   << "wide true\n"
634                                   << "collapsed false\n";
635                 }
636
637                 if (!inset) {
638 #ifndef NO_PEXTRA_REALLY
639                         --call_depth;
640 #endif
641                         return false; // no end read yet
642                 }
643
644                 // Here we need to check for \end_deeper and handle that
645                 // before we do the footnote parsing.
646                 // This _is_ a hack! (Lgb)
647                 while (true) {
648                         lex.next();
649                         string const tmp = lex.getString();
650                         if (tmp == "\\end_deeper") {
651                                 //lyxerr << "\\end_deeper caught!" << endl;
652                                 if (!depth) {
653                                         lex.printError("\\end_deeper: "
654                                                        "depth is already null");
655                                 } else
656                                         --depth;
657                                 
658                         } else {
659                                 old_float << tmp << ' ';
660                                 break;
661                         }
662                 }
663                 
664                 old_float << lex.getLongString("\\end_float")
665                           << "\n\\end_inset\n";
666                 //lyxerr << "Float Body:\n" << old_float.str() << endl;
667                 // That this does not work seems like a bug
668                 // in stringstream. (Lgb)
669                 istringstream istr(old_float.str());
670                 LyXLex nylex(0, 0);
671                 nylex.setStream(istr);
672                 inset->read(this, nylex);
673                 par->insertInset(pos, inset, font);
674                 ++pos;
675                 insertErtContents(par, pos);
676 #endif
677         } else if (token == "\\begin_deeper") {
678                 ++depth;
679         } else if (token == "\\end_deeper") {
680                 if (!depth) {
681                         lex.printError("\\end_deeper: "
682                                        "depth is already null");
683                 }
684                 else
685                         --depth;
686         } else if (token == "\\begin_preamble") {
687                 params.readPreamble(lex);
688         } else if (token == "\\textclass") {
689                 lex.eatLine();
690                 pair<bool, textclass_type> pp = 
691                         textclasslist.NumberOfClass(lex.getString());
692                 if (pp.first) {
693                         params.textclass = pp.second;
694                 } else {
695                         Alert::alert(string(_("Textclass error")), 
696                                 string(_("The document uses an unknown textclass \"")) + 
697                                 lex.getString() + string("\"."),
698                                 string(_("LyX will not be able to produce output correctly.")));
699                         params.textclass = 0;
700                 }
701                 if (!textclasslist.Load(params.textclass)) {
702                         // if the textclass wasn't loaded properly
703                         // we need to either substitute another
704                         // or stop loading the file.
705                         // I can substitute but I don't see how I can
706                         // stop loading... ideas??  ARRae980418
707                         Alert::alert(_("Textclass Loading Error!"),
708                                    string(_("Can't load textclass ")) +
709                                    textclasslist.NameOfClass(params.textclass),
710                                    _("-- substituting default"));
711                         params.textclass = 0;
712                 }
713         } else if (token == "\\options") {
714                 lex.eatLine();
715                 params.options = lex.getString();
716         } else if (token == "\\language") {
717                 params.readLanguage(lex);    
718         } else if (token == "\\fontencoding") {
719                 lex.eatLine();
720         } else if (token == "\\inputencoding") {
721                 lex.eatLine();
722                 params.inputenc = lex.getString();
723         } else if (token == "\\graphics") {
724                 params.readGraphicsDriver(lex);
725         } else if (token == "\\fontscheme") {
726                 lex.eatLine();
727                 params.fonts = lex.getString();
728         } else if (token == "\\noindent") {
729                 par->params().noindent(true);
730         } else if (token == "\\fill_top") {
731                 par->params().spaceTop(VSpace(VSpace::VFILL));
732         } else if (token == "\\fill_bottom") {
733                 par->params().spaceBottom(VSpace(VSpace::VFILL));
734         } else if (token == "\\line_top") {
735                 par->params().lineTop(true);
736         } else if (token == "\\line_bottom") {
737                 par->params().lineBottom(true);
738         } else if (token == "\\pagebreak_top") {
739                 par->params().pagebreakTop(true);
740         } else if (token == "\\pagebreak_bottom") {
741                 par->params().pagebreakBottom(true);
742         } else if (token == "\\start_of_appendix") {
743                 par->params().startOfAppendix(true);
744         } else if (token == "\\paragraph_separation") {
745                 int tmpret = lex.findToken(string_paragraph_separation);
746                 if (tmpret == -1)
747                         ++tmpret;
748                 if (tmpret != LYX_LAYOUT_DEFAULT) 
749                         params.paragraph_separation =
750                                 static_cast<BufferParams::PARSEP>(tmpret);
751         } else if (token == "\\defskip") {
752                 lex.nextToken();
753                 params.defskip = VSpace(lex.getString());
754 #ifndef NO_COMPABILITY
755         } else if (token == "\\epsfig") { // obsolete
756                 // Indeed it is obsolete, but we HAVE to be backwards
757                 // compatible until 0.14, because otherwise all figures
758                 // in existing documents are irretrivably lost. (Asger)
759                 params.readGraphicsDriver(lex);
760 #endif
761         } else if (token == "\\quotes_language") {
762                 int tmpret = lex.findToken(string_quotes_language);
763                 if (tmpret == -1)
764                         ++tmpret;
765                 if (tmpret != LYX_LAYOUT_DEFAULT) {
766                         InsetQuotes::quote_language tmpl = 
767                                 InsetQuotes::EnglishQ;
768                         switch (tmpret) {
769                         case 0:
770                                 tmpl = InsetQuotes::EnglishQ;
771                                 break;
772                         case 1:
773                                 tmpl = InsetQuotes::SwedishQ;
774                                 break;
775                         case 2:
776                                 tmpl = InsetQuotes::GermanQ;
777                                 break;
778                         case 3:
779                                 tmpl = InsetQuotes::PolishQ;
780                                 break;
781                         case 4:
782                                 tmpl = InsetQuotes::FrenchQ;
783                                 break;
784                         case 5:
785                                 tmpl = InsetQuotes::DanishQ;
786                                 break;  
787                         }
788                         params.quotes_language = tmpl;
789                 }
790         } else if (token == "\\quotes_times") {
791                 lex.nextToken();
792                 switch (lex.getInteger()) {
793                 case 1: 
794                         params.quotes_times = InsetQuotes::SingleQ; 
795                         break;
796                 case 2: 
797                         params.quotes_times = InsetQuotes::DoubleQ; 
798                         break;
799                 }
800         } else if (token == "\\papersize") {
801                 int tmpret = lex.findToken(string_papersize);
802                 if (tmpret == -1)
803                         ++tmpret;
804                 else
805                         params.papersize2 = tmpret;
806         } else if (token == "\\paperpackage") {
807                 int tmpret = lex.findToken(string_paperpackages);
808                 if (tmpret == -1) {
809                         ++tmpret;
810                         params.paperpackage = BufferParams::PACKAGE_NONE;
811                 } else
812                         params.paperpackage = tmpret;
813         } else if (token == "\\use_geometry") {
814                 lex.nextToken();
815                 params.use_geometry = lex.getInteger();
816         } else if (token == "\\use_amsmath") {
817                 lex.nextToken();
818                 params.use_amsmath = lex.getInteger();
819         } else if (token == "\\use_natbib") {
820                 lex.nextToken();
821                 params.use_natbib = lex.getInteger();
822         } else if (token == "\\use_numerical_citations") {
823                 lex.nextToken();
824                 params.use_numerical_citations = lex.getInteger();
825         } else if (token == "\\paperorientation") {
826                 int tmpret = lex.findToken(string_orientation);
827                 if (tmpret == -1)
828                         ++tmpret;
829                 if (tmpret != LYX_LAYOUT_DEFAULT) 
830                         params.orientation = static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
831         } else if (token == "\\paperwidth") {
832                 lex.next();
833                 params.paperwidth = lex.getString();
834         } else if (token == "\\paperheight") {
835                 lex.next();
836                 params.paperheight = lex.getString();
837         } else if (token == "\\leftmargin") {
838                 lex.next();
839                 params.leftmargin = lex.getString();
840         } else if (token == "\\topmargin") {
841                 lex.next();
842                 params.topmargin = lex.getString();
843         } else if (token == "\\rightmargin") {
844                 lex.next();
845                 params.rightmargin = lex.getString();
846         } else if (token == "\\bottommargin") {
847                 lex.next();
848                 params.bottommargin = lex.getString();
849         } else if (token == "\\headheight") {
850                 lex.next();
851                 params.headheight = lex.getString();
852         } else if (token == "\\headsep") {
853                 lex.next();
854                 params.headsep = lex.getString();
855         } else if (token == "\\footskip") {
856                 lex.next();
857                 params.footskip = lex.getString();
858         } else if (token == "\\paperfontsize") {
859                 lex.nextToken();
860                 params.fontsize = strip(lex.getString());
861         } else if (token == "\\papercolumns") {
862                 lex.nextToken();
863                 params.columns = lex.getInteger();
864         } else if (token == "\\papersides") {
865                 lex.nextToken();
866                 switch (lex.getInteger()) {
867                 default:
868                 case 1: params.sides = LyXTextClass::OneSide; break;
869                 case 2: params.sides = LyXTextClass::TwoSides; break;
870                 }
871         } else if (token == "\\paperpagestyle") {
872                 lex.nextToken();
873                 params.pagestyle = strip(lex.getString());
874         } else if (token == "\\bullet") {
875                 lex.nextToken();
876                 int const index = lex.getInteger();
877                 lex.nextToken();
878                 int temp_int = lex.getInteger();
879                 params.user_defined_bullets[index].setFont(temp_int);
880                 params.temp_bullets[index].setFont(temp_int);
881                 lex.nextToken();
882                 temp_int = lex.getInteger();
883                 params.user_defined_bullets[index].setCharacter(temp_int);
884                 params.temp_bullets[index].setCharacter(temp_int);
885                 lex.nextToken();
886                 temp_int = lex.getInteger();
887                 params.user_defined_bullets[index].setSize(temp_int);
888                 params.temp_bullets[index].setSize(temp_int);
889                 lex.nextToken();
890                 string const temp_str = lex.getString();
891                 if (temp_str != "\\end_bullet") {
892                                 // this element isn't really necessary for
893                                 // parsing but is easier for humans
894                                 // to understand bullets. Put it back and
895                                 // set a debug message?
896                         lex.printError("\\end_bullet expected, got" + temp_str);
897                                 //how can I put it back?
898                 }
899         } else if (token == "\\bulletLaTeX") {
900                 // The bullet class should be able to read this.
901                 lex.nextToken();
902                 int const index = lex.getInteger();
903                 lex.next();
904                 string temp_str = lex.getString();
905                 string sum_str;
906                 while (temp_str != "\\end_bullet") {
907                                 // this loop structure is needed when user
908                                 // enters an empty string since the first
909                                 // thing returned will be the \\end_bullet
910                                 // OR
911                                 // if the LaTeX entry has spaces. Each element
912                                 // therefore needs to be read in turn
913                         sum_str += temp_str;
914                         lex.next();
915                         temp_str = lex.getString();
916                 }
917
918                 params.user_defined_bullets[index].setText(sum_str);
919                 params.temp_bullets[index].setText(sum_str);
920         } else if (token == "\\secnumdepth") {
921                 lex.nextToken();
922                 params.secnumdepth = lex.getInteger();
923         } else if (token == "\\tocdepth") {
924                 lex.nextToken();
925                 params.tocdepth = lex.getInteger();
926         } else if (token == "\\spacing") {
927                 lex.next();
928                 string const tmp = strip(lex.getString());
929                 Spacing::Space tmp_space = Spacing::Default;
930                 float tmp_val = 0.0;
931                 if (tmp == "single") {
932                         tmp_space = Spacing::Single;
933                 } else if (tmp == "onehalf") {
934                         tmp_space = Spacing::Onehalf;
935                 } else if (tmp == "double") {
936                         tmp_space = Spacing::Double;
937                 } else if (tmp == "other") {
938                         lex.next();
939                         tmp_space = Spacing::Other;
940                         tmp_val = lex.getFloat();
941                 } else {
942                         lex.printError("Unknown spacing token: '$$Token'");
943                 }
944                 // Small hack so that files written with klyx will be
945                 // parsed correctly.
946                 if (first_par) {
947                         par->params().spacing(Spacing(tmp_space, tmp_val));
948                 } else {
949                         params.spacing.set(tmp_space, tmp_val);
950                 }
951         } else if (token == "\\paragraph_spacing") {
952                 lex.next();
953                 string const tmp = strip(lex.getString());
954                 if (tmp == "single") {
955                         par->params().spacing(Spacing(Spacing::Single));
956                 } else if (tmp == "onehalf") {
957                         par->params().spacing(Spacing(Spacing::Onehalf));
958                 } else if (tmp == "double") {
959                         par->params().spacing(Spacing(Spacing::Double));
960                 } else if (tmp == "other") {
961                         lex.next();
962                         par->params().spacing(Spacing(Spacing::Other,
963                                          lex.getFloat()));
964                 } else {
965                         lex.printError("Unknown spacing token: '$$Token'");
966                 }
967         } else if (token == "\\float_placement") {
968                 lex.nextToken();
969                 params.float_placement = lex.getString();
970         } else if (token == "\\family") { 
971                 lex.next();
972                 font.setLyXFamily(lex.getString());
973         } else if (token == "\\series") {
974                 lex.next();
975                 font.setLyXSeries(lex.getString());
976         } else if (token == "\\shape") {
977                 lex.next();
978                 font.setLyXShape(lex.getString());
979         } else if (token == "\\size") {
980                 lex.next();
981                 font.setLyXSize(lex.getString());
982 #ifndef NO_COMPABILITY
983         } else if (token == "\\latex") {
984                 lex.next();
985                 string const tok = lex.getString();
986                 if (tok == "no_latex") {
987                         // Do the insetert.
988                         insertErtContents(par, pos);
989                 } else if (tok == "latex") {
990                         ert_comp.active = true;
991                         ert_comp.font = font;
992                 } else if (tok == "default") {
993                         // Do the insetert.
994                         insertErtContents(par, pos);
995                 } else {
996                         lex.printError("Unknown LaTeX font flag "
997                                        "`$$Token'");
998                 }
999 #endif
1000         } else if (token == "\\lang") {
1001                 lex.next();
1002                 string const tok = lex.getString();
1003                 Language const * lang = languages.getLanguage(tok);
1004                 if (lang) {
1005                         font.setLanguage(lang);
1006                 } else {
1007                         font.setLanguage(params.language);
1008                         lex.printError("Unknown language `$$Token'");
1009                 }
1010         } else if (token == "\\numeric") {
1011                 lex.next();
1012                 font.setNumber(font.setLyXMisc(lex.getString()));
1013         } else if (token == "\\emph") {
1014                 lex.next();
1015                 font.setEmph(font.setLyXMisc(lex.getString()));
1016         } else if (token == "\\bar") {
1017                 lex.next();
1018                 string const tok = lex.getString();
1019                 // This is dirty, but gone with LyX3. (Asger)
1020                 if (tok == "under")
1021                         font.setUnderbar(LyXFont::ON);
1022                 else if (tok == "no")
1023                         font.setUnderbar(LyXFont::OFF);
1024                 else if (tok == "default")
1025                         font.setUnderbar(LyXFont::INHERIT);
1026                 else
1027                         lex.printError("Unknown bar font flag "
1028                                        "`$$Token'");
1029         } else if (token == "\\noun") {
1030                 lex.next();
1031                 font.setNoun(font.setLyXMisc(lex.getString()));
1032         } else if (token == "\\color") {
1033                 lex.next();
1034                 font.setLyXColor(lex.getString());
1035         } else if (token == "\\align") {
1036                 int tmpret = lex.findToken(string_align);
1037                 if (tmpret == -1) ++tmpret;
1038                 if (tmpret != LYX_LAYOUT_DEFAULT) { // tmpret != 99 ???
1039                         int const tmpret2 = int(pow(2.0, tmpret));
1040                         //lyxerr << "Tmpret2 = " << tmpret2 << endl;
1041                         par->params().align(LyXAlignment(tmpret2));
1042                 }
1043         } else if (token == "\\added_space_top") {
1044                 lex.nextToken();
1045                 VSpace value = VSpace(lex.getString());
1046                 if ((value.length().len().value() != 0) ||
1047                     (value.kind() != VSpace::LENGTH))
1048                     par->params().spaceTop(value);
1049         } else if (token == "\\added_space_bottom") {
1050                 lex.nextToken();
1051                 VSpace value = VSpace(lex.getString());
1052                 if ((value.length().len().value() != 0) ||
1053                     (value.kind() != VSpace::LENGTH))
1054                     par->params().spaceBottom(value);
1055 #ifndef NO_COMPABILITY
1056 #ifndef NO_PEXTRA_REALLY
1057         } else if (token == "\\pextra_type") {
1058                 lex.nextToken();
1059                 par->params().pextraType(lex.getInteger());
1060         } else if (token == "\\pextra_width") {
1061                 lex.nextToken();
1062                 par->params().pextraWidth(lex.getString());
1063         } else if (token == "\\pextra_widthp") {
1064                 lex.nextToken();
1065                 par->params().pextraWidthp(lex.getString());
1066         } else if (token == "\\pextra_alignment") {
1067                 lex.nextToken();
1068                 par->params().pextraAlignment(lex.getInteger());
1069         } else if (token == "\\pextra_hfill") {
1070                 lex.nextToken();
1071                 par->params().pextraHfill(lex.getInteger());
1072         } else if (token == "\\pextra_start_minipage") {
1073                 lex.nextToken();
1074                 par->params().pextraStartMinipage(lex.getInteger());
1075 #endif
1076 #endif
1077         } else if (token == "\\labelwidthstring") {
1078                 lex.eatLine();
1079                 par->params().labelWidthString(lex.getString());
1080                 // do not delete this token, it is still needed!
1081         } else if (token == "\\end_inset") {
1082                 lyxerr << "Solitary \\end_inset. Missing \\begin_inset?.\n"
1083                        << "Last inset read was: " << last_inset_read
1084                        << endl;
1085                 // Simply ignore this. The insets do not have
1086                 // to read this.
1087                 // But insets should read it, it is a part of
1088                 // the inset isn't it? Lgb.
1089         } else if (token == "\\begin_inset") {
1090 #ifndef NO_COMPABILITY
1091                 insertErtContents(par, pos, false);
1092                 ert_stack.push(ert_comp);
1093                 ert_comp = ErtComp();
1094 #endif
1095                 readInset(lex, par, pos, font);
1096 #ifndef NO_COMPABILITY
1097                 ert_comp = ert_stack.top();
1098                 ert_stack.pop();
1099                 insertErtContents(par, pos);
1100 #endif
1101         } else if (token == "\\SpecialChar") {
1102                 LyXLayout const & layout =
1103                         textclasslist.Style(params.textclass, 
1104                                             par->getLayout());
1105
1106                 // Insets don't make sense in a free-spacing context! ---Kayvan
1107                 if (layout.free_spacing || par->isFreeSpacing()) {
1108                         if (lex.isOK()) {
1109                                 lex.next();
1110                                 string next_token = lex.getString();
1111                                 if (next_token == "\\-") {
1112                                         par->insertChar(pos, '-', font);
1113                                 } else if (next_token == "\\protected_separator"
1114                                         || next_token == "~") {
1115                                         par->insertChar(pos, ' ', font);
1116                                 } else {
1117                                         lex.printError("Token `$$Token' "
1118                                                        "is in free space "
1119                                                        "paragraph layout!");
1120                                         --pos;
1121                                 }
1122                         }
1123                 } else {
1124                         Inset * inset = new InsetSpecialChar;
1125                         inset->read(this, lex);
1126                         par->insertInset(pos, inset, font);
1127                 }
1128                 ++pos;
1129         } else if (token == "\\newline") {
1130 #ifndef NO_COMPABILITY
1131                 if (!ert_comp.in_tabular && ert_comp.active) {
1132                         ert_comp.contents += char(Paragraph::META_NEWLINE);
1133                 } else {
1134                         // Since we cannot know it this is only a regular
1135                         // newline or a tabular cell delimter we have to
1136                         // handle the ERT here.
1137                         insertErtContents(par, pos, false);
1138
1139                         par->insertChar(pos, Paragraph::META_NEWLINE, font);
1140                         ++pos;
1141                 }
1142 #else
1143                 par->insertChar(pos, Paragraph::META_NEWLINE, font);
1144                 ++pos;
1145 #endif
1146         } else if (token == "\\LyXTable") {
1147 #ifndef NO_COMPABILITY
1148                 ert_comp.in_tabular = true;
1149 #endif
1150                 Inset * inset = new InsetTabular(*this);
1151                 inset->read(this, lex);
1152                 par->insertInset(pos, inset, font);
1153                 ++pos;
1154         } else if (token == "\\hfill") {
1155                 par->insertChar(pos, Paragraph::META_HFILL, font);
1156                 ++pos;
1157         } else if (token == "\\protected_separator") { // obsolete
1158                 // This is a backward compability thingie. (Lgb)
1159                 // Remove it later some time...introduced with fileformat
1160                 // 2.16. (Lgb)
1161                 LyXLayout const & layout =
1162                         textclasslist.Style(params.textclass, 
1163                                             par->getLayout());
1164
1165                 if (layout.free_spacing || par->isFreeSpacing()) {
1166                         par->insertChar(pos, ' ', font);
1167                 } else {
1168                         Inset * inset = new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1169                         par->insertInset(pos, inset, font);
1170                 }
1171                 ++pos;
1172         } else if (token == "\\bibitem") {  // ale970302
1173                 if (!par->bibkey) {
1174                         InsetCommandParams p("bibitem", "dummy");
1175                         par->bibkey = new InsetBibKey(p);
1176                 }
1177                 par->bibkey->read(this, lex);                   
1178         } else if (token == "\\backslash") {
1179 #ifndef NO_COMPABILITY
1180                 if (ert_comp.active) {
1181                         ert_comp.contents += "\\";
1182                 } else {
1183 #endif
1184                 par->insertChar(pos, '\\', font);
1185                 ++pos;
1186 #ifndef NO_COMPABILITY
1187                 }
1188 #endif
1189         } else if (token == "\\the_end") {
1190 #ifndef NO_COMPABILITY
1191                 // If we still have some ert active here we have to insert
1192                 // it so we don't loose it. (Lgb)
1193                 insertErtContents(par, pos);
1194 #endif
1195                 the_end_read = true;
1196 #ifndef NO_COMPABILITY
1197 #ifndef NO_PEXTRA_REALLY
1198                 minipar = parBeforeMinipage = 0;
1199 #endif
1200 #endif
1201         } else {
1202 #ifndef NO_COMPABILITY
1203                 if (ert_comp.active) {
1204                         ert_comp.contents += token;
1205                 } else {
1206 #endif
1207                 // This should be insurance for the future: (Asger)
1208                 ++unknown_tokens;
1209                 lex.eatLine();
1210                 string const s = _("Unknown token: ") + token
1211                         + " " + lex.text()  + "\n";
1212
1213                 InsetError * new_inset = new InsetError(s);
1214                 par->insertInset(pos, new_inset, LyXFont(LyXFont::ALL_INHERIT,
1215                                                          params.language));
1216
1217 #ifndef NO_COMPABILITY
1218                 }
1219 #endif
1220         }
1221
1222 #ifndef NO_COMPABILITY
1223 #ifndef NO_PEXTRA_REALLY
1224         // I wonder if we could use this blanket fix for all the
1225         // checkminipage cases...
1226         // don't forget about ert paragraphs and compatibility read for'em
1227         if (par && (par->size() || !ert_comp.contents.empty())) {
1228                 // It is possible that this will check to often,
1229                 // but that should not be an correctness issue.
1230                 // Only a speed issue.
1231                 checkminipage = true;
1232         }
1233         
1234         // now check if we have a minipage paragraph as at this
1235         // point we already read all the necessary data!
1236         // this cannot be done in layout because there we did
1237         // not read yet the paragraph PEXTRA-params (Jug)
1238         //
1239         // BEGIN pextra_minipage compability
1240         // This should be removed in 1.3.x (Lgb)
1241         // I don't think we should remove this so fast (Jug)
1242         
1243         // This compability code is not perfect. In a couple
1244         // of rand cases it fails. When the minipage par is
1245         // the first par in the document, and when there are
1246         // none or only one regular paragraphs after the
1247         // minipage. Currently I am not investing any effort
1248         // in fixing those cases.
1249
1250         //lyxerr << "Call depth: " << call_depth << endl;
1251         if (checkminipage && (call_depth == 1)) {
1252         checkminipage = false;
1253         if (minipar && (minipar != par) &&
1254             (par->params().pextraType()==Paragraph::PEXTRA_MINIPAGE))
1255         {
1256                 lyxerr << "minipages in a row" << endl;
1257                 if (par->params().pextraStartMinipage()) {
1258                         lyxerr << "start new minipage" << endl;
1259                         // minipages in a row
1260                         par->previous()->next(0);
1261                         par->previous(0);
1262                                 
1263                         Paragraph * tmp = minipar;
1264                         while (tmp) {
1265                                 tmp->params().pextraType(0);
1266                                 tmp->params().pextraWidth(string());
1267                                 tmp->params().pextraWidthp(string());
1268                                 tmp->params().pextraAlignment(0);
1269                                 tmp->params().pextraHfill(false);
1270                                 tmp->params().pextraStartMinipage(false);
1271                                 tmp = tmp->next();
1272                         }
1273                         // create a new paragraph to insert the
1274                         // minipages in the following case
1275                         if (par->params().pextraStartMinipage() &&
1276                             !par->params().pextraHfill())
1277                         {
1278                                 Paragraph * p = new Paragraph;
1279                                 p->layout = 0;
1280                                 p->previous(parBeforeMinipage);
1281                                 parBeforeMinipage->next(p);
1282                                 p->next(0);
1283                                 p->params().depth(parBeforeMinipage->params().depth());
1284                                 parBeforeMinipage = p;
1285                         }
1286                         InsetMinipage * mini = new InsetMinipage;
1287                         mini->pos(static_cast<InsetMinipage::Position>(par->params().pextraAlignment()));
1288                         mini->pageWidth(LyXLength(par->params().pextraWidth()));
1289                         if (!par->params().pextraWidthp().empty()) {
1290                             lyxerr << "WP:" << mini->pageWidth().asString() << endl;
1291                             mini->pageWidth(LyXLength((par->params().pextraWidthp())+"%"));
1292                         }
1293                         Paragraph * op = mini->firstParagraph();
1294                         mini->inset.paragraph(par);
1295                         //
1296                         // and free the old ones!
1297                         //
1298                         while(op) {
1299                                 Paragraph * pp = op->next();
1300                                 delete op;
1301                                 op = pp;
1302                         }
1303                         // Insert the minipage last in the
1304                         // previous paragraph.
1305                         if (par->params().pextraHfill()) {
1306                                 parBeforeMinipage->insertChar
1307                                         (parBeforeMinipage->size(), Paragraph::META_HFILL);
1308                         }
1309                         parBeforeMinipage->insertInset
1310                                 (parBeforeMinipage->size(), mini);
1311                                 
1312                         minipar = par;
1313                 } else {
1314                         lyxerr << "new minipage par" << endl;
1315                         //nothing to do just continue reading
1316                 }
1317                         
1318         } else if (minipar && (minipar != par)) {
1319                 lyxerr << "last minipage par read" << endl;
1320                 // The last paragraph read was not part of a
1321                 // minipage but the par linked list is...
1322                 // So we need to remove the last par from the
1323                 // rest
1324                 if (par->previous())
1325                         par->previous()->next(0);
1326                 par->previous(parBeforeMinipage);
1327                 parBeforeMinipage->next(par);
1328                 Paragraph * tmp = minipar;
1329                 while (tmp) {
1330                         tmp->params().pextraType(0);
1331                         tmp->params().pextraWidth(string());
1332                         tmp->params().pextraWidthp(string());
1333                         tmp->params().pextraAlignment(0);
1334                         tmp->params().pextraHfill(false);
1335                         tmp->params().pextraStartMinipage(false);
1336                         tmp = tmp->next();
1337                 }
1338                 depth = parBeforeMinipage->params().depth();
1339                 // and set this depth on the par as it has not been set already
1340                 par->params().depth(depth);
1341                 minipar = parBeforeMinipage = 0;
1342         } else if (!minipar &&
1343                    (par->params().pextraType() == Paragraph::PEXTRA_MINIPAGE))
1344         {
1345                 // par is the first paragraph in a minipage
1346                 lyxerr << "begin minipage" << endl;
1347                 // To minimize problems for
1348                 // the users we will insert
1349                 // the first minipage in
1350                 // a sequence of minipages
1351                 // in its own paragraph.
1352                 Paragraph * p = new Paragraph;
1353                 p->layout = 0;
1354                 p->previous(par->previous());
1355                 p->next(0);
1356                 p->params().depth(depth);
1357                 par->params().depth(0);
1358                 depth = 0;
1359                 if (par->previous())
1360                         par->previous()->next(p);
1361                 par->previous(0);
1362                 parBeforeMinipage = p;
1363                 minipar = par;
1364                 if (!first_par || (first_par == par))
1365                         first_par = p;
1366
1367                 InsetMinipage * mini = new InsetMinipage;
1368                 mini->pos(static_cast<InsetMinipage::Position>(minipar->params().pextraAlignment()));
1369                 mini->pageWidth(LyXLength(minipar->params().pextraWidth()));
1370                 if (!par->params().pextraWidthp().empty()) {
1371                     lyxerr << "WP:" << mini->pageWidth().asString() << endl;
1372                     mini->pageWidth(LyXLength((par->params().pextraWidthp())+"%"));
1373                 }
1374                 mini->inset.paragraph(minipar);
1375                         
1376                 // Insert the minipage last in the
1377                 // previous paragraph.
1378                 if (minipar->params().pextraHfill()) {
1379                         parBeforeMinipage->insertChar
1380                                 (parBeforeMinipage->size(),Paragraph::META_HFILL);
1381                 }
1382                 parBeforeMinipage->insertInset
1383                         (parBeforeMinipage->size(), mini);
1384         }
1385         }
1386         // End of pextra_minipage compability
1387         --call_depth;
1388 #endif
1389 #endif
1390         return the_end_read;
1391 }
1392
1393 // needed to insert the selection
1394 void Buffer::insertStringAsLines(Paragraph *& par, pos_type & pos,
1395                                  LyXFont const & fn,string const & str) const
1396 {
1397         LyXLayout const & layout = textclasslist.Style(params.textclass, 
1398                                                        par->getLayout());
1399         LyXFont font = fn;
1400         
1401         (void)par->checkInsertChar(font);
1402         // insert the string, don't insert doublespace
1403         bool space_inserted = true;
1404         for(string::const_iterator cit = str.begin(); 
1405             cit != str.end(); ++cit) {
1406                 if (*cit == '\n') {
1407                         if (par->size() || layout.keepempty) { 
1408                                 par->breakParagraph(params, pos, 
1409                                                     layout.isEnvironment());
1410                                 par = par->next();
1411                                 pos = 0;
1412                                 space_inserted = true;
1413                         } else {
1414                                 continue;
1415                         }
1416                         // do not insert consecutive spaces if !free_spacing
1417                 } else if ((*cit == ' ' || *cit == '\t') &&
1418                            space_inserted && !layout.free_spacing &&
1419                                    !par->isFreeSpacing())
1420                 {
1421                         continue;
1422                 } else if (*cit == '\t') {
1423                         if (!layout.free_spacing && !par->isFreeSpacing()) {
1424                                 // tabs are like spaces here
1425                                 par->insertChar(pos, ' ', font);
1426                                 ++pos;
1427                                 space_inserted = true;
1428                         } else {
1429                                 const pos_type nb = 8 - pos % 8;
1430                                 for (pos_type a = 0; a < nb ; ++a) {
1431                                         par->insertChar(pos, ' ', font);
1432                                         ++pos;
1433                                 }
1434                                 space_inserted = true;
1435                         }
1436                 } else if (!IsPrintable(*cit)) {
1437                         // Ignore unprintables
1438                         continue;
1439                 } else {
1440                         // just insert the character
1441                         par->insertChar(pos, *cit, font);
1442                         ++pos;
1443                         space_inserted = (*cit == ' ');
1444                 }
1445
1446         }       
1447 }
1448
1449
1450 void Buffer::readInset(LyXLex & lex, Paragraph *& par,
1451                        int & pos, LyXFont & font)
1452 {
1453         // consistency check
1454         if (lex.getString() != "\\begin_inset") {
1455                 lyxerr << "Buffer::readInset: Consistency check failed."
1456                        << endl;
1457         }
1458         
1459         Inset * inset = 0;
1460
1461         lex.next();
1462         string const tmptok = lex.getString();
1463         last_inset_read = tmptok;
1464
1465         // test the different insets
1466         if (tmptok == "LatexCommand") {
1467                 InsetCommandParams inscmd;
1468                 inscmd.read(lex);
1469
1470                 string const cmdName = inscmd.getCmdName();
1471                 
1472                 // This strange command allows LyX to recognize "natbib" style
1473                 // citations: citet, citep, Citet etc.
1474                 if (compare_no_case(cmdName, "cite", 4) == 0) {
1475                         inset = new InsetCitation(inscmd);
1476                 } else if (cmdName == "bibitem") {
1477                         lex.printError("Wrong place for bibitem");
1478                         inset = new InsetBibKey(inscmd);
1479                 } else if (cmdName == "BibTeX") {
1480                         inset = new InsetBibtex(inscmd);
1481                 } else if (cmdName == "index") {
1482                         inset = new InsetIndex(inscmd);
1483                 } else if (cmdName == "include") {
1484                         inset = new InsetInclude(inscmd, *this);
1485                 } else if (cmdName == "label") {
1486                         inset = new InsetLabel(inscmd);
1487                 } else if (cmdName == "url"
1488                            || cmdName == "htmlurl") {
1489                         inset = new InsetUrl(inscmd);
1490                 } else if (cmdName == "ref"
1491                            || cmdName == "pageref"
1492                            || cmdName == "vref"
1493                            || cmdName == "vpageref"
1494                            || cmdName == "prettyref") {
1495                         if (!inscmd.getOptions().empty()
1496                             || !inscmd.getContents().empty()) {
1497                                 inset = new InsetRef(inscmd, *this);
1498                         }
1499                 } else if (cmdName == "tableofcontents") {
1500                         inset = new InsetTOC(inscmd);
1501                 } else if (cmdName == "listofalgorithms") {
1502                         inset = new InsetFloatList("algorithm");
1503                 } else if (cmdName == "listoffigures") {
1504                         inset = new InsetFloatList("figure");
1505                 } else if (cmdName == "listoftables") {
1506                         inset = new InsetFloatList("table");
1507                 } else if (cmdName == "printindex") {
1508                         inset = new InsetPrintIndex(inscmd);
1509                 } else if (cmdName == "lyxparent") {
1510                         inset = new InsetParent(inscmd, *this);
1511                 }
1512         } else {
1513                 bool alreadyread = false;
1514                 if (tmptok == "Quotes") {
1515                         inset = new InsetQuotes;
1516                 } else if (tmptok == "External") {
1517                         inset = new InsetExternal;
1518                 } else if (tmptok == "FormulaMacro") {
1519                         inset = new InsetFormulaMacro;
1520                 } else if (tmptok == "Formula") {
1521                         inset = new InsetFormula;
1522                 } else if (tmptok == "Figure") { // Backward compatibility
1523 //                      inset = new InsetFig(100, 100, *this);
1524                         inset = new InsetGraphics;
1525                 } else if (tmptok == "Graphics") {
1526                         inset = new InsetGraphics;
1527                 } else if (tmptok == "Info") {// backwards compatibility
1528                         inset = new InsetNote(this,
1529                                               lex.getLongString("\\end_inset"),
1530                                               true);
1531                         alreadyread = true;
1532                 } else if (tmptok == "Note") {
1533                         inset = new InsetNote;
1534                 } else if (tmptok == "Include") {
1535                         InsetCommandParams p("Include");
1536                         inset = new InsetInclude(p, *this);
1537                 } else if (tmptok == "ERT") {
1538                         inset = new InsetERT;
1539                 } else if (tmptok == "Tabular") {
1540                         inset = new InsetTabular(*this);
1541                 } else if (tmptok == "Text") {
1542                         inset = new InsetText;
1543                 } else if (tmptok == "Foot") {
1544                         inset = new InsetFoot;
1545                 } else if (tmptok == "Marginal") {
1546                         inset = new InsetMarginal;
1547                 } else if (tmptok == "Minipage") {
1548                         inset = new InsetMinipage;
1549                 } else if (tmptok == "Float") {
1550                         lex.next();
1551                         string tmptok = lex.getString();
1552                         inset = new InsetFloat(tmptok);
1553 #if 0
1554                 } else if (tmptok == "List") {
1555                         inset = new InsetList;
1556                 } else if (tmptok == "Theorem") {
1557                         inset = new InsetList;
1558 #endif
1559                 } else if (tmptok == "Caption") {
1560                         inset = new InsetCaption;
1561                 } else if (tmptok == "FloatList") {
1562                         inset = new InsetFloatList;
1563                 }
1564                 
1565                 if (inset && !alreadyread) inset->read(this, lex);
1566         }
1567         
1568         if (inset) {
1569                 par->insertInset(pos, inset, font);
1570                 ++pos;
1571         }
1572 }
1573
1574
1575 bool Buffer::readFile(LyXLex & lex, Paragraph * par)
1576 {
1577         if (lex.isOK()) {
1578                 lex.next();
1579                 string const token(lex.getString());
1580                 if (token == "\\lyxformat") { // the first token _must_ be...
1581                         lex.eatLine();
1582                         string tmp_format = lex.getString();
1583                         //lyxerr << "LyX Format: `" << tmp_format << "'" << endl;
1584                         // if present remove ".," from string.
1585                         string::size_type dot = tmp_format.find_first_of(".,");
1586                         //lyxerr << "           dot found at " << dot << endl;
1587                         if (dot != string::npos)
1588                                 tmp_format.erase(dot, 1);
1589                         file_format = strToInt(tmp_format);
1590                         if (file_format == LYX_FORMAT) {
1591                                 // current format
1592                         } else if (file_format > LYX_FORMAT) {
1593                                 // future format
1594                                 Alert::alert(_("Warning!"),
1595                                            _("LyX file format is newer that what"),
1596                                            _("is supported in this LyX version. Expect some problems."));
1597                                 
1598                         } else if (file_format < LYX_FORMAT) {
1599                                 // old formats
1600                                 if (file_format < 200) {
1601                                         Alert::alert(_("ERROR!"),
1602                                                    _("Old LyX file format found. "
1603                                                      "Use LyX 0.10.x to read this!"));
1604                                         return false;
1605                                 }
1606                         }
1607                         bool the_end = readLyXformat2(lex, par);
1608                         params.setPaperStuff();
1609                         // the_end was added in 213
1610                         if (file_format < 213)
1611                                 the_end = true;
1612
1613                         if (!the_end) {
1614                                 Alert::alert(_("Warning!"),
1615                                            _("Reading of document is not complete"),
1616                                            _("Maybe the document is truncated"));
1617                         }
1618                         return true;
1619                 } else { // "\\lyxformat" not found
1620                         Alert::alert(_("ERROR!"), _("Not a LyX file!"));
1621                 }
1622         } else
1623                 Alert::alert(_("ERROR!"), _("Unable to read file!"));
1624         return false;
1625 }
1626                     
1627
1628 // Should probably be moved to somewhere else: BufferView? LyXView?
1629 bool Buffer::save() const
1630 {
1631         // We don't need autosaves in the immediate future. (Asger)
1632         resetAutosaveTimers();
1633
1634         // make a backup
1635         string s;
1636         if (lyxrc.make_backup) {
1637                 s = fileName() + '~';
1638                 if (!lyxrc.backupdir_path.empty())
1639                         s = AddName(lyxrc.backupdir_path,
1640                                     subst(os::slashify_path(s),'/','!'));
1641
1642                 // Rename is the wrong way of making a backup,
1643                 // this is the correct way.
1644                 /* truss cp fil fil2:
1645                    lstat("LyXVC3.lyx", 0xEFFFF898)                 Err#2 ENOENT
1646                    stat("LyXVC.lyx", 0xEFFFF688)                   = 0
1647                    open("LyXVC.lyx", O_RDONLY)                     = 3
1648                    open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
1649                    fstat(4, 0xEFFFF508)                            = 0
1650                    fstat(3, 0xEFFFF508)                            = 0
1651                    read(3, " # T h i s   f i l e   w".., 8192)     = 5579
1652                    write(4, " # T h i s   f i l e   w".., 5579)    = 5579
1653                    read(3, 0xEFFFD4A0, 8192)                       = 0
1654                    close(4)                                        = 0
1655                    close(3)                                        = 0
1656                    chmod("LyXVC3.lyx", 0100644)                    = 0
1657                    lseek(0, 0, SEEK_CUR)                           = 46440
1658                    _exit(0)
1659                 */
1660
1661                 // Should probably have some more error checking here.
1662                 // Should be cleaned up in 0.13, at least a bit.
1663                 // Doing it this way, also makes the inodes stay the same.
1664                 // This is still not a very good solution, in particular we
1665                 // might loose the owner of the backup.
1666                 FileInfo finfo(fileName());
1667                 if (finfo.exist()) {
1668                         mode_t fmode = finfo.getMode();
1669                         struct utimbuf times = {
1670                                 finfo.getAccessTime(),
1671                                 finfo.getModificationTime() };
1672
1673                         ifstream ifs(fileName().c_str());
1674                         ofstream ofs(s.c_str(), ios::out|ios::trunc);
1675                         if (ifs && ofs) {
1676                                 ofs << ifs.rdbuf();
1677                                 ifs.close();
1678                                 ofs.close();
1679                                 ::chmod(s.c_str(), fmode);
1680                                 
1681                                 if (::utime(s.c_str(), &times)) {
1682                                         lyxerr << "utime error." << endl;
1683                                 }
1684                         } else {
1685                                 lyxerr << "LyX was not able to make "
1686                                         "backup copy. Beware." << endl;
1687                         }
1688                 }
1689         }
1690         
1691         if (writeFile(fileName(), false)) {
1692                 markLyxClean();
1693                 removeAutosaveFile(fileName());
1694         } else {
1695                 // Saving failed, so backup is not backup
1696                 if (lyxrc.make_backup) {
1697                         lyx::rename(s, fileName());
1698                 }
1699                 return false;
1700         }
1701         return true;
1702 }
1703
1704
1705 // Returns false if unsuccesful
1706 bool Buffer::writeFile(string const & fname, bool flag) const
1707 {
1708         // if flag is false writeFile will not create any GUI
1709         // warnings, only cerr.
1710         // Needed for autosave in background or panic save (Matthias 120496)
1711
1712         if (read_only && (fname == fileName())) {
1713                 // Here we should come with a question if we should
1714                 // perform the write anyway.
1715                 if (flag)
1716                         lyxerr << _("Error! Document is read-only: ")
1717                                << fname << endl;
1718                 else
1719                         Alert::alert(_("Error! Document is read-only: "),
1720                                    fname);
1721                 return false;
1722         }
1723
1724         FileInfo finfo(fname);
1725         if (finfo.exist() && !finfo.writable()) {
1726                 // Here we should come with a question if we should
1727                 // try to do the save anyway. (i.e. do a chmod first)
1728                 if (flag)
1729                         lyxerr << _("Error! Cannot write file: ")
1730                                << fname << endl;
1731                 else
1732                         Alert::err_alert(_("Error! Cannot write file: "),
1733                                      fname);
1734                 return false;
1735         }
1736
1737         ofstream ofs(fname.c_str());
1738         if (!ofs) {
1739                 if (flag)
1740                         lyxerr << _("Error! Cannot open file: ")
1741                                << fname << endl;
1742                 else
1743                         Alert::err_alert(_("Error! Cannot open file: "),
1744                                      fname);
1745                 return false;
1746         }
1747
1748 #ifdef HAVE_LOCALE
1749         // Use the standard "C" locale for file output.
1750         ofs.imbue(std::locale::classic());
1751 #endif
1752
1753         // The top of the file should not be written by params.
1754
1755         // write out a comment in the top of the file
1756         ofs << '#' << lyx_docversion 
1757             << " created this file. For more info see http://www.lyx.org/\n"
1758             << "\\lyxformat " << LYX_FORMAT << "\n";
1759
1760         // now write out the buffer paramters.
1761         params.writeFile(ofs);
1762
1763         Paragraph::depth_type depth = 0;
1764
1765         // this will write out all the paragraphs
1766         // using recursive descent.
1767         paragraph->writeFile(this, ofs, params, depth);
1768
1769         // Write marker that shows file is complete
1770         ofs << "\n\\the_end" << endl;
1771
1772         ofs.close();
1773
1774         // how to check if close went ok?
1775         // Following is an attempt... (BE 20001011)
1776         
1777         // good() returns false if any error occured, including some
1778         //        formatting error.
1779         // bad()  returns true if something bad happened in the buffer,
1780         //        which should include file system full errors.
1781
1782         bool status = true;
1783         if (!ofs.good()) {
1784                 status = false;
1785 #if 0
1786                 if (ofs.bad()) {
1787                         lyxerr << "Buffer::writeFile: BAD ERROR!" << endl;
1788                 } else {
1789                         lyxerr << "Buffer::writeFile: NOT SO BAD ERROR!"
1790                                << endl;
1791                 }
1792 #endif
1793         }
1794         
1795         return status;
1796 }
1797
1798
1799 string const Buffer::asciiParagraph(Paragraph const * par,
1800                                     unsigned int linelen,
1801                                     bool noparbreak) const
1802 {
1803         ostringstream buffer;
1804         ostringstream word;
1805         Paragraph::depth_type depth = 0;
1806         int ltype = 0;
1807         Paragraph::depth_type ltype_depth = 0;
1808         string::size_type currlinelen = 0;
1809         bool ref_printed = false;
1810 //      if (!par->previous()) {
1811 #if 0
1812         // begins or ends a deeper area ?
1813         if (depth != par->params().depth()) {
1814                 if (par->params().depth() > depth) {
1815                         while (par->params().depth() > depth) {
1816                                 ++depth;
1817                         }
1818                 } else {
1819                         while (par->params().depth() < depth) {
1820                                 --depth;
1821                         }
1822                 }
1823         }
1824 #else
1825         depth = par->params().depth();
1826 #endif
1827                 
1828         // First write the layout
1829         string const tmp = textclasslist.NameOfLayout(params.textclass, par->layout);
1830         if (tmp == "Itemize") {
1831                 ltype = 1;
1832                 ltype_depth = depth + 1;
1833         } else if (tmp == "Enumerate") {
1834                 ltype = 2;
1835                 ltype_depth = depth + 1;
1836         } else if (contains(tmp, "ection")) {
1837                 ltype = 3;
1838                 ltype_depth = depth + 1;
1839         } else if (contains(tmp, "aragraph")) {
1840                 ltype = 4;
1841                 ltype_depth = depth + 1;
1842         } else if (tmp == "Description") {
1843                 ltype = 5;
1844                 ltype_depth = depth + 1;
1845         } else if (tmp == "Abstract") {
1846                 ltype = 6;
1847                 ltype_depth = 0;
1848         } else if (tmp == "Bibliography") {
1849                 ltype = 7;
1850                 ltype_depth = 0;
1851         } else {
1852                 ltype = 0;
1853                 ltype_depth = 0;
1854         }
1855                 
1856         /* maybe some vertical spaces */ 
1857                 
1858         /* the labelwidthstring used in lists */ 
1859                 
1860         /* some lines? */ 
1861                 
1862         /* some pagebreaks? */ 
1863                 
1864         /* noindent ? */ 
1865                 
1866         /* what about the alignment */ 
1867 //      } else {
1868 //              lyxerr << "Should this ever happen?" << endl;
1869 //      }
1870
1871         // linelen <= 0 is special and means we don't have pargraph breaks
1872         if (!noparbreak) {
1873                 if (linelen > 0)
1874                         buffer << "\n\n";
1875                 for (Paragraph::depth_type j = 0; j < depth; ++j)
1876                         buffer << "  ";
1877                 currlinelen = depth * 2;
1878                 //--
1879                 // we should probably change to the paragraph language in the
1880                 // gettext here (if possible) so that strings are outputted in
1881                 // the correct language! (20012712 Jug)
1882                 //--    
1883                 switch (ltype) {
1884                 case 0: // Standard
1885                 case 4: // (Sub)Paragraph
1886                 case 5: // Description
1887                         break;
1888                 case 6: // Abstract
1889                         if (linelen > 0)
1890                                 buffer << _("Abstract") << "\n\n";
1891                         else
1892                                 buffer << _("Abstract: ");
1893                         break;
1894                 case 7: // Bibliography
1895                         if (!ref_printed) {
1896                                 if (linelen > 0)
1897                                         buffer << _("References") << "\n\n";
1898                                 else
1899                                         buffer << _("References: ");
1900                                 ref_printed = true;
1901                         }
1902                         break;
1903                 default:
1904                         buffer << par->params().labelString() << " ";
1905                         break;
1906                 }
1907         }
1908         string s = buffer.str();
1909         if (s.rfind('\n') != string::npos) {
1910                 string dummy;
1911                 s = rsplit(buffer.str().c_str(), dummy, '\n');
1912         }
1913         currlinelen = s.length();
1914         if (!currlinelen) {
1915                 for (Paragraph::depth_type j = 0; j < depth; ++j)
1916                         buffer << "  ";
1917                 currlinelen = depth * 2;
1918                 if (ltype_depth > depth) {
1919                         for (Paragraph::depth_type j = ltype_depth;
1920                                  j > depth; --j)
1921                         {
1922                                 buffer << "  ";
1923                         }
1924                         currlinelen += (ltype_depth-depth)*2;
1925                 }
1926         }
1927         // this is to change the linebreak to do it by word a bit more intelligent
1928         // hopefully! (only in the case where we have a max linelenght!) (Jug)
1929         for (pos_type i = 0; i < par->size(); ++i) {
1930                 char c = par->getUChar(params, i);
1931                 switch (c) {
1932                 case Paragraph::META_INSET:
1933                 {
1934                         Inset const * inset = par->getInset(i);
1935                         if (inset) {
1936                                 if (linelen > 0) {
1937                                         buffer << word.str();
1938                                         word.str("");
1939                                 }
1940                                 if (inset->ascii(this, buffer, linelen)) {
1941                                         // to be sure it breaks paragraph
1942                                         currlinelen += linelen;
1943                                 }
1944 #if 0
1945                                 else {
1946                                         string dummy;
1947                                         string const s =
1948                                                 rsplit(buffer.str().c_str(),
1949                                                        dummy, '\n');
1950                                         currlinelen = s.length();
1951                                 }
1952 #endif
1953                         }
1954                 }
1955                 break;
1956                 
1957                 case Paragraph::META_NEWLINE:
1958                         if (linelen > 0) {
1959                                 buffer << word.str() << "\n";
1960                                 word.str("");
1961                                 for (Paragraph::depth_type j = 0; 
1962                                      j < depth; ++j)
1963                                         buffer << "  ";
1964                                 currlinelen = depth * 2;
1965                                 if (ltype_depth > depth) {
1966                                         for (Paragraph::depth_type j = ltype_depth;
1967                                                  j > depth; --j)
1968                                                 buffer << "  ";
1969                                         currlinelen += (ltype_depth - depth) * 2;
1970                                 }
1971                         }
1972                         break;
1973                         
1974                 case Paragraph::META_HFILL:
1975                         buffer << word.str() << "\t";
1976                         currlinelen += word.str().length() + 1;
1977                         word.str("");
1978                         break;
1979
1980                 default:
1981                         if (c == ' ') {
1982                                 buffer << word.str() << ' ';
1983                                 currlinelen += word.str().length() + 1;
1984                                 word.str("");
1985                         } else {
1986                                 if (c != '\0') {
1987                                         word << c;
1988                                 } else {
1989                                         lyxerr[Debug::INFO] <<
1990                                                 "writeAsciiFile: NULL char in structure." << endl;
1991                                 }
1992                                 if ((linelen > 0) &&
1993                                         (currlinelen+word.str().length()) > linelen)
1994                                 {
1995                                         buffer << "\n";
1996                                         for (Paragraph::depth_type j = 0; j < depth; ++j)
1997                                                 buffer << "  ";
1998                                         currlinelen = depth * 2;
1999                                         if (ltype_depth > depth) {
2000                                                 for (Paragraph::depth_type j = ltype_depth;
2001                                                          j > depth; --j)
2002                                                 {
2003                                                         buffer << "  ";
2004                                                 }
2005                                                 currlinelen += (ltype_depth-depth)*2;
2006                                         }
2007                                 }
2008                         }
2009                         break;
2010                 }
2011         }
2012         buffer << word.str();
2013         return buffer.str().c_str();
2014 }
2015
2016
2017 void Buffer::writeFileAscii(string const & fname, int linelen) 
2018 {
2019         ofstream ofs(fname.c_str());
2020         if (!ofs) {
2021                 Alert::err_alert(_("Error: Cannot write file:"), fname);
2022                 return;
2023         }
2024         writeFileAscii(ofs, linelen);
2025 }
2026
2027
2028 void Buffer::writeFileAscii(ostream & ofs, int linelen) 
2029 {
2030         Paragraph * par = paragraph;
2031         while (par) {
2032                 ofs << asciiParagraph(par, linelen, par->previous() == 0);
2033                 par = par->next();
2034         }
2035         ofs << "\n";
2036 }
2037
2038
2039 bool use_babel;
2040
2041
2042 void Buffer::makeLaTeXFile(string const & fname, 
2043                            string const & original_path,
2044                            bool nice, bool only_body)
2045 {
2046         lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl;
2047         
2048         niceFile = nice; // this will be used by Insetincludes.
2049
2050         tex_code_break_column = lyxrc.ascii_linelen;
2051
2052         LyXTextClass const & tclass =
2053                 textclasslist.TextClass(params.textclass);
2054
2055         ofstream ofs(fname.c_str());
2056         if (!ofs) {
2057                 Alert::err_alert(_("Error: Cannot open file: "), fname);
2058                 return;
2059         }
2060         
2061         // validate the buffer.
2062         lyxerr[Debug::LATEX] << "  Validating buffer..." << endl;
2063         LaTeXFeatures features(params, tclass.numLayouts());
2064         validate(features);
2065         lyxerr[Debug::LATEX] << "  Buffer validation done." << endl;
2066         
2067         texrow.reset();
2068         // The starting paragraph of the coming rows is the 
2069         // first paragraph of the document. (Asger)
2070         texrow.start(paragraph, 0);
2071
2072         if (!only_body && nice) {
2073                 ofs << "%% " << lyx_docversion << " created this file.  "
2074                         "For more info, see http://www.lyx.org/.\n"
2075                         "%% Do not edit unless you really know what "
2076                         "you are doing.\n";
2077                 texrow.newline();
2078                 texrow.newline();
2079         }
2080         lyxerr[Debug::INFO] << "lyx header finished" << endl;
2081         // There are a few differences between nice LaTeX and usual files:
2082         // usual is \batchmode and has a 
2083         // special input@path to allow the including of figures
2084         // with either \input or \includegraphics (what figinsets do).
2085         // batchmode is not set if there is a tex_code_break_column.
2086         // In this case somebody is interested in the generated LaTeX,
2087         // so this is OK. input@path is set when the actual parameter
2088         // original_path is set. This is done for usual tex-file, but not
2089         // for nice-latex-file. (Matthias 250696)
2090         if (!only_body) {
2091                 if (!nice) {
2092                         // code for usual, NOT nice-latex-file
2093                         ofs << "\\batchmode\n"; // changed
2094                         // from \nonstopmode
2095                         texrow.newline();
2096                 }
2097                 if (!original_path.empty()) {
2098                         ofs << "\\makeatletter\n"
2099                             << "\\def\\input@path{{"
2100                             << os::external_path(original_path) << "/}}\n"
2101                             << "\\makeatother\n";
2102                         texrow.newline();
2103                         texrow.newline();
2104                         texrow.newline();
2105                 }
2106                 
2107                 ofs << "\\documentclass";
2108                 
2109                 ostringstream options; // the document class options.
2110                 
2111                 if (tokenPos(tclass.opt_fontsize(),
2112                              '|', params.fontsize) >= 0) {
2113                         // only write if existing in list (and not default)
2114                         options << params.fontsize << "pt,";
2115                 }
2116                 
2117                 
2118                 if (!params.use_geometry &&
2119                     (params.paperpackage == BufferParams::PACKAGE_NONE)) {
2120                         switch (params.papersize) {
2121                         case BufferParams::PAPER_A4PAPER:
2122                                 options << "a4paper,";
2123                                 break;
2124                         case BufferParams::PAPER_USLETTER:
2125                                 options << "letterpaper,";
2126                                 break;
2127                         case BufferParams::PAPER_A5PAPER:
2128                                 options << "a5paper,";
2129                                 break;
2130                         case BufferParams::PAPER_B5PAPER:
2131                                 options << "b5paper,";
2132                                 break;
2133                         case BufferParams::PAPER_EXECUTIVEPAPER:
2134                                 options << "executivepaper,";
2135                                 break;
2136                         case BufferParams::PAPER_LEGALPAPER:
2137                                 options << "legalpaper,";
2138                                 break;
2139                         }
2140                 }
2141
2142                 // if needed
2143                 if (params.sides != tclass.sides()) {
2144                         switch (params.sides) {
2145                         case LyXTextClass::OneSide:
2146                                 options << "oneside,";
2147                                 break;
2148                         case LyXTextClass::TwoSides:
2149                                 options << "twoside,";
2150                                 break;
2151                         }
2152                 }
2153
2154                 // if needed
2155                 if (params.columns != tclass.columns()) {
2156                         if (params.columns == 2)
2157                                 options << "twocolumn,";
2158                         else
2159                                 options << "onecolumn,";
2160                 }
2161
2162                 if (!params.use_geometry 
2163                     && params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
2164                         options << "landscape,";
2165                 
2166                 // language should be a parameter to \documentclass
2167                 use_babel = false;
2168                 ostringstream language_options;
2169                 if (params.language->babel() == "hebrew"
2170                     && default_language->babel() != "hebrew")
2171                          // This seems necessary
2172                         features.useLanguage(default_language);
2173
2174                 if (lyxrc.language_use_babel ||
2175                     params.language->lang() != lyxrc.default_language ||
2176                     !features.hasLanguages()) {
2177                         use_babel = true;
2178                         language_options << features.getLanguages();
2179                         language_options << params.language->babel();
2180                         if (lyxrc.language_global_options)
2181                                 options << language_options.str() << ',';
2182                 }
2183
2184                 // the user-defined options
2185                 if (!params.options.empty()) {
2186                         options << params.options << ',';
2187                 }
2188
2189                 string strOptions(options.str().c_str());
2190                 if (!strOptions.empty()) {
2191                         strOptions = strip(strOptions, ',');
2192                         ofs << '[' << strOptions << ']';
2193                 }
2194                 
2195                 ofs << '{'
2196                     << textclasslist.LatexnameOfClass(params.textclass)
2197                     << "}\n";
2198                 texrow.newline();
2199                 // end of \documentclass defs
2200                 
2201                 // font selection must be done before loading fontenc.sty
2202                 // The ae package is not needed when using OT1 font encoding.
2203                 if (params.fonts != "default" &&
2204                     (params.fonts != "ae" || lyxrc.fontenc != "default")) {
2205                         ofs << "\\usepackage{" << params.fonts << "}\n";
2206                         texrow.newline();
2207                         if (params.fonts == "ae") {
2208                                 ofs << "\\usepackage{aecompl}\n";
2209                                 texrow.newline();
2210                         }
2211                 }
2212                 // this one is not per buffer
2213                 if (lyxrc.fontenc != "default") {
2214                         ofs << "\\usepackage[" << lyxrc.fontenc
2215                             << "]{fontenc}\n";
2216                         texrow.newline();
2217                 }
2218
2219                 if (params.inputenc == "auto") {
2220                         string const doc_encoding =
2221                                 params.language->encoding()->LatexName();
2222
2223                         // Create a list with all the input encodings used 
2224                         // in the document
2225                         set<string> encodings = features.getEncodingSet(doc_encoding);
2226
2227                         ofs << "\\usepackage[";
2228                         std::copy(encodings.begin(), encodings.end(),
2229                                   std::ostream_iterator<string>(ofs, ","));
2230                         ofs << doc_encoding << "]{inputenc}\n";
2231                         texrow.newline();
2232                 } else if (params.inputenc != "default") {
2233                         ofs << "\\usepackage[" << params.inputenc
2234                             << "]{inputenc}\n";
2235                         texrow.newline();
2236                 }
2237
2238                 // At the very beginning the text parameters.
2239                 if (params.paperpackage != BufferParams::PACKAGE_NONE) {
2240                         switch (params.paperpackage) {
2241                         case BufferParams::PACKAGE_A4:
2242                                 ofs << "\\usepackage{a4}\n";
2243                                 texrow.newline();
2244                                 break;
2245                         case BufferParams::PACKAGE_A4WIDE:
2246                                 ofs << "\\usepackage{a4wide}\n";
2247                                 texrow.newline();
2248                                 break;
2249                         case BufferParams::PACKAGE_WIDEMARGINSA4:
2250                                 ofs << "\\usepackage[widemargins]{a4}\n";
2251                                 texrow.newline();
2252                                 break;
2253                         }
2254                 }
2255                 if (params.use_geometry) {
2256                         ofs << "\\usepackage{geometry}\n";
2257                         texrow.newline();
2258                         ofs << "\\geometry{verbose";
2259                         if (params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
2260                                 ofs << ",landscape";
2261                         switch (params.papersize2) {
2262                         case BufferParams::VM_PAPER_CUSTOM:
2263                                 if (!params.paperwidth.empty())
2264                                         ofs << ",paperwidth="
2265                                             << params.paperwidth;
2266                                 if (!params.paperheight.empty())
2267                                         ofs << ",paperheight="
2268                                             << params.paperheight;
2269                                 break;
2270                         case BufferParams::VM_PAPER_USLETTER:
2271                                 ofs << ",letterpaper";
2272                                 break;
2273                         case BufferParams::VM_PAPER_USLEGAL:
2274                                 ofs << ",legalpaper";
2275                                 break;
2276                         case BufferParams::VM_PAPER_USEXECUTIVE:
2277                                 ofs << ",executivepaper";
2278                                 break;
2279                         case BufferParams::VM_PAPER_A3:
2280                                 ofs << ",a3paper";
2281                                 break;
2282                         case BufferParams::VM_PAPER_A4:
2283                                 ofs << ",a4paper";
2284                                 break;
2285                         case BufferParams::VM_PAPER_A5:
2286                                 ofs << ",a5paper";
2287                                 break;
2288                         case BufferParams::VM_PAPER_B3:
2289                                 ofs << ",b3paper";
2290                                 break;
2291                         case BufferParams::VM_PAPER_B4:
2292                                 ofs << ",b4paper";
2293                                 break;
2294                         case BufferParams::VM_PAPER_B5:
2295                                 ofs << ",b5paper";
2296                                 break;
2297                         default:
2298                                 // default papersize ie BufferParams::VM_PAPER_DEFAULT
2299                                 switch (lyxrc.default_papersize) {
2300                                 case BufferParams::PAPER_DEFAULT: // keep compiler happy
2301                                 case BufferParams::PAPER_USLETTER:
2302                                         ofs << ",letterpaper";
2303                                         break;
2304                                 case BufferParams::PAPER_LEGALPAPER:
2305                                         ofs << ",legalpaper";
2306                                         break;
2307                                 case BufferParams::PAPER_EXECUTIVEPAPER:
2308                                         ofs << ",executivepaper";
2309                                         break;
2310                                 case BufferParams::PAPER_A3PAPER:
2311                                         ofs << ",a3paper";
2312                                         break;
2313                                 case BufferParams::PAPER_A4PAPER:
2314                                         ofs << ",a4paper";
2315                                         break;
2316                                 case BufferParams::PAPER_A5PAPER:
2317                                         ofs << ",a5paper";
2318                                         break;
2319                                 case BufferParams::PAPER_B5PAPER:
2320                                         ofs << ",b5paper";
2321                                         break;
2322                                 }
2323                         }
2324                         if (!params.topmargin.empty())
2325                                 ofs << ",tmargin=" << params.topmargin;
2326                         if (!params.bottommargin.empty())
2327                                 ofs << ",bmargin=" << params.bottommargin;
2328                         if (!params.leftmargin.empty())
2329                                 ofs << ",lmargin=" << params.leftmargin;
2330                         if (!params.rightmargin.empty())
2331                                 ofs << ",rmargin=" << params.rightmargin;
2332                         if (!params.headheight.empty())
2333                                 ofs << ",headheight=" << params.headheight;
2334                         if (!params.headsep.empty())
2335                                 ofs << ",headsep=" << params.headsep;
2336                         if (!params.footskip.empty())
2337                                 ofs << ",footskip=" << params.footskip;
2338                         ofs << "}\n";
2339                         texrow.newline();
2340                 }
2341
2342                 if (tokenPos(tclass.opt_pagestyle(),
2343                              '|', params.pagestyle) >= 0) {
2344                         if (params.pagestyle == "fancy") {
2345                                 ofs << "\\usepackage{fancyhdr}\n";
2346                                 texrow.newline();
2347                         }
2348                         ofs << "\\pagestyle{" << params.pagestyle << "}\n";
2349                         texrow.newline();
2350                 }
2351
2352                 if (params.secnumdepth != tclass.secnumdepth()) {
2353                         ofs << "\\setcounter{secnumdepth}{"
2354                             << params.secnumdepth
2355                             << "}\n";
2356                         texrow.newline();
2357                 }
2358                 if (params.tocdepth != tclass.tocdepth()) {
2359                         ofs << "\\setcounter{tocdepth}{"
2360                             << params.tocdepth
2361                             << "}\n";
2362                         texrow.newline();
2363                 }
2364                 
2365                 if (params.paragraph_separation) {
2366                         switch (params.defskip.kind()) {
2367                         case VSpace::SMALLSKIP: 
2368                                 ofs << "\\setlength\\parskip{\\smallskipamount}\n";
2369                                 break;
2370                         case VSpace::MEDSKIP:
2371                                 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2372                                 break;
2373                         case VSpace::BIGSKIP:
2374                                 ofs << "\\setlength\\parskip{\\bigskipamount}\n";
2375                                 break;
2376                         case VSpace::LENGTH:
2377                                 ofs << "\\setlength\\parskip{"
2378                                     << params.defskip.length().asLatexString()
2379                                     << "}\n";
2380                                 break;
2381                         default: // should never happen // Then delete it.
2382                                 ofs << "\\setlength\\parskip{\\medskipamount}\n";
2383                                 break;
2384                         }
2385                         texrow.newline();
2386                         
2387                         ofs << "\\setlength\\parindent{0pt}\n";
2388                         texrow.newline();
2389                 }
2390
2391                 // Now insert the LyX specific LaTeX commands...
2392
2393                 // The optional packages;
2394                 string preamble(features.getPackages());
2395
2396                 // this might be useful...
2397                 preamble += "\n\\makeatletter\n";
2398
2399                 // Some macros LyX will need
2400                 string tmppreamble(features.getMacros());
2401
2402                 if (!tmppreamble.empty()) {
2403                         preamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2404                                 "LyX specific LaTeX commands.\n"
2405                                 + tmppreamble + '\n';
2406                 }
2407
2408                 // the text class specific preamble 
2409                 tmppreamble = features.getTClassPreamble();
2410                 if (!tmppreamble.empty()) {
2411                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2412                                 "Textclass specific LaTeX commands.\n"
2413                                 + tmppreamble + '\n';
2414                 }
2415
2416                 /* the user-defined preamble */
2417                 if (!params.preamble.empty()) {
2418                         preamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2419                                 "User specified LaTeX commands.\n"
2420                                 + params.preamble + '\n';
2421                 }
2422
2423                 preamble += "\\makeatother\n";
2424
2425                 // Itemize bullet settings need to be last in case the user
2426                 // defines their own bullets that use a package included
2427                 // in the user-defined preamble -- ARRae
2428                 // Actually it has to be done much later than that
2429                 // since some packages like frenchb make modifications
2430                 // at \begin{document} time -- JMarc 
2431                 string bullets_def;
2432                 for (int i = 0; i < 4; ++i) {
2433                         if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
2434                                 if (bullets_def.empty())
2435                                         bullets_def="\\AtBeginDocument{\n";
2436                                 bullets_def += "  \\renewcommand{\\labelitemi";
2437                                 switch (i) {
2438                                 // `i' is one less than the item to modify
2439                                 case 0:
2440                                         break;
2441                                 case 1:
2442                                         bullets_def += 'i';
2443                                         break;
2444                                 case 2:
2445                                         bullets_def += "ii";
2446                                         break;
2447                                 case 3:
2448                                         bullets_def += 'v';
2449                                         break;
2450                                 }
2451                                 bullets_def += "}{" + 
2452                                   params.user_defined_bullets[i].getText() 
2453                                   + "}\n";
2454                         }
2455                 }
2456
2457                 if (!bullets_def.empty())
2458                   preamble += bullets_def + "}\n\n";
2459
2460                 int const nlines =
2461                         int(lyx::count(preamble.begin(), preamble.end(), '\n'));
2462                 for (int j = 0; j != nlines; ++j) {
2463                         texrow.newline();
2464                 }
2465
2466                 ofs << preamble;
2467
2468                 // We try to load babel late, in case it interferes
2469                 // with other packages.
2470                 if (use_babel) {
2471                         string tmp = lyxrc.language_package;
2472                         if (!lyxrc.language_global_options
2473                             && tmp == "\\usepackage{babel}")
2474                                 tmp = string("\\usepackage[") +
2475                                         language_options.str().c_str() +
2476                                         "]{babel}";
2477                         ofs << tmp << "\n";
2478                         texrow.newline();
2479                 }
2480
2481                 // make the body.
2482                 ofs << "\\begin{document}\n";
2483                 texrow.newline();
2484         } // only_body
2485         lyxerr[Debug::INFO] << "preamble finished, now the body." << endl;
2486
2487         if (!lyxrc.language_auto_begin) {
2488                 ofs << subst(lyxrc.language_command_begin, "$$lang",
2489                              params.language->babel())
2490                     << endl;
2491                 texrow.newline();
2492         }
2493         
2494         latexParagraphs(ofs, paragraph, 0, texrow);
2495
2496         // add this just in case after all the paragraphs
2497         ofs << endl;
2498         texrow.newline();
2499
2500         if (!lyxrc.language_auto_end) {
2501                 ofs << subst(lyxrc.language_command_end, "$$lang",
2502                              params.language->babel())
2503                     << endl;
2504                 texrow.newline();
2505         }
2506
2507         if (!only_body) {
2508                 ofs << "\\end{document}\n";
2509                 texrow.newline();
2510         
2511                 lyxerr[Debug::LATEX] << "makeLaTeXFile...done" << endl;
2512         } else {
2513                 lyxerr[Debug::LATEX] << "LaTeXFile for inclusion made."
2514                                      << endl;
2515         }
2516
2517         // Just to be sure. (Asger)
2518         texrow.newline();
2519
2520         // tex_code_break_column's value is used to decide
2521         // if we are in batchmode or not (within mathed_write()
2522         // in math_write.C) so we must set it to a non-zero
2523         // value when we leave otherwise we save incorrect .lyx files.
2524         tex_code_break_column = lyxrc.ascii_linelen;
2525
2526         ofs.close();
2527         if (ofs.fail()) {
2528                 lyxerr << "File was not closed properly." << endl;
2529         }
2530         
2531         lyxerr[Debug::INFO] << "Finished making latex file." << endl;
2532         lyxerr[Debug::INFO] << "Row count was " << texrow.rows()-1 << "." << endl;
2533 }
2534
2535
2536 //
2537 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
2538 //
2539 void Buffer::latexParagraphs(ostream & ofs, Paragraph * par,
2540                              Paragraph * endpar, TexRow & texrow) const
2541 {
2542         bool was_title = false;
2543         bool already_title = false;
2544
2545         // if only_body
2546         while (par != endpar) {
2547                 Inset * in = par->inInset();
2548                 // well we have to check if we are in an inset with unlimited
2549                 // lenght (all in one row) if that is true then we don't allow
2550                 // any special options in the paragraph and also we don't allow
2551                 // any environment other then "Standard" to be valid!
2552                 if ((in == 0) || !in->forceDefaultParagraphs(in)) {
2553                         LyXLayout const & layout =
2554                                 textclasslist.Style(params.textclass, par->layout);
2555                         
2556                         if (layout.intitle) {
2557                                 if (already_title) {
2558                                         lyxerr <<"Error in latexParagraphs: You"
2559                                                 " should not mix title layouts"
2560                                                 " with normal ones." << endl;
2561                                 } else
2562                                         was_title = true;
2563                         } else if (was_title && !already_title) {
2564                                 ofs << "\\maketitle\n";
2565                                 texrow.newline();
2566                                 already_title = true;
2567                                 was_title = false;                  
2568                         }
2569                         
2570                         if (layout.isEnvironment()) {
2571                                 par = par->TeXEnvironment(this, params, ofs, texrow);
2572                         } else {
2573                                 par = par->TeXOnePar(this, params, ofs, texrow, false);
2574                         }
2575                 } else {
2576                         par = par->TeXOnePar(this, params, ofs, texrow, false);
2577                 }
2578         }
2579         // It might be that we only have a title in this document
2580         if (was_title && !already_title) {
2581                 ofs << "\\maketitle\n";
2582                 texrow.newline();
2583         }
2584 }
2585
2586
2587 bool Buffer::isLatex() const
2588 {
2589         return textclasslist.TextClass(params.textclass).outputType() == LATEX;
2590 }
2591
2592
2593 bool Buffer::isLinuxDoc() const
2594 {
2595         return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC;
2596 }
2597
2598
2599 bool Buffer::isLiterate() const
2600 {
2601         return textclasslist.TextClass(params.textclass).outputType() == LITERATE;
2602 }
2603
2604
2605 bool Buffer::isDocBook() const
2606 {
2607         return textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2608 }
2609
2610
2611 bool Buffer::isSGML() const
2612 {
2613         return textclasslist.TextClass(params.textclass).outputType() == LINUXDOC ||
2614                textclasslist.TextClass(params.textclass).outputType() == DOCBOOK;
2615 }
2616
2617
2618 void Buffer::sgmlOpenTag(ostream & os, Paragraph::depth_type depth,
2619                          string const & latexname) const
2620 {
2621         if (!latexname.empty() && latexname != "!-- --")
2622                 //os << "<!-- " << depth << " -->" << "<" << latexname << ">";
2623                 os << string(depth, ' ') << "<" << latexname << ">\n";
2624 }
2625
2626
2627 void Buffer::sgmlCloseTag(ostream & os, Paragraph::depth_type depth,
2628                           string const & latexname) const
2629 {
2630         if (!latexname.empty() && latexname != "!-- --")
2631                 //os << "<!-- " << depth << " -->" << "</" << latexname << ">\n";
2632                 os << string(depth, ' ') << "</" << latexname << ">\n";
2633 }
2634
2635
2636 void Buffer::makeLinuxDocFile(string const & fname, bool nice, bool body_only)
2637 {
2638         ofstream ofs(fname.c_str());
2639
2640         if (!ofs) {
2641                 Alert::alert(_("LYX_ERROR:"), _("Cannot write file"), fname);
2642                 return;
2643         }
2644
2645         niceFile = nice; // this will be used by included files.
2646
2647         LyXTextClass const & tclass =
2648                 textclasslist.TextClass(params.textclass);
2649
2650         LaTeXFeatures features(params, tclass.numLayouts());
2651         validate(features);
2652
2653         texrow.reset();
2654
2655         string top_element = textclasslist.LatexnameOfClass(params.textclass);
2656
2657         if (!body_only) {
2658                 ofs << "<!doctype linuxdoc system";
2659
2660                 string preamble = params.preamble;
2661                 preamble += features.getIncludedFiles(fname);
2662                 preamble += features.getLyXSGMLEntities();
2663
2664                 if (!preamble.empty()) {
2665                         ofs << " [ " << preamble << " ]";
2666                 }
2667                 ofs << ">\n\n";
2668
2669                 if (params.options.empty())
2670                         sgmlOpenTag(ofs, 0, top_element);
2671                 else {
2672                         string top = top_element;
2673                         top += " ";
2674                         top += params.options;
2675                         sgmlOpenTag(ofs, 0, top);
2676                 }
2677         }
2678
2679         ofs << "<!-- "  << lyx_docversion
2680             << " created this file. For more info see http://www.lyx.org/"
2681             << " -->\n";
2682
2683         Paragraph::depth_type depth = 0; // paragraph depth
2684         Paragraph * par = paragraph;
2685         string item_name;
2686         vector<string> environment_stack(5);
2687
2688         while (par) {
2689                 LyXLayout const & style =
2690                         textclasslist.Style(params.textclass,
2691                                             par->layout);
2692
2693                 // treat <toc> as a special case for compatibility with old code
2694                 if (par->isInset(0)) {
2695                         Inset * inset = par->getInset(0);
2696                         Inset::Code lyx_code = inset->lyxCode();
2697                         if (lyx_code == Inset::TOC_CODE) {
2698                                 string const temp = "toc";
2699                                 sgmlOpenTag(ofs, depth, temp);
2700
2701                                 par = par->next();
2702                                 continue;
2703                         }
2704                 }
2705
2706                 // environment tag closing
2707                 for (; depth > par->params().depth(); --depth) {
2708                         sgmlCloseTag(ofs, depth, environment_stack[depth]);
2709                         environment_stack[depth].erase();
2710                 }
2711
2712                 // write opening SGML tags
2713                 switch (style.latextype) {
2714                 case LATEX_PARAGRAPH:
2715                         if (depth == par->params().depth() 
2716                            && !environment_stack[depth].empty()) {
2717                                 sgmlCloseTag(ofs, depth, environment_stack[depth]);
2718                                 environment_stack[depth].erase();
2719                                 if (depth) 
2720                                         --depth;
2721                                 else
2722                                         ofs << "</p>";
2723                         }
2724                         sgmlOpenTag(ofs, depth, style.latexname());
2725                         break;
2726
2727                 case LATEX_COMMAND:
2728                         if (depth!= 0)
2729                                 sgmlError(par, 0,
2730                                           _("Error : Wrong depth for"
2731                                             " LatexType Command.\n"));
2732
2733                         if (!environment_stack[depth].empty()) {
2734                                 sgmlCloseTag(ofs, depth,
2735                                              environment_stack[depth]);
2736                                 ofs << "</p>";
2737                         }
2738
2739                         environment_stack[depth].erase();
2740                         sgmlOpenTag(ofs, depth, style.latexname());
2741                         break;
2742
2743                 case LATEX_ENVIRONMENT:
2744                 case LATEX_ITEM_ENVIRONMENT:
2745                         if (depth == par->params().depth() 
2746                             && environment_stack[depth] != style.latexname()) {
2747                                 sgmlCloseTag(ofs, depth,
2748                                              environment_stack[depth]);
2749                                 environment_stack[depth].erase();
2750                         }
2751                         if (depth < par->params().depth()) {
2752                                depth = par->params().depth();
2753                                environment_stack[depth].erase();
2754                         }
2755                         if (environment_stack[depth] != style.latexname()) {
2756                                 if (depth == 0) {
2757                                         sgmlOpenTag(ofs, depth, "p");
2758                                 }
2759                                 sgmlOpenTag(ofs, depth, style.latexname());
2760
2761                                 if (environment_stack.size() == depth + 1)
2762                                         environment_stack.push_back("!-- --");
2763                                 environment_stack[depth] = style.latexname();
2764                         }
2765
2766                         if (style.latexparam() == "CDATA")
2767                                 ofs << "<![CDATA[";
2768
2769                         if (style.latextype == LATEX_ENVIRONMENT) break;
2770
2771                         if (style.labeltype == LABEL_MANUAL)
2772                                 item_name = "tag";
2773                         else
2774                                 item_name = "item";
2775
2776                         sgmlOpenTag(ofs, depth + 1, item_name);
2777                         break;
2778                 default:
2779                         sgmlOpenTag(ofs, depth, style.latexname());
2780                         break;
2781                 }
2782
2783                 simpleLinuxDocOnePar(ofs, par, depth);
2784
2785                 par = par->next();
2786
2787                 ofs << "\n";
2788                 // write closing SGML tags
2789                 switch (style.latextype) {
2790                 case LATEX_COMMAND:
2791                         break;
2792                 case LATEX_ENVIRONMENT:
2793                 case LATEX_ITEM_ENVIRONMENT:
2794                         if (style.latexparam() == "CDATA")
2795                                 ofs << "]]>";
2796                         break;
2797                 default:
2798                         sgmlCloseTag(ofs, depth, style.latexname());
2799                         break;
2800                 }
2801         }
2802    
2803         // Close open tags
2804         for (int i=depth; i >= 0; --i)
2805                 sgmlCloseTag(ofs, depth, environment_stack[i]);
2806
2807         if (!body_only) {
2808                 ofs << "\n\n";
2809                 sgmlCloseTag(ofs, 0, top_element);
2810         }
2811
2812         ofs.close();
2813         // How to check for successful close
2814 }
2815
2816
2817 // checks, if newcol chars should be put into this line
2818 // writes newline, if necessary.
2819 namespace {
2820
2821 void sgmlLineBreak(ostream & os, string::size_type & colcount,
2822                           string::size_type newcol)
2823 {
2824         colcount += newcol;
2825         if (colcount > lyxrc.ascii_linelen) {
2826                 os << "\n";
2827                 colcount = newcol; // assume write after this call
2828         }
2829 }
2830
2831 enum PAR_TAG {
2832         NONE=0,
2833         TT = 1,
2834         SF = 2,
2835         BF = 4,
2836         IT = 8,
2837         SL = 16,
2838         EM = 32
2839 };
2840
2841
2842 string tag_name(PAR_TAG const & pt) {
2843         switch (pt) {
2844         case NONE: return "!-- --";
2845         case TT: return "tt";
2846         case SF: return "sf";
2847         case BF: return "bf";
2848         case IT: return "it";
2849         case SL: return "sl";
2850         case EM: return "em";
2851         }
2852         return "";
2853 }
2854
2855
2856 inline
2857 void operator|=(PAR_TAG & p1, PAR_TAG const & p2)
2858 {
2859         p1 = static_cast<PAR_TAG>(p1 | p2);
2860 }
2861
2862
2863 inline
2864 void reset(PAR_TAG & p1, PAR_TAG const & p2)
2865 {
2866         p1 = static_cast<PAR_TAG>(p1 & ~p2);
2867 }
2868
2869 } // namespace anon
2870
2871
2872 // Handle internal paragraph parsing -- layout already processed.
2873 void Buffer::simpleLinuxDocOnePar(ostream & os,
2874                                   Paragraph * par, 
2875                                   Paragraph::depth_type /*depth*/)
2876 {
2877         LyXLayout const & style = textclasslist.Style(params.textclass,
2878                                                       par->getLayout());
2879         string::size_type char_line_count = 5;     // Heuristic choice ;-) 
2880
2881         // gets paragraph main font
2882         LyXFont font_old;
2883         bool desc_on;
2884         if (style.labeltype == LABEL_MANUAL) {
2885                 font_old = style.labelfont;
2886                 desc_on = true;
2887         } else {
2888                 font_old = style.font;
2889                 desc_on = false;
2890         }
2891
2892         LyXFont::FONT_FAMILY family_type = LyXFont::ROMAN_FAMILY;
2893         LyXFont::FONT_SERIES series_type = LyXFont::MEDIUM_SERIES;
2894         LyXFont::FONT_SHAPE  shape_type  = LyXFont::UP_SHAPE;
2895         bool is_em = false;
2896
2897         stack<PAR_TAG> tag_state;
2898         // parsing main loop
2899         for (pos_type i = 0; i < par->size(); ++i) {
2900
2901                 PAR_TAG tag_close = NONE;
2902                 list < PAR_TAG > tag_open;
2903
2904                 LyXFont const font = par->getFont(params, i);
2905
2906                 if (font_old.family() != font.family()) {
2907                         switch (family_type) {
2908                         case LyXFont::SANS_FAMILY:
2909                                 tag_close |= SF;
2910                                 break;
2911                         case LyXFont::TYPEWRITER_FAMILY:
2912                                 tag_close |= TT;
2913                                 break;
2914                         default:
2915                                 break;
2916                         }
2917
2918                         family_type = font.family();
2919
2920                         switch (family_type) {
2921                         case LyXFont::SANS_FAMILY:
2922                                 tag_open.push_back(SF);
2923                                 break;
2924                         case LyXFont::TYPEWRITER_FAMILY:
2925                                 tag_open.push_back(TT);
2926                                 break;
2927                         default:
2928                                 break;
2929                         }
2930                 }
2931
2932                 if (font_old.series() != font.series()) {
2933                         switch (series_type) {
2934                         case LyXFont::BOLD_SERIES:
2935                                 tag_close |= BF;
2936                                 break;
2937                         default:
2938                                 break;
2939                         }
2940
2941                         series_type = font.series();
2942
2943                         switch (series_type) {
2944                         case LyXFont::BOLD_SERIES:
2945                                 tag_open.push_back(BF);
2946                                 break;
2947                         default:
2948                                 break;
2949                         }
2950
2951                 }
2952
2953                 if (font_old.shape() != font.shape()) {
2954                         switch (shape_type) {
2955                         case LyXFont::ITALIC_SHAPE:
2956                                 tag_close |= IT;
2957                                 break;
2958                         case LyXFont::SLANTED_SHAPE:
2959                                 tag_close |= SL;
2960                                 break;
2961                         default:
2962                                 break;
2963                         }
2964
2965                         shape_type = font.shape();
2966
2967                         switch (shape_type) {
2968                         case LyXFont::ITALIC_SHAPE:
2969                                 tag_open.push_back(IT);
2970                                 break;
2971                         case LyXFont::SLANTED_SHAPE:
2972                                 tag_open.push_back(SL);
2973                                 break;
2974                         default:
2975                                 break;
2976                         }
2977                 }
2978                 // handle <em> tag
2979                 if (font_old.emph() != font.emph()) {
2980                         if (font.emph() == LyXFont::ON) {
2981                                 tag_open.push_back(EM);
2982                                 is_em = true;
2983                         }
2984                         else if (is_em) {
2985                                 tag_close |= EM;
2986                                 is_em = false;
2987                         }
2988                 }
2989
2990                 list < PAR_TAG > temp;
2991                 while (!tag_state.empty() && tag_close) {
2992                         PAR_TAG k =  tag_state.top();
2993                         tag_state.pop();
2994                         os << "</" << tag_name(k) << ">";
2995                         if (tag_close & k)
2996                                 reset(tag_close,k);
2997                         else
2998                                 temp.push_back(k);
2999                 }
3000
3001                 for(list< PAR_TAG >::const_iterator j = temp.begin();
3002                     j != temp.end(); ++j) {
3003                         tag_state.push(*j);
3004                         os << "<" << tag_name(*j) << ">";
3005                 }
3006
3007                 for(list< PAR_TAG >::const_iterator j = tag_open.begin();
3008                     j != tag_open.end(); ++j) {
3009                         tag_state.push(*j);
3010                         os << "<" << tag_name(*j) << ">";
3011                 }
3012
3013                 char c = par->getChar(i);
3014
3015                 if (c == Paragraph::META_INSET) {
3016                         Inset * inset = par->getInset(i);
3017                         inset->linuxdoc(this, os);
3018                         font_old = font;
3019                         continue;
3020                 }
3021
3022                 if (style.latexparam() == "CDATA") {
3023                         // "TeX"-Mode on == > SGML-Mode on.
3024                         if (c != '\0')
3025                                 os << c;
3026                         ++char_line_count;
3027                 } else {
3028                         string sgml_string;
3029                         if (par->sgmlConvertChar(c, sgml_string)
3030                             && !style.free_spacing && !par->isFreeSpacing())
3031                         { 
3032                                 // in freespacing mode, spaces are
3033                                 // non-breaking characters
3034                                 if (desc_on) {// if char is ' ' then...
3035
3036                                         ++char_line_count;
3037                                         sgmlLineBreak(os, char_line_count, 6);
3038                                         os << "</tag>";
3039                                         desc_on = false;
3040                                 } else  {
3041                                         sgmlLineBreak(os, char_line_count, 1);
3042                                         os << c;
3043                                 }
3044                         } else {
3045                                 os << sgml_string;
3046                                 char_line_count += sgml_string.length();
3047                         }
3048                 }
3049                 font_old = font;
3050         }
3051
3052         while (!tag_state.empty()) {
3053                 os << "</" << tag_name(tag_state.top()) << ">";
3054                 tag_state.pop();
3055         }
3056
3057         // resets description flag correctly
3058         if (desc_on) {
3059                 // <tag> not closed...
3060                 sgmlLineBreak(os, char_line_count, 6);
3061                 os << "</tag>";
3062         }
3063 }
3064
3065
3066 // Print an error message.
3067 void Buffer::sgmlError(Paragraph * par, int pos,
3068                        string const & message) const
3069 {
3070         // insert an error marker in text
3071         InsetError * new_inset = new InsetError(message);
3072         par->insertInset(pos, new_inset, LyXFont(LyXFont::ALL_INHERIT, 
3073                                                  params.language));
3074 }
3075
3076
3077 void Buffer::makeDocBookFile(string const & fname, bool nice, bool only_body)
3078 {
3079         ofstream ofs(fname.c_str());
3080         if (!ofs) {
3081                 Alert::alert(_("LYX_ERROR:"), _("Cannot write file"), fname);
3082                 return;
3083         }
3084
3085         Paragraph * par = paragraph;
3086
3087         niceFile = nice; // this will be used by Insetincludes.
3088
3089         LyXTextClass const & tclass =
3090                 textclasslist.TextClass(params.textclass);
3091
3092         LaTeXFeatures features(params, tclass.numLayouts());
3093         validate(features);
3094    
3095         texrow.reset();
3096
3097         string top_element = textclasslist.LatexnameOfClass(params.textclass);
3098
3099         if (!only_body) {
3100                 ofs << "<!DOCTYPE " << top_element
3101                     << "  PUBLIC \"-//OASIS//DTD DocBook V4.1//EN\"";
3102
3103                 string preamble = params.preamble;
3104                 preamble += features.getIncludedFiles(fname);
3105                 preamble += features.getLyXSGMLEntities();
3106
3107                 if (!preamble.empty()) {
3108                         ofs << "\n [ " << preamble << " ]";
3109                 }
3110                 ofs << ">\n\n";
3111         }
3112
3113         string top = top_element;       
3114         top += " lang=\"";
3115         top += params.language->code();
3116         top += "\"";
3117
3118         if (!params.options.empty()) {
3119                 top += " ";
3120                 top += params.options;
3121         }
3122         sgmlOpenTag(ofs, 0, top);
3123
3124         ofs << "<!-- DocBook file was created by " << lyx_docversion
3125             << "\n  See http://www.lyx.org/ for more information -->\n";
3126
3127         vector<string> environment_stack(10);
3128         vector<string> environment_inner(10);
3129         vector<string> command_stack(10);
3130
3131         bool command_flag = false;
3132         Paragraph::depth_type command_depth = 0;
3133         Paragraph::depth_type command_base = 0;
3134         Paragraph::depth_type cmd_depth = 0;
3135         Paragraph::depth_type depth = 0; // paragraph depth
3136
3137         string item_name;
3138         string command_name;
3139
3140         while (par) {
3141                 string sgmlparam;
3142                 string c_depth;
3143                 string c_params;
3144                 int desc_on = 0; // description mode
3145
3146                 LyXLayout const & style =
3147                         textclasslist.Style(params.textclass,
3148                                             par->layout);
3149
3150                 // environment tag closing
3151                 for (; depth > par->params().depth(); --depth) {
3152                         if (environment_inner[depth] != "!-- --") {
3153                                 item_name = "listitem";
3154                                 sgmlCloseTag(ofs, command_depth + depth,
3155                                              item_name);
3156                                 if (environment_inner[depth] == "varlistentry")
3157                                         sgmlCloseTag(ofs, depth+command_depth,
3158                                                      environment_inner[depth]);
3159                         }
3160                         sgmlCloseTag(ofs, depth + command_depth,
3161                                      environment_stack[depth]);
3162                         environment_stack[depth].erase();
3163                         environment_inner[depth].erase();
3164                 }
3165
3166                 if (depth == par->params().depth()
3167                    && environment_stack[depth] != style.latexname()
3168                    && !environment_stack[depth].empty()) {
3169                         if (environment_inner[depth] != "!-- --") {
3170                                 item_name= "listitem";
3171                                 sgmlCloseTag(ofs, command_depth+depth,
3172                                              item_name);
3173                                 if (environment_inner[depth] == "varlistentry")
3174                                         sgmlCloseTag(ofs,
3175                                                      depth + command_depth,
3176                                                      environment_inner[depth]);
3177                         }
3178                         
3179                         sgmlCloseTag(ofs, depth + command_depth,
3180                                      environment_stack[depth]);
3181                         
3182                         environment_stack[depth].erase();
3183                         environment_inner[depth].erase();
3184                 }
3185
3186                 // Write opening SGML tags.
3187                 switch (style.latextype) {
3188                 case LATEX_PARAGRAPH:
3189                         sgmlOpenTag(ofs, depth + command_depth,
3190                                     style.latexname());
3191                         break;
3192
3193                 case LATEX_COMMAND:
3194                         if (depth != 0)
3195                                 sgmlError(par, 0,
3196                                           _("Error : Wrong depth for "
3197                                             "LatexType Command.\n"));
3198                         
3199                         command_name = style.latexname();
3200                         
3201                         sgmlparam = style.latexparam();
3202                         c_params = split(sgmlparam, c_depth,'|');
3203                         
3204                         cmd_depth = lyx::atoi(c_depth);
3205                         
3206                         if (command_flag) {
3207                                 if (cmd_depth < command_base) {
3208                                         for (Paragraph::depth_type j = command_depth; j >= command_base; --j)
3209                                                 sgmlCloseTag(ofs, j, command_stack[j]);
3210                                         command_depth = command_base = cmd_depth;
3211                                 } else if (cmd_depth <= command_depth) {
3212                                         for (int j = command_depth; j >= int(cmd_depth); --j)
3213                                                 sgmlCloseTag(ofs, j, command_stack[j]);
3214                                         command_depth = cmd_depth;
3215                                 } else
3216                                         command_depth = cmd_depth;
3217                         } else {
3218                                 command_depth = command_base = cmd_depth;
3219                                 command_flag = true;
3220                         }
3221                         if (command_stack.size() == command_depth + 1)
3222                                 command_stack.push_back(string());
3223                         command_stack[command_depth] = command_name;
3224
3225                         // treat label as a special case for
3226                         // more WYSIWYM handling.
3227                         // This is a hack while paragraphs can't have
3228                         // attributes, like id in this case.
3229                         if (par->isInset(0)) {
3230                                 Inset * inset = par->getInset(0);
3231                                 Inset::Code lyx_code = inset->lyxCode();
3232                                 if (lyx_code == Inset::LABEL_CODE) {
3233                                         command_name += " id=\"";
3234                                         command_name += (static_cast<InsetCommand *>(inset))->getContents();
3235                                         command_name += "\"";
3236                                         desc_on = 3;
3237                                 }
3238                         }
3239
3240                         sgmlOpenTag(ofs, depth + command_depth, command_name);
3241                         if (c_params.empty())
3242                                 item_name = "title";
3243                         else
3244                                 item_name = c_params;
3245                         sgmlOpenTag(ofs, depth + 1 + command_depth, item_name);
3246                         break;
3247
3248                 case LATEX_ENVIRONMENT:
3249                 case LATEX_ITEM_ENVIRONMENT:
3250                         if (depth < par->params().depth()) {
3251                                 depth = par->params().depth();
3252                                 environment_stack[depth].erase();
3253                         }
3254
3255                         if (environment_stack[depth] != style.latexname()) {
3256                                 if (environment_stack.size() == depth + 1) {
3257                                         environment_stack.push_back("!-- --");
3258                                         environment_inner.push_back("!-- --");
3259                                 }
3260                                 environment_stack[depth] = style.latexname();
3261                                 environment_inner[depth] = "!-- --";
3262                                 sgmlOpenTag(ofs, depth + command_depth,
3263                                             environment_stack[depth]);
3264                         } else {
3265                                 if (environment_inner[depth] != "!-- --") {
3266                                         item_name= "listitem";
3267                                         sgmlCloseTag(ofs,
3268                                                      command_depth + depth,
3269                                                      item_name);
3270                                         if (environment_inner[depth] == "varlistentry")
3271                                                 sgmlCloseTag(ofs,
3272                                                              depth + command_depth,
3273                                                              environment_inner[depth]);
3274                                 }
3275                         }
3276                         
3277                         if (style.latextype == LATEX_ENVIRONMENT) {
3278                                 if (!style.latexparam().empty()) {
3279                                         if (style.latexparam() == "CDATA")
3280                                                 ofs << "<![CDATA[";
3281                                         else
3282                                                 sgmlOpenTag(ofs, depth + command_depth,
3283                                                             style.latexparam());
3284                                 }
3285                                 break;
3286                         }
3287
3288                         desc_on = (style.labeltype == LABEL_MANUAL);
3289
3290                         if (desc_on)
3291                                 environment_inner[depth]= "varlistentry";
3292                         else
3293                                 environment_inner[depth]= "listitem";
3294
3295                         sgmlOpenTag(ofs, depth + 1 + command_depth,
3296                                     environment_inner[depth]);
3297
3298                         if (desc_on) {
3299                                 item_name= "term";
3300                                 sgmlOpenTag(ofs, depth + 1 + command_depth,
3301                                             item_name);
3302                         } else {
3303                                 item_name= "para";
3304                                 sgmlOpenTag(ofs, depth + 1 + command_depth,
3305                                             item_name);
3306                         }
3307                         break;
3308                 default:
3309                         sgmlOpenTag(ofs, depth + command_depth,
3310                                     style.latexname());
3311                         break;
3312                 }
3313
3314                 simpleDocBookOnePar(ofs, par, desc_on, depth+1+command_depth);
3315                 par = par->next();
3316
3317                 string end_tag;
3318                 // write closing SGML tags
3319                 switch (style.latextype) {
3320                 case LATEX_COMMAND:
3321                         if (c_params.empty())
3322                                 end_tag = "title";
3323                         else
3324                                 end_tag = c_params;
3325                         sgmlCloseTag(ofs, depth + command_depth, end_tag);
3326                         break;
3327                 case LATEX_ENVIRONMENT:
3328                         if (!style.latexparam().empty()) {
3329                                 if (style.latexparam() == "CDATA")
3330                                         ofs << "]]>";
3331                                 else
3332                                         sgmlCloseTag(ofs, depth + command_depth,
3333                                                      style.latexparam());
3334                         }
3335                         break;
3336                 case LATEX_ITEM_ENVIRONMENT:
3337                         if (desc_on == 1) break;
3338                         end_tag= "para";
3339                         sgmlCloseTag(ofs, depth + 1 + command_depth, end_tag);
3340                         break;
3341                 case LATEX_PARAGRAPH:
3342                         sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3343                         break;
3344                 default:
3345                         sgmlCloseTag(ofs, depth + command_depth, style.latexname());
3346                         break;
3347                 }
3348         }
3349
3350         // Close open tags
3351         for (int d = depth; d >= 0; --d) {
3352                 if (!environment_stack[depth].empty()) {
3353                         if (environment_inner[depth] != "!-- --") {
3354                                 item_name = "listitem";
3355                                 sgmlCloseTag(ofs, command_depth + depth,
3356                                              item_name);
3357                                if (environment_inner[depth] == "varlistentry")
3358                                        sgmlCloseTag(ofs, depth + command_depth,
3359                                                     environment_inner[depth]);
3360                         }
3361                         
3362                         sgmlCloseTag(ofs, depth + command_depth,
3363                                      environment_stack[depth]);
3364                 }
3365         }
3366         
3367         for (int j = command_depth; j >= 0 ; --j)
3368                 if (!command_stack[j].empty())
3369                         sgmlCloseTag(ofs, j, command_stack[j]);
3370
3371         ofs << "\n\n";
3372         sgmlCloseTag(ofs, 0, top_element);
3373
3374         ofs.close();
3375         // How to check for successful close
3376 }
3377
3378
3379 void Buffer::simpleDocBookOnePar(ostream & os,
3380                                  Paragraph * par, int & desc_on,
3381                                  Paragraph::depth_type depth) const
3382 {
3383         bool emph_flag = false;
3384
3385         LyXLayout const & style = textclasslist.Style(params.textclass,
3386                                                       par->getLayout());
3387
3388         LyXFont font_old = style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
3389
3390         int char_line_count = depth;
3391         //if (!style.free_spacing)
3392         //      os << string(depth,' ');
3393
3394         // parsing main loop
3395         for (pos_type i = 0; i < par->size(); ++i) {
3396                 LyXFont font = par->getFont(params, i);
3397
3398                 // handle <emphasis> tag
3399                 if (font_old.emph() != font.emph()) {
3400                         if (font.emph() == LyXFont::ON) {
3401                                 os << "<emphasis>";
3402                                 emph_flag = true;
3403                         } else if (i) {
3404                                 os << "</emphasis>";
3405                                 emph_flag = false;
3406                         }
3407                 }
3408       
3409
3410                 if (par->isInset(i)) {
3411                         Inset * inset = par->getInset(i);
3412                         // don't print the inset in position 0 if desc_on == 3 (label)
3413                         if ( i || desc_on != 3) {
3414                                 if(style.latexparam() == "CDATA")
3415                                         os << "]]>";
3416                                 inset->docbook(this, os);
3417                                 if(style.latexparam() == "CDATA")
3418                                         os << "<![CDATA[";
3419                         }
3420                 } else {
3421                         char c = par->getChar(i);
3422                         string sgml_string;
3423                         par->sgmlConvertChar(c, sgml_string);
3424
3425                         if (style.pass_thru) {
3426                                 os << c;
3427                         } else if (style.free_spacing || par->isFreeSpacing() || c != ' ') {
3428                                         os << sgml_string;
3429                         } else if (desc_on ==1) {
3430                                 ++char_line_count;
3431                                 os << "\n</term><listitem><para>";
3432                                 desc_on = 2;
3433                         } else {
3434                                 os << ' ';
3435                         }
3436                 }
3437                 font_old = font;
3438         }
3439
3440         if (emph_flag) {
3441                 os << "</emphasis>";
3442         }
3443         
3444         // resets description flag correctly
3445         if (desc_on == 1) {
3446                 // <term> not closed...
3447                 os << "</term>";
3448         }
3449         if (style.free_spacing) os << '\n';
3450 }
3451
3452
3453 // This should be enabled when the Chktex class is implemented. (Asger)
3454 // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?)
3455 // Other flags: -wall -v0 -x
3456 int Buffer::runChktex()
3457 {
3458         if (!users->text) return 0;
3459
3460         users->owner()->prohibitInput();
3461
3462         // get LaTeX-Filename
3463         string const name = getLatexName();
3464         string path = filePath();
3465
3466         string const org_path = path;
3467         if (lyxrc.use_tempdir || !IsDirWriteable(path)) {
3468                 path = tmppath;  
3469         }
3470
3471         Path p(path); // path to LaTeX file
3472         users->owner()->message(_("Running chktex..."));
3473
3474         // Remove all error insets
3475         bool const removedErrorInsets = users->removeAutoInsets();
3476
3477         // Generate the LaTeX file if neccessary
3478         makeLaTeXFile(name, org_path, false);
3479
3480         TeXErrors terr;
3481         Chktex chktex(lyxrc.chktex_command, name, filePath());
3482         int res = chktex.run(terr); // run chktex
3483
3484         if (res == -1) {
3485                 Alert::alert(_("chktex did not work!"),
3486                            _("Could not run with file:"), name);
3487         } else if (res > 0) {
3488                 // Insert all errors as errors boxes
3489                 users->insertErrors(terr);
3490         }
3491
3492         // if we removed error insets before we ran chktex or if we inserted
3493         // error insets after we ran chktex, this must be run:
3494         if (removedErrorInsets || res) {
3495                 users->redraw();
3496                 users->fitCursor();
3497         }
3498         users->owner()->allowInput();
3499
3500         return res;
3501 }
3502
3503
3504 void Buffer::validate(LaTeXFeatures & features) const
3505 {
3506         Paragraph * par = paragraph;
3507         LyXTextClass const & tclass = 
3508                 textclasslist.TextClass(params.textclass);
3509     
3510         // AMS Style is at document level
3511         if (params.use_amsmath || tclass.provides(LyXTextClass::amsmath))
3512                 features.require("amsmath");
3513     
3514         while (par) {
3515                 // We don't use "lyxerr.debug" because of speed. (Asger)
3516                 if (lyxerr.debugging(Debug::LATEX))
3517                         lyxerr << "Paragraph: " <<  par << endl;
3518
3519                 // Now just follow the list of paragraphs and run
3520                 // validate on each of them.
3521                 par->validate(features);
3522
3523                 // and then the next paragraph
3524                 par = par->next();
3525         }
3526
3527         // the bullet shapes are buffer level not paragraph level
3528         // so they are tested here
3529         for (int i = 0; i < 4; ++i) {
3530                 if (params.user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
3531                         int const font = params.user_defined_bullets[i].getFont();
3532                         if (font == 0) {
3533                                 int const c = params
3534                                         .user_defined_bullets[i]
3535                                         .getCharacter();
3536                                 if (c == 16
3537                                    || c == 17
3538                                    || c == 25
3539                                    || c == 26
3540                                    || c == 31) {
3541                                         features.require("latexsym");
3542                                 }
3543                         } else if (font == 1) {
3544                                 features.require("amssymb");
3545                         } else if ((font >= 2 && font <= 5)) {
3546                                 features.require("pifont");
3547                         }
3548                 }
3549         }
3550         
3551         if (lyxerr.debugging(Debug::LATEX)) {
3552                 features.showStruct();
3553         }
3554 }
3555
3556
3557 // This function should be in Buffer because it's a buffer's property (ale)
3558 string const Buffer::getIncludeonlyList(char delim)
3559 {
3560         string lst;
3561         for (inset_iterator it = inset_iterator_begin();
3562             it != inset_iterator_end(); ++it) {
3563                 if ((*it)->lyxCode() == Inset::INCLUDE_CODE) {
3564                         InsetInclude * insetinc = 
3565                                 static_cast<InsetInclude *>(*it);
3566                         if (insetinc->isIncludeOnly()) {
3567                                 if (!lst.empty())
3568                                         lst += delim;
3569                                 lst += insetinc->getRelFileBaseName();
3570                         }
3571                 }
3572         }
3573         lyxerr[Debug::INFO] << "Includeonly(" << lst << ')' << endl;
3574         return lst;
3575 }
3576
3577
3578 vector<string> const Buffer::getLabelList()
3579 {
3580         /// if this is a child document and the parent is already loaded
3581         /// Use the parent's list instead  [ale990407]
3582         if (!params.parentname.empty()
3583             && bufferlist.exists(params.parentname)) {
3584                 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3585                 if (tmp)
3586                         return tmp->getLabelList();
3587         }
3588
3589         vector<string> label_list;
3590         for (inset_iterator it = inset_iterator_begin();
3591              it != inset_iterator_end(); ++it) {
3592                 vector<string> const l = (*it)->getLabelList();
3593                 label_list.insert(label_list.end(), l.begin(), l.end());
3594         }
3595         return label_list;
3596 }
3597
3598
3599 Buffer::Lists const Buffer::getLists() const
3600 {
3601         Lists l;
3602         Paragraph * par = paragraph;
3603
3604 #if 1
3605         std::pair<bool, textclass_type> const tmp =
3606                 textclasslist.NumberOfLayout(params.textclass, "Caption");
3607         bool const found = tmp.first;
3608         textclass_type const cap = tmp.second;
3609         
3610 #else
3611         // This is the prefered way to to this, but boost::tie can break
3612         // some compilers
3613         bool found;
3614         textclass_type cap;
3615         boost::tie(found, cap) = textclasslist
3616                 .NumberOfLayout(params.textclass, "Caption");
3617 #endif
3618
3619         while (par) {
3620                 char const labeltype =
3621                         textclasslist.Style(params.textclass, 
3622                                             par->getLayout()).labeltype;
3623                 
3624                 if (labeltype >= LABEL_COUNTER_CHAPTER
3625                     && labeltype <= LABEL_COUNTER_CHAPTER + params.tocdepth) {
3626                                 // insert this into the table of contents
3627                         SingleList & item = l["TOC"];
3628                         int depth = max(0,
3629                                         labeltype - 
3630                                         textclasslist.TextClass(params.textclass).maxcounter());
3631                         item.push_back(TocItem(par, depth, par->asString(this, true)));
3632                 }
3633                 // For each paragrph, traverse its insets and look for
3634                 // FLOAT_CODE
3635                 
3636                 if (found) {
3637                         Paragraph::inset_iterator it =
3638                                 par->inset_iterator_begin();
3639                         Paragraph::inset_iterator end =
3640                                 par->inset_iterator_end();
3641                         
3642                         for (; it != end; ++it) {
3643                                 if ((*it)->lyxCode() == Inset::FLOAT_CODE) {
3644                                         InsetFloat * il =
3645                                                 static_cast<InsetFloat*>(*it);
3646                                         
3647                                         string const type = il->type();
3648                                         
3649                                         // Now find the caption in the float...
3650                                         // We now tranverse the paragraphs of
3651                                         // the inset...
3652                                         Paragraph * tmp = il->inset.paragraph();
3653                                         while (tmp) {
3654                                                 if (tmp->layout == cap) {
3655                                                         SingleList & item = l[type];
3656                                                         string const str =
3657                                                                 tostr(item.size()+1) + ". " + tmp->asString(this, false);
3658                                                         item.push_back(TocItem(tmp, 0 , str));
3659                                                 }
3660                                                 tmp = tmp->next();
3661                                         }
3662                                 }
3663                         }
3664                 } else {
3665                         lyxerr << "caption not found" << endl;
3666                 }
3667                 
3668                 par = par->next();
3669         }
3670         return l;
3671 }
3672
3673
3674 // This is also a buffer property (ale)
3675 vector<pair<string, string> > const Buffer::getBibkeyList()
3676 {
3677         /// if this is a child document and the parent is already loaded
3678         /// Use the parent's list instead  [ale990412]
3679         if (!params.parentname.empty() && bufferlist.exists(params.parentname)) {
3680                 Buffer * tmp = bufferlist.getBuffer(params.parentname);
3681                 if (tmp)
3682                         return tmp->getBibkeyList();
3683         }
3684
3685         vector<pair<string, string> > keys;
3686         Paragraph * par = paragraph;
3687         while (par) {
3688                 if (par->bibkey)
3689                         keys.push_back(pair<string, string>(par->bibkey->getContents(),
3690                                                            par->asString(this, false)));
3691                 par = par->next();
3692         }
3693
3694         // Might be either using bibtex or a child has bibliography
3695         if (keys.empty()) {
3696                 for (inset_iterator it = inset_iterator_begin();
3697                         it != inset_iterator_end(); ++it) {
3698                         // Search for Bibtex or Include inset
3699                         if ((*it)->lyxCode() == Inset::BIBTEX_CODE) {
3700                                 vector<pair<string,string> > tmp =
3701                                         static_cast<InsetBibtex*>(*it)->getKeys(this);
3702                                 keys.insert(keys.end(), tmp.begin(), tmp.end());
3703                         } else if ((*it)->lyxCode() == Inset::INCLUDE_CODE) {
3704                                 vector<pair<string,string> > const tmp =
3705                                         static_cast<InsetInclude*>(*it)->getKeys();
3706                                 keys.insert(keys.end(), tmp.begin(), tmp.end());
3707                         }
3708                 }
3709         }
3710  
3711         return keys;
3712 }
3713
3714
3715 bool Buffer::isDepClean(string const & name) const
3716 {
3717         DEPCLEAN * item = dep_clean;
3718         while (item && item->master != name)
3719                 item = item->next;
3720         if (!item) return true;
3721         return item->clean;
3722 }
3723
3724
3725 void Buffer::markDepClean(string const & name)
3726 {
3727         if (!dep_clean) {
3728                 dep_clean = new DEPCLEAN;
3729                 dep_clean->clean = true;
3730                 dep_clean->master = name;
3731                 dep_clean->next = 0;
3732         } else {
3733                 DEPCLEAN * item = dep_clean;
3734                 while (item && item->master != name)
3735                         item = item->next;
3736                 if (item) {
3737                         item->clean = true;
3738                 } else {
3739                         item = new DEPCLEAN;
3740                         item->clean = true;
3741                         item->master = name;
3742                         item->next = 0;
3743                 }
3744         }
3745 }
3746
3747
3748 bool Buffer::dispatch(string const & command)
3749 {
3750         // Split command string into command and argument
3751         string cmd;
3752         string line = frontStrip(command);
3753         string const arg = strip(frontStrip(split(line, cmd, ' ')));
3754
3755         return dispatch(lyxaction.LookupFunc(cmd), arg);
3756 }
3757
3758
3759 bool Buffer::dispatch(int action, string const & argument)
3760 {
3761         bool dispatched = true;
3762         switch (action) {
3763                 case LFUN_EXPORT: 
3764                         Exporter::Export(this, argument, false);
3765                         break;
3766
3767                 default:
3768                         dispatched = false;
3769         }
3770         return dispatched;
3771 }
3772
3773
3774 void Buffer::resizeInsets(BufferView * bv)
3775 {
3776         /// then remove all LyXText in text-insets
3777         Paragraph * par = paragraph;
3778         for (; par; par = par->next()) {
3779             par->resizeInsetsLyXText(bv);
3780         }
3781 }
3782
3783
3784 void Buffer::redraw()
3785 {
3786         users->redraw(); 
3787         users->fitCursor(); 
3788 }
3789
3790
3791 void Buffer::changeLanguage(Language const * from, Language const * to)
3792 {
3793
3794         ParIterator end = par_iterator_end();
3795         for (ParIterator it = par_iterator_begin(); it != end; ++it)
3796                 (*it)->changeLanguage(params, from, to);
3797 }
3798
3799
3800 bool Buffer::isMultiLingual()
3801 {
3802         ParIterator end = par_iterator_end();
3803         for (ParIterator it = par_iterator_begin(); it != end; ++it)
3804                 if ((*it)->isMultiLingual(params))
3805                         return true;
3806
3807         return false;
3808 }
3809
3810
3811 Buffer::inset_iterator::inset_iterator(Paragraph * paragraph, pos_type pos)
3812         : par(paragraph)
3813 {
3814         it = par->InsetIterator(pos);
3815         if (it == par->inset_iterator_end()) {
3816                 par = par->next();
3817                 setParagraph();
3818         }
3819 }
3820
3821
3822 void Buffer::inset_iterator::setParagraph()
3823 {
3824         while (par) {
3825                 it = par->inset_iterator_begin();
3826                 if (it != par->inset_iterator_end())
3827                         return;
3828                 par = par->next();
3829         }
3830         //it = 0;
3831         // We maintain an invariant that whenever par = 0 then it = 0
3832 }
3833
3834
3835 Inset * Buffer::getInsetFromID(int id_arg) const
3836 {
3837         for (inset_iterator it = inset_const_iterator_begin();
3838                  it != inset_const_iterator_end(); ++it)
3839         {
3840                 if ((*it)->id() == id_arg)
3841                         return *it;
3842                 Inset * in = (*it)->getInsetFromID(id_arg);
3843                 if (in)
3844                         return in;
3845         }
3846         return 0;
3847 }
3848
3849
3850 Paragraph * Buffer::getParFromID(int id) const
3851 {
3852         if (id < 0) return 0;
3853         Paragraph * par = paragraph;
3854         while (par) {
3855                 if (par->id() == id) {
3856                         return par;
3857                 }
3858                 Paragraph * tmp = par->getParFromID(id);
3859                 if (tmp) {
3860                         return tmp;
3861                 }
3862                 par = par->next();
3863         }
3864         return 0;
3865 }
3866
3867
3868 ParIterator Buffer::par_iterator_begin()
3869 {
3870         return ParIterator(paragraph);
3871 }
3872
3873
3874 ParIterator Buffer::par_iterator_end()
3875 {
3876         return ParIterator();
3877 }