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