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