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