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