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