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