]> git.lyx.org Git - lyx.git/blob - src/paragraph_funcs.C
73308f4047bbdaaa1fb4ae7d167632b9d9b6b748
[lyx.git] / src / paragraph_funcs.C
1 /**
2  * \file paragraph_funcs.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "paragraph_funcs.h"
14
15 #include "buffer.h"
16 #include "bufferparams.h"
17
18 #include "debug.h"
19 #include "encoding.h"
20 #include "errorlist.h"
21 #include "factory.h"
22 #include "gettext.h"
23 #include "iterators.h"
24 #include "language.h"
25 #include "latexrunparams.h"
26 #include "lyxlex.h"
27 #include "lyxrc.h"
28 #include "paragraph_pimpl.h"
29 #include "sgml.h"
30 #include "texrow.h"
31 #include "vspace.h"
32
33 #include "insets/insetbibitem.h"
34 #include "insets/insethfill.h"
35 #include "insets/insetlatexaccent.h"
36 #include "insets/insetline.h"
37 #include "insets/insetnewline.h"
38 #include "insets/insetpagebreak.h"
39 #include "insets/insetoptarg.h"
40 #include "insets/insetspace.h"
41 #include "insets/insetspecialchar.h"
42 #include "insets/insettabular.h"
43
44 #include "support/filetools.h"
45 #include "support/lstrings.h"
46 #include "support/lyxlib.h"
47 #include "support/std_sstream.h"
48
49 #include <vector>
50
51 using lyx::pos_type;
52
53 using lyx::support::ascii_lowercase;
54 using lyx::support::atoi;
55 using lyx::support::bformat;
56 using lyx::support::compare_ascii_no_case;
57 using lyx::support::compare_no_case;
58 using lyx::support::contains;
59 using lyx::support::split;
60 using lyx::support::subst;
61
62 using std::endl;
63 using std::string;
64 using std::vector;
65 using std::istringstream;
66 using std::ostream;
67 using std::pair;
68
69 extern string bibitemWidest(Buffer const &);
70
71
72 namespace {
73
74 bool moveItem(Paragraph & from, Paragraph & to,
75         BufferParams const & params, pos_type i, pos_type j)
76 {
77         char const tmpchar = from.getChar(i);
78         LyXFont tmpfont = from.getFontSettings(params, i);
79
80         if (tmpchar == Paragraph::META_INSET) {
81                 InsetOld * tmpinset = 0;
82                 if (from.getInset(i)) {
83                         // the inset is not in a paragraph anymore
84                         tmpinset = from.insetlist.release(i);
85                 }
86
87                 if (!to.insetAllowed(tmpinset->lyxCode()))
88                         return false;
89                 to.insertInset(j, tmpinset, tmpfont);
90         } else {
91                 if (!to.checkInsertChar(tmpfont))
92                         return false;
93                 to.insertChar(j, tmpchar, tmpfont);
94         }
95         return true;
96 }
97
98 }
99
100
101 void breakParagraph(BufferParams const & bparams,
102                     ParagraphList & paragraphs,
103                     ParagraphList::iterator par,
104                     pos_type pos,
105                     int flag)
106 {
107         // create a new paragraph, and insert into the list
108         ParagraphList::iterator tmp = paragraphs.insert(boost::next(par),
109                                                         Paragraph());
110
111         // without doing that we get a crash when typing <Return> at the
112         // end of a paragraph
113         tmp->layout(bparams.getLyXTextClass().defaultLayout());
114         // remember to set the inset_owner
115         tmp->setInsetOwner(par->inInset());
116
117         if (bparams.tracking_changes)
118                 tmp->trackChanges();
119
120         // this is an idea for a more userfriendly layout handling, I will
121         // see what the users say
122
123         // layout stays the same with latex-environments
124         if (flag) {
125                 tmp->layout(par->layout());
126                 tmp->setLabelWidthString(par->params().labelWidthString());
127         }
128
129         bool const isempty = (par->allowEmpty() && par->empty());
130
131         if (!isempty && (par->size() > pos || par->empty() || flag == 2)) {
132                 tmp->layout(par->layout());
133                 tmp->params().align(par->params().align());
134                 tmp->setLabelWidthString(par->params().labelWidthString());
135
136                 tmp->params().spaceBottom(par->params().spaceBottom());
137                 par->params().spaceBottom(VSpace(VSpace::NONE));
138
139                 tmp->params().depth(par->params().depth());
140                 tmp->params().noindent(par->params().noindent());
141
142                 // copy everything behind the break-position
143                 // to the new paragraph
144
145 #ifdef WITH_WARNINGS
146 #warning this seems wrong
147 #endif
148                 /* FIXME: if !keepempty, empty() == true, then we reach
149                  * here with size() == 0. So pos_end becomes - 1. Why
150                  * doesn't this cause problems ???
151                  */
152                 pos_type pos_end = par->size() - 1;
153                 pos_type i = pos;
154                 pos_type j = pos;
155
156                 for (; i <= pos_end; ++i) {
157                         Change::Type change = par->lookupChange(i);
158                         if (moveItem(*par, *tmp, bparams, i, j - pos)) {
159                                 tmp->setChange(j - pos, change);
160                                 ++j;
161                         }
162                 }
163
164                 for (i = pos_end; i >= pos; --i)
165                         par->eraseIntern(i);
166         }
167
168         if (pos)
169                 return;
170
171         tmp->params().spaceTop(par->params().spaceTop());
172         par->params().clear();
173
174         par->layout(bparams.getLyXTextClass().defaultLayout());
175
176         // layout stays the same with latex-environments
177         if (flag) {
178                 par->layout(tmp->layout());
179                 par->setLabelWidthString(tmp->params().labelWidthString());
180                 par->params().depth(tmp->params().depth());
181         }
182
183         // subtle, but needed to get empty pars working right
184         if (bparams.tracking_changes) {
185                 if (!par->size()) {
186                         par->cleanChanges();
187                 } else if (!tmp->size()) {
188                         tmp->cleanChanges();
189                 }
190         }
191 }
192
193
194 void breakParagraphConservative(BufferParams const & bparams,
195                                 ParagraphList & paragraphs,
196                                 ParagraphList::iterator par,
197                                 pos_type pos)
198 {
199         // create a new paragraph
200         ParagraphList::iterator tmp = paragraphs.insert(boost::next(par),
201                                                         Paragraph());
202         tmp->makeSameLayout(*par);
203
204         // When can pos > size()?
205         // I guess pos == size() is possible.
206         if (par->size() > pos) {
207                 // copy everything behind the break-position to the new
208                 // paragraph
209                 pos_type pos_end = par->size() - 1;
210
211                 for (pos_type i = pos, j = pos; i <= pos_end; ++i)
212                         if (moveItem(*par, *tmp, bparams, i, j - pos))
213                                 ++j;
214
215                 for (pos_type k = pos_end; k >= pos; --k)
216                         par->erase(k);
217         }
218 }
219
220
221 void mergeParagraph(BufferParams const & bparams,
222                     ParagraphList & paragraphs,
223                     ParagraphList::iterator par)
224 {
225         ParagraphList::iterator the_next = boost::next(par);
226
227         // first the DTP-stuff
228         par->params().spaceBottom(the_next->params().spaceBottom());
229
230         pos_type pos_end = the_next->size() - 1;
231         pos_type pos_insert = par->size();
232
233         // ok, now copy the paragraph
234         for (pos_type i = 0, j = 0; i <= pos_end; ++i)
235                 if (moveItem(*the_next, *par, bparams, i, pos_insert + j))
236                         ++j;
237
238         paragraphs.erase(the_next);
239 }
240
241
242 ParagraphList::iterator depthHook(ParagraphList::iterator pit,
243                                   ParagraphList const & plist,
244                                   Paragraph::depth_type depth)
245 {
246         ParagraphList::iterator newpit = pit;
247         ParagraphList::iterator beg = const_cast<ParagraphList&>(plist).begin();
248
249         if (newpit != beg)
250                 --newpit;
251
252         while (newpit != beg && newpit->getDepth() > depth) {
253                 --newpit;
254         }
255
256         if (newpit->getDepth() > depth)
257                 return pit;
258
259         return newpit;
260 }
261
262
263 ParagraphList::iterator outerHook(ParagraphList::iterator pit,
264                                   ParagraphList const & plist)
265 {
266         if (!pit->getDepth())
267                 return const_cast<ParagraphList&>(plist).end();
268         return depthHook(pit, plist,
269                          Paragraph::depth_type(pit->getDepth() - 1));
270 }
271
272
273 bool isFirstInSequence(ParagraphList::iterator pit,
274                        ParagraphList const & plist)
275 {
276         ParagraphList::iterator dhook = depthHook(pit, plist, pit->getDepth());
277         return (dhook == pit
278                 || dhook->layout() != pit->layout()
279                 || dhook->getDepth() != pit->getDepth());
280 }
281
282
283 int getEndLabel(ParagraphList::iterator p, ParagraphList const & plist)
284 {
285         ParagraphList::iterator pit = p;
286         Paragraph::depth_type par_depth = p->getDepth();
287         while (pit != const_cast<ParagraphList&>(plist).end()) {
288                 LyXLayout_ptr const & layout = pit->layout();
289                 int const endlabeltype = layout->endlabeltype;
290
291                 if (endlabeltype != END_LABEL_NO_LABEL) {
292                         if (boost::next(p) == const_cast<ParagraphList&>(plist).end())
293                                 return endlabeltype;
294
295                         Paragraph::depth_type const next_depth = boost::next(p)->getDepth();
296                         if (par_depth > next_depth ||
297                             (par_depth == next_depth &&
298                              layout != boost::next(p)->layout()))
299                                 return endlabeltype;
300                         break;
301                 }
302                 if (par_depth == 0)
303                         break;
304                 pit = outerHook(pit, plist);
305                 if (pit != const_cast<ParagraphList&>(plist).end())
306                         par_depth = pit->getDepth();
307         }
308         return END_LABEL_NO_LABEL;
309 }
310
311
312 namespace {
313
314 ParagraphList::iterator
315 TeXEnvironment(Buffer const & buf,
316                ParagraphList const & paragraphs,
317                ParagraphList::iterator pit,
318                ostream & os, TexRow & texrow,
319                LatexRunParams const & runparams);
320
321 ParagraphList::iterator
322 TeXOnePar(Buffer const & buf,
323           ParagraphList const & paragraphs,
324           ParagraphList::iterator pit,
325           ostream & os, TexRow & texrow,
326           LatexRunParams const & runparams,
327           string const & everypar = string());
328
329
330 ParagraphList::iterator
331 TeXDeeper(Buffer const & buf,
332           ParagraphList const & paragraphs,
333           ParagraphList::iterator pit,
334           ostream & os, TexRow & texrow,
335           LatexRunParams const & runparams)
336 {
337         lyxerr[Debug::LATEX] << "TeXDeeper...     " << &*pit << endl;
338         ParagraphList::iterator par = pit;
339
340         while (par != const_cast<ParagraphList&>(paragraphs).end() &&
341                      par->params().depth() == pit->params().depth()) {
342                 if (par->layout()->isEnvironment()) {
343                         par = TeXEnvironment(buf, paragraphs, par,
344                                              os, texrow, runparams);
345                 } else {
346                         par = TeXOnePar(buf, paragraphs, par,
347                                              os, texrow, runparams);
348                 }
349         }
350         lyxerr[Debug::LATEX] << "TeXDeeper...done " << &*par << endl;
351
352         return par;
353 }
354
355
356 ParagraphList::iterator
357 TeXEnvironment(Buffer const & buf,
358                ParagraphList const & paragraphs,
359                ParagraphList::iterator pit,
360                ostream & os, TexRow & texrow,
361                LatexRunParams const & runparams)
362 {
363         lyxerr[Debug::LATEX] << "TeXEnvironment...     " << &*pit << endl;
364
365         BufferParams const & bparams = buf.params();
366
367         LyXLayout_ptr const & style = pit->layout();
368
369         Language const * language = pit->getParLanguage(bparams);
370         Language const * doc_language = bparams.language;
371         Language const * previous_language =
372                 (pit != const_cast<ParagraphList&>(paragraphs).begin())
373                 ? boost::prior(pit)->getParLanguage(bparams)
374                 : doc_language;
375         if (language->babel() != previous_language->babel()) {
376
377                 if (!lyxrc.language_command_end.empty() &&
378                     previous_language->babel() != doc_language->babel()) {
379                         os << subst(lyxrc.language_command_end, "$$lang",
380                                     previous_language->babel())
381                            << endl;
382                         texrow.newline();
383                 }
384
385                 if (lyxrc.language_command_end.empty() ||
386                     language->babel() != doc_language->babel()) {
387                         os << subst(lyxrc.language_command_begin, "$$lang",
388                                     language->babel())
389                            << endl;
390                         texrow.newline();
391                 }
392         }
393
394         bool leftindent_open = false;
395         if (!pit->params().leftIndent().zero()) {
396                 os << "\\begin{LyXParagraphLeftIndent}{" <<
397                         pit->params().leftIndent().asLatexString() << "}\n";
398                 texrow.newline();
399                 leftindent_open = true;
400         }
401
402         if (style->isEnvironment()) {
403                 if (style->latextype == LATEX_LIST_ENVIRONMENT) {
404                         os << "\\begin{" << style->latexname() << "}{"
405                            << pit->params().labelWidthString() << "}\n";
406                 } else if (style->labeltype == LABEL_BIBLIO) {
407                         // ale970405
408                         os << "\\begin{" << style->latexname() << "}{"
409                            <<  bibitemWidest(buf)
410                            << "}\n";
411                 } else if (style->latextype == LATEX_ITEM_ENVIRONMENT) {
412                         os << "\\begin{" << style->latexname() << '}'
413                            << style->latexparam() << '\n';
414                 } else
415                         os << "\\begin{" << style->latexname() << '}'
416                            << style->latexparam() << '\n';
417                 texrow.newline();
418         }
419         ParagraphList::iterator par = pit;
420         do {
421                 par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams);
422
423                 if (par != const_cast<ParagraphList&>(paragraphs).end() && par->params().depth() > pit->params().depth()) {
424                             if (par->layout()->isParagraph()) {
425
426                             // Thinko!
427                             // How to handle this? (Lgb)
428                             //&& !suffixIs(os, "\n\n")
429                                     //) {
430                                 // There should be at least one '\n' already
431                                 // but we need there to be two for Standard
432                                 // paragraphs that are depth-increment'ed to be
433                                 // output correctly.  However, tables can
434                                 // also be paragraphs so don't adjust them.
435                                 // ARRae
436                                 // Thinkee:
437                                 // Will it ever harm to have one '\n' too
438                                 // many? i.e. that we sometimes will have
439                                 // three in a row. (Lgb)
440                                 os << '\n';
441                                 texrow.newline();
442                         }
443                         par = TeXDeeper(buf, paragraphs, par, os, texrow,
444                                         runparams);
445                 }
446         } while (par != const_cast<ParagraphList&>(paragraphs).end()
447                  && par->layout() == pit->layout()
448                  && par->params().depth() == pit->params().depth()
449                  && par->params().leftIndent() == pit->params().leftIndent());
450
451         if (style->isEnvironment()) {
452                 os << "\\end{" << style->latexname() << "}\n";
453                 texrow.newline();
454         }
455
456         if (leftindent_open) {
457                 os << "\\end{LyXParagraphLeftIndent}\n";
458                 texrow.newline();
459         }
460
461         lyxerr[Debug::LATEX] << "TeXEnvironment...done " << &*par << endl;
462         return par;  // ale970302
463 }
464
465
466 InsetOptArg * optArgInset(Paragraph const & par)
467 {
468         // Find the entry.
469         InsetList::const_iterator it = par.insetlist.begin();
470         InsetList::const_iterator end = par.insetlist.end();
471         for (; it != end; ++it) {
472                 InsetOld * ins = it->inset;
473                 if (ins->lyxCode() == InsetOld::OPTARG_CODE) {
474                         return static_cast<InsetOptArg *>(ins);
475                 }
476         }
477         return 0;
478 }
479
480
481 ParagraphList::iterator
482 TeXOnePar(Buffer const & buf,
483           ParagraphList const & paragraphs,
484           ParagraphList::iterator pit,
485           ostream & os, TexRow & texrow,
486           LatexRunParams const & runparams,
487           string const & everypar)
488 {
489         lyxerr[Debug::LATEX] << "TeXOnePar...     " << &*pit << " '"
490                 << everypar << "'" << endl;
491         BufferParams const & bparams = buf.params();
492
493         InsetOld const * in = pit->inInset();
494         bool further_blank_line = false;
495         LyXLayout_ptr style;
496
497         // well we have to check if we are in an inset with unlimited
498         // length (all in one row) if that is true then we don't allow
499         // any special options in the paragraph and also we don't allow
500         // any environment other then "Standard" to be valid!
501         if (in == 0 || !in->forceDefaultParagraphs(in)) {
502                 style = pit->layout();
503
504                 if (pit->params().startOfAppendix()) {
505                         os << "\\appendix\n";
506                         texrow.newline();
507                 }
508
509                 if (!pit->params().spacing().isDefault()
510                         && (pit == const_cast<ParagraphList&>(paragraphs).begin()
511                             || !boost::prior(pit)->hasSameLayout(*pit)))
512                 {
513                         os << pit->params().spacing().writeEnvirBegin() << '\n';
514                         texrow.newline();
515                 }
516
517                 if (style->isCommand()) {
518                         os << '\n';
519                         texrow.newline();
520                 }
521
522                 if (pit->params().spaceTop().kind() != VSpace::NONE) {
523                         os << pit->params().spaceTop().asLatexCommand(bparams);
524                         further_blank_line = true;
525                 }
526
527                 if (further_blank_line) {
528                         os << '\n';
529                         texrow.newline();
530                 }
531         } else {
532                 style = bparams.getLyXTextClass().defaultLayout();
533         }
534
535         Language const * language = pit->getParLanguage(bparams);
536         Language const * doc_language = bparams.language;
537         Language const * previous_language =
538                 (pit != const_cast<ParagraphList&>(paragraphs).begin())
539                 ? boost::prior(pit)->getParLanguage(bparams)
540                 : doc_language;
541
542         if (language->babel() != previous_language->babel()
543             // check if we already put language command in TeXEnvironment()
544             && !(style->isEnvironment()
545                  && (pit == const_cast<ParagraphList&>(paragraphs).begin() ||
546                      (boost::prior(pit)->layout() != pit->layout() &&
547                       boost::prior(pit)->getDepth() <= pit->getDepth())
548                      || boost::prior(pit)->getDepth() < pit->getDepth())))
549         {
550                 if (!lyxrc.language_command_end.empty() &&
551                     previous_language->babel() != doc_language->babel())
552                 {
553                         os << subst(lyxrc.language_command_end, "$$lang",
554                                     previous_language->babel())
555                            << endl;
556                         texrow.newline();
557                 }
558
559                 if (lyxrc.language_command_end.empty() ||
560                     language->babel() != doc_language->babel())
561                 {
562                         os << subst(lyxrc.language_command_begin, "$$lang",
563                                     language->babel())
564                            << endl;
565                         texrow.newline();
566                 }
567         }
568
569         if (bparams.inputenc == "auto" &&
570             language->encoding() != previous_language->encoding()) {
571                 os << "\\inputencoding{"
572                    << language->encoding()->LatexName()
573                    << "}\n";
574                 texrow.newline();
575         }
576
577         switch (style->latextype) {
578         case LATEX_COMMAND:
579                 os << '\\' << style->latexname();
580
581                 // Separate handling of optional argument inset.
582                 if (style->optionalargs == 1) {
583                         InsetOptArg * it = optArgInset(*pit);
584                         if (it)
585                                 it->latexOptional(buf, os, runparams);
586                 }
587                 else
588                         os << style->latexparam();
589                 break;
590         case LATEX_ITEM_ENVIRONMENT:
591         case LATEX_LIST_ENVIRONMENT:
592                 os << "\\item ";
593                 break;
594         case LATEX_BIB_ENVIRONMENT:
595                 // ignore this, the inset will write itself
596                 break;
597         default:
598                 break;
599         }
600
601         os << everypar;
602         bool need_par = pit->simpleTeXOnePar(buf, bparams,
603                                              outerFont(pit, paragraphs),
604                                              os, texrow, runparams);
605
606         // Make sure that \\par is done with the font of the last
607         // character if this has another size as the default.
608         // This is necessary because LaTeX (and LyX on the screen)
609         // calculates the space between the baselines according
610         // to this font. (Matthias)
611         //
612         // Is this really needed ? (Dekel)
613         // We do not need to use to change the font for the last paragraph
614         // or for a command.
615         LyXFont const outerfont(outerFont(pit, paragraphs));
616
617         LyXFont const font =
618                 (pit->empty()
619                  ? pit->getLayoutFont(bparams, outerfont)
620                  : pit->getFont(bparams, pit->size() - 1, outerfont));
621
622         bool is_command = style->isCommand();
623
624         if (style->resfont.size() != font.size()
625             && boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()
626             && !is_command) {
627                 if (!need_par)
628                         os << '{';
629                 os << "\\" << font.latexSize() << " \\par}";
630         } else if (need_par) {
631                 os << "\\par}";
632         } else if (is_command)
633                 os << '}';
634
635         switch (style->latextype) {
636         case LATEX_ITEM_ENVIRONMENT:
637         case LATEX_LIST_ENVIRONMENT:
638                 if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()
639                     && (pit->params().depth() < boost::next(pit)->params().depth())) {
640                         os << '\n';
641                         texrow.newline();
642                 }
643                 break;
644         case LATEX_ENVIRONMENT: {
645                 // if its the last paragraph of the current environment
646                 // skip it otherwise fall through
647                 ParagraphList::iterator next = boost::next(pit);
648
649                 if (next != const_cast<ParagraphList&>(paragraphs).end()
650                     && (next->layout() != pit->layout()
651                         || next->params().depth() != pit->params().depth()))
652                         break;
653         }
654
655                 // fall through possible
656         default:
657                 // we don't need it for the last paragraph!!!
658                 if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()) {
659                         os << '\n';
660                         texrow.newline();
661                 }
662         }
663
664         if (in == 0 || !in->forceDefaultParagraphs(in)) {
665                 further_blank_line = false;
666
667                 if (pit->params().spaceBottom().kind() != VSpace::NONE) {
668                         os << pit->params().spaceBottom().asLatexCommand(bparams);
669                         further_blank_line = true;
670                 }
671
672                 if (further_blank_line) {
673                         os << '\n';
674                         texrow.newline();
675                 }
676
677                 if (!pit->params().spacing().isDefault()
678                         && (boost::next(pit) == const_cast<ParagraphList&>(paragraphs).end()
679                             || !boost::next(pit)->hasSameLayout(*pit)))
680                 {
681                         os << pit->params().spacing().writeEnvirEnd() << '\n';
682                         texrow.newline();
683                 }
684         }
685
686         // we don't need it for the last paragraph!!!
687         if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()) {
688                 os << '\n';
689                 texrow.newline();
690         } else {
691                 // Since \selectlanguage write the language to the aux file,
692                 // we need to reset the language at the end of footnote or
693                 // float.
694
695                 if (language->babel() != doc_language->babel()) {
696                         if (lyxrc.language_command_end.empty())
697                                 os << subst(lyxrc.language_command_begin,
698                                             "$$lang",
699                                             doc_language->babel())
700                                    << endl;
701                         else
702                                 os << subst(lyxrc.language_command_end,
703                                             "$$lang",
704                                             language->babel())
705                                    << endl;
706                         texrow.newline();
707                 }
708         }
709
710         lyxerr[Debug::LATEX] << "TeXOnePar...done " << &*boost::next(pit) << endl;
711         return ++pit;
712 }
713
714 } // anon namespace
715
716
717 //
718 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
719 //
720 void latexParagraphs(Buffer const & buf,
721                      ParagraphList const & paragraphs,
722                      ostream & os,
723                      TexRow & texrow,
724                      LatexRunParams const & runparams,
725                      string const & everypar)
726 {
727         bool was_title = false;
728         bool already_title = false;
729         LyXTextClass const & tclass = buf.params().getLyXTextClass();
730         ParagraphList::iterator par = const_cast<ParagraphList&>(paragraphs).begin();
731         ParagraphList::iterator endpar = const_cast<ParagraphList&>(paragraphs).end();
732
733         // if only_body
734         while (par != endpar) {
735                 InsetOld * in = par->inInset();
736                 // well we have to check if we are in an inset with unlimited
737                 // length (all in one row) if that is true then we don't allow
738                 // any special options in the paragraph and also we don't allow
739                 // any environment other then "Standard" to be valid!
740                 if (in == 0 || !in->forceDefaultParagraphs(in)) {
741                         LyXLayout_ptr const & layout = par->layout();
742
743                         if (layout->intitle) {
744                                 if (already_title) {
745                                         lyxerr <<"Error in latexParagraphs: You"
746                                                 " should not mix title layouts"
747                                                 " with normal ones." << endl;
748                                 } else if (!was_title) {
749                                         was_title = true;
750                                         if (tclass.titletype() == TITLE_ENVIRONMENT) {
751                                                 os << "\\begin{"
752                                                     << tclass.titlename()
753                                                     << "}\n";
754                                                 texrow.newline();
755                                         }
756                                 }
757                         } else if (was_title && !already_title) {
758                                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
759                                         os << "\\end{" << tclass.titlename()
760                                             << "}\n";
761                                 }
762                                 else {
763                                         os << "\\" << tclass.titlename()
764                                             << "\n";
765                                 }
766                                 texrow.newline();
767                                 already_title = true;
768                                 was_title = false;
769                         }
770
771                         if (layout->is_environment) {
772                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
773                                                 runparams, everypar);
774                         } else if (layout->isEnvironment() ||
775                                 !par->params().leftIndent().zero())
776                         {
777                                 par = TeXEnvironment(buf, paragraphs, par, os,
778                                                      texrow, runparams);
779                         } else {
780                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
781                                                 runparams, everypar);
782                         }
783                 } else {
784                         par = TeXOnePar(buf, paragraphs, par, os, texrow,
785                                         runparams, everypar);
786                 }
787         }
788         // It might be that we only have a title in this document
789         if (was_title && !already_title) {
790                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
791                         os << "\\end{" << tclass.titlename()
792                             << "}\n";
793                 }
794                 else {
795                         os << "\\" << tclass.titlename()
796                             << "\n";
797                                 }
798                 texrow.newline();
799         }
800 }
801
802
803 namespace {
804
805 pair<int, string> const addDepth(int depth, int ldepth)
806 {
807         int d = depth * 2;
808         if (ldepth > depth)
809                 d += (ldepth - depth) * 2;
810         return make_pair(d, string(d, ' '));
811 }
812
813 }
814
815
816 void asciiParagraph(Buffer const & buf,
817                     Paragraph const & par,
818                     ostream & os,
819                     LatexRunParams const & runparams,
820                     bool noparbreak)
821 {
822         int ltype = 0;
823         Paragraph::depth_type ltype_depth = 0;
824         bool ref_printed = false;
825         Paragraph::depth_type depth = par.params().depth();
826
827         // First write the layout
828         string const & tmp = par.layout()->name();
829         if (compare_no_case(tmp, "itemize") == 0) {
830                 ltype = 1;
831                 ltype_depth = depth + 1;
832         } else if (compare_ascii_no_case(tmp, "enumerate") == 0) {
833                 ltype = 2;
834                 ltype_depth = depth + 1;
835         } else if (contains(ascii_lowercase(tmp), "ection")) {
836                 ltype = 3;
837                 ltype_depth = depth + 1;
838         } else if (contains(ascii_lowercase(tmp), "aragraph")) {
839                 ltype = 4;
840                 ltype_depth = depth + 1;
841         } else if (compare_ascii_no_case(tmp, "description") == 0) {
842                 ltype = 5;
843                 ltype_depth = depth + 1;
844         } else if (compare_ascii_no_case(tmp, "abstract") == 0) {
845                 ltype = 6;
846                 ltype_depth = 0;
847         } else if (compare_ascii_no_case(tmp, "bibliography") == 0) {
848                 ltype = 7;
849                 ltype_depth = 0;
850         } else {
851                 ltype = 0;
852                 ltype_depth = 0;
853         }
854
855         /* maybe some vertical spaces */
856
857         /* the labelwidthstring used in lists */
858
859         /* some lines? */
860
861         /* some pagebreaks? */
862
863         /* noindent ? */
864
865         /* what about the alignment */
866
867         // runparams.linelen <= 0 is special and means we don't have paragraph breaks
868
869         string::size_type currlinelen = 0;
870
871         if (!noparbreak) {
872                 if (runparams.linelen > 0)
873                         os << "\n\n";
874
875                 os << string(depth * 2, ' ');
876                 currlinelen += depth * 2;
877
878                 //--
879                 // we should probably change to the paragraph language in the
880                 // gettext here (if possible) so that strings are outputted in
881                 // the correct language! (20012712 Jug)
882                 //--
883                 switch (ltype) {
884                 case 0: // Standard
885                 case 4: // (Sub)Paragraph
886                 case 5: // Description
887                         break;
888                 case 6: // Abstract
889                         if (runparams.linelen > 0) {
890                                 os << _("Abstract") << "\n\n";
891                                 currlinelen = 0;
892                         } else {
893                                 string const abst = _("Abstract: ");
894                                 os << abst;
895                                 currlinelen += abst.length();
896                         }
897                         break;
898                 case 7: // Bibliography
899                         if (!ref_printed) {
900                                 if (runparams.linelen > 0) {
901                                         os << _("References") << "\n\n";
902                                         currlinelen = 0;
903                                 } else {
904                                         string const refs = _("References: ");
905                                         os << refs;
906                                         currlinelen += refs.length();
907                                 }
908
909                                 ref_printed = true;
910                         }
911                         break;
912                 default:
913                 {
914                         string const parlab = par.params().labelString();
915                         os << parlab << ' ';
916                         currlinelen += parlab.length() + 1;
917                 }
918                 break;
919
920                 }
921         }
922
923         if (!currlinelen) {
924                 pair<int, string> p = addDepth(depth, ltype_depth);
925                 os << p.second;
926                 currlinelen += p.first;
927         }
928
929         // this is to change the linebreak to do it by word a bit more
930         // intelligent hopefully! (only in the case where we have a
931         // max runparams.linelength!) (Jug)
932
933         string word;
934
935         for (pos_type i = 0; i < par.size(); ++i) {
936                 char c = par.getUChar(buf.params(), i);
937                 switch (c) {
938                 case Paragraph::META_INSET:
939                 {
940                         InsetOld const * inset = par.getInset(i);
941                         if (inset) {
942                                 if (runparams.linelen > 0) {
943                                         os << word;
944                                         currlinelen += word.length();
945                                         word.erase();
946                                 }
947                                 if (inset->ascii(buf, os, runparams)) {
948                                         // to be sure it breaks paragraph
949                                         currlinelen += runparams.linelen;
950                                 }
951                         }
952                 }
953                 break;
954
955                 default:
956                         if (c == ' ') {
957                                 if (runparams.linelen > 0 &&
958                                     currlinelen + word.length() > runparams.linelen - 10) {
959                                         os << "\n";
960                                         pair<int, string> p = addDepth(depth, ltype_depth);
961                                         os << p.second;
962                                         currlinelen = p.first;
963                                 }
964
965                                 os << word << ' ';
966                                 currlinelen += word.length() + 1;
967                                 word.erase();
968
969                         } else {
970                                 if (c != '\0') {
971                                         word += c;
972                                 } else {
973                                         lyxerr[Debug::INFO] <<
974                                                 "writeAsciiFile: NULL char in structure." << endl;
975                                 }
976                                 if ((runparams.linelen > 0) &&
977                                         (currlinelen + word.length()) > runparams.linelen)
978                                 {
979                                         os << "\n";
980
981                                         pair<int, string> p =
982                                                 addDepth(depth, ltype_depth);
983                                         os << p.second;
984                                         currlinelen = p.first;
985                                 }
986                         }
987                         break;
988                 }
989         }
990         os << word;
991 }
992
993
994 void linuxdocParagraphs(Buffer const & buf,
995                         ParagraphList const & paragraphs,
996                         ostream & os,
997                         LatexRunParams const & runparams)
998 {
999         
1000         Paragraph::depth_type depth = 0; // paragraph depth
1001         string item_name;
1002         vector<string> environment_stack(5);
1003
1004         ParagraphList::iterator pit = const_cast<ParagraphList&>(paragraphs).begin();
1005         ParagraphList::iterator pend = const_cast<ParagraphList&>(paragraphs).end();
1006         for (; pit != pend; ++pit) {
1007                 LyXLayout_ptr const & style = pit->layout();
1008                 // treat <toc> as a special case for compatibility with old code
1009                 if (pit->isInset(0)) {
1010                         InsetOld * inset = pit->getInset(0);
1011                         InsetOld::Code lyx_code = inset->lyxCode();
1012                         if (lyx_code == InsetOld::TOC_CODE) {
1013                                 string const temp = "toc";
1014                                 sgml::openTag(os, depth, false, temp);
1015                                 continue;
1016                         }
1017                 }
1018
1019                 // environment tag closing
1020                 for (; depth > pit->params().depth(); --depth) {
1021                         sgml::closeTag(os, depth, false, environment_stack[depth]);
1022                         environment_stack[depth].erase();
1023                 }
1024
1025                 // write opening SGML tags
1026                 switch (style->latextype) {
1027                 case LATEX_PARAGRAPH:
1028                         if (depth == pit->params().depth()
1029                            && !environment_stack[depth].empty()) {
1030                                 sgml::closeTag(os, depth, false, environment_stack[depth]);
1031                                 environment_stack[depth].erase();
1032                                 if (depth)
1033                                         --depth;
1034                                 else
1035                                         os << "</p>";
1036                         }
1037                         sgml::openTag(os, depth, false, style->latexname());
1038                         break;
1039
1040                 case LATEX_COMMAND:
1041                         if (depth != 0)
1042                                 //error(ErrorItem(_("Error:"), _("Wrong depth for LatexType Command.\n"), pit->id(), 0, pit->size()));
1043                                 ;
1044
1045                         if (!environment_stack[depth].empty()) {
1046                                 sgml::closeTag(os, depth, false, environment_stack[depth]);
1047                                 os << "</p>";
1048                         }
1049
1050                         environment_stack[depth].erase();
1051                         sgml::openTag(os, depth, false, style->latexname());
1052                         break;
1053
1054                 case LATEX_ENVIRONMENT:
1055                 case LATEX_ITEM_ENVIRONMENT:
1056                 case LATEX_BIB_ENVIRONMENT:
1057                 {
1058                         string const & latexname = style->latexname();
1059
1060                         if (depth == pit->params().depth()
1061                             && environment_stack[depth] != latexname) {
1062                                 sgml::closeTag(os, depth, false,
1063                                              environment_stack[depth]);
1064                                 environment_stack[depth].erase();
1065                         }
1066                         if (depth < pit->params().depth()) {
1067                                depth = pit->params().depth();
1068                                environment_stack[depth].erase();
1069                         }
1070                         if (environment_stack[depth] != latexname) {
1071                                 if (depth == 0) {
1072                                         sgml::openTag(os, depth, false, "p");
1073                                 }
1074                                 sgml::openTag(os, depth, false, latexname);
1075
1076                                 if (environment_stack.size() == depth + 1)
1077                                         environment_stack.push_back("!-- --");
1078                                 environment_stack[depth] = latexname;
1079                         }
1080
1081                         if (style->latexparam() == "CDATA")
1082                                 os << "<![CDATA[";
1083
1084                         if (style->latextype == LATEX_ENVIRONMENT) break;
1085
1086                         if (style->labeltype == LABEL_MANUAL)
1087                                 item_name = "tag";
1088                         else
1089                                 item_name = "item";
1090
1091                         sgml::openTag(os, depth + 1, false, item_name);
1092                 }
1093                 break;
1094
1095                 default:
1096                         sgml::openTag(os, depth, false, style->latexname());
1097                         break;
1098                 }
1099
1100                 pit->simpleLinuxDocOnePar(buf, os, outerFont(pit, paragraphs),
1101                                           runparams, depth);
1102
1103                 os << "\n";
1104                 // write closing SGML tags
1105                 switch (style->latextype) {
1106                 case LATEX_COMMAND:
1107                         break;
1108                 case LATEX_ENVIRONMENT:
1109                 case LATEX_ITEM_ENVIRONMENT:
1110                 case LATEX_BIB_ENVIRONMENT:
1111                         if (style->latexparam() == "CDATA")
1112                                 os << "]]>";
1113                         break;
1114                 default:
1115                         sgml::closeTag(os, depth, false, style->latexname());
1116                         break;
1117                 }
1118         }
1119
1120         // Close open tags
1121         for (int i = depth; i >= 0; --i)
1122                 sgml::closeTag(os, depth, false, environment_stack[i]);
1123 }
1124
1125
1126 void docbookParagraphs(Buffer const & buf,
1127                        ParagraphList const & paragraphs,
1128                        ostream & os,
1129                        LatexRunParams const & runparams)
1130 {
1131         vector<string> environment_stack(10);
1132         vector<string> environment_inner(10);
1133         vector<string> command_stack(10);
1134
1135         bool command_flag = false;
1136         Paragraph::depth_type command_depth = 0;
1137         Paragraph::depth_type command_base = 0;
1138         Paragraph::depth_type cmd_depth = 0;
1139         Paragraph::depth_type depth = 0; // paragraph depth
1140
1141         string item_name;
1142         string command_name;
1143
1144         ParagraphList::iterator par = const_cast<ParagraphList&>(paragraphs).begin();
1145         ParagraphList::iterator pend = const_cast<ParagraphList&>(paragraphs).end();
1146
1147         for (; par != pend; ++par) {
1148                 string sgmlparam;
1149                 string c_depth;
1150                 string c_params;
1151                 int desc_on = 0; // description mode
1152
1153                 LyXLayout_ptr const & style = par->layout();
1154
1155                 // environment tag closing
1156                 for (; depth > par->params().depth(); --depth) {
1157                         if (!environment_inner[depth].empty()) 
1158                         sgml::closeEnvTags(os, false, environment_inner[depth], 
1159                                         command_depth + depth);
1160                         sgml::closeTag(os, depth + command_depth, false, environment_stack[depth]);
1161                         environment_stack[depth].erase();
1162                         environment_inner[depth].erase();
1163                 }
1164
1165                 if (depth == par->params().depth()
1166                    && environment_stack[depth] != style->latexname()
1167                    && !environment_stack[depth].empty()) {
1168                                 sgml::closeEnvTags(os, false, environment_inner[depth], 
1169                                         command_depth + depth);
1170                         sgml::closeTag(os, depth + command_depth, false, environment_stack[depth]);
1171
1172                         environment_stack[depth].erase();
1173                         environment_inner[depth].erase();
1174                 }
1175
1176                 // Write opening SGML tags.
1177                 switch (style->latextype) {
1178                 case LATEX_PARAGRAPH:
1179                         sgml::openTag(os, depth + command_depth,
1180                                     false, style->latexname());
1181                         break;
1182
1183                 case LATEX_COMMAND:
1184                         if (depth != 0)
1185                                 //error(ErrorItem(_("Error"), _("Wrong depth for LatexType Command."), par->id(), 0, par->size()));
1186                                 ;
1187                         
1188                         command_name = style->latexname();
1189
1190                         sgmlparam = style->latexparam();
1191                         c_params = split(sgmlparam, c_depth,'|');
1192
1193                         cmd_depth = atoi(c_depth);
1194
1195                         if (command_flag) {
1196                                 if (cmd_depth < command_base) {
1197                                         for (Paragraph::depth_type j = command_depth;
1198                                              j >= command_base; --j) {
1199                                                 sgml::closeTag(os, j, false, command_stack[j]);
1200                                                 os << endl;
1201                                         }
1202                                         command_depth = command_base = cmd_depth;
1203                                 } else if (cmd_depth <= command_depth) {
1204                                         for (int j = command_depth;
1205                                              j >= int(cmd_depth); --j) {
1206                                                 sgml::closeTag(os, j, false, command_stack[j]);
1207                                                 os << endl;
1208                                         }
1209                                         command_depth = cmd_depth;
1210                                 } else
1211                                         command_depth = cmd_depth;
1212                         } else {
1213                                 command_depth = command_base = cmd_depth;
1214                                 command_flag = true;
1215                         }
1216                         if (command_stack.size() == command_depth + 1)
1217                                 command_stack.push_back(string());
1218                         command_stack[command_depth] = command_name;
1219
1220                         // treat label as a special case for
1221                         // more WYSIWYM handling.
1222                         // This is a hack while paragraphs can't have
1223                         // attributes, like id in this case.
1224                         if (par->isInset(0)) {
1225                                 InsetOld * inset = par->getInset(0);
1226                                 InsetOld::Code lyx_code = inset->lyxCode();
1227                                 if (lyx_code == InsetOld::LABEL_CODE) {
1228                                         command_name += " id=\"";
1229                                         command_name += (static_cast<InsetCommand *>(inset))->getContents();
1230                                         command_name += '"';
1231                                         desc_on = 3;
1232                                 }
1233                         }
1234
1235                         sgml::openTag(os, depth + command_depth, false, command_name);
1236
1237                         item_name = c_params.empty() ? "title" : c_params;
1238                         sgml::openTag(os, depth + 1 + command_depth, false, item_name);
1239                         break;
1240
1241                 case LATEX_ENVIRONMENT:
1242                 case LATEX_ITEM_ENVIRONMENT:
1243                         if (depth < par->params().depth()) {
1244                                 depth = par->params().depth();
1245                                 environment_stack[depth].erase();
1246                         }
1247
1248                         if (environment_stack[depth] != style->latexname()) {
1249                                 if (environment_stack.size() == depth + 1) {
1250                                         environment_stack.push_back("!-- --");
1251                                         environment_inner.push_back("!-- --");
1252                                 }
1253                                 environment_stack[depth] = style->latexname();
1254                                 environment_inner[depth] = "!-- --";
1255                                 sgml::openTag(os, depth + command_depth, false, environment_stack[depth]);
1256                         } else {
1257                                         sgml::closeEnvTags(os, false, environment_inner[depth], 
1258                                                 command_depth + depth);
1259                         }
1260
1261                         if (style->latextype == LATEX_ENVIRONMENT) {
1262                                 if (!style->latexparam().empty()) {
1263                                         if (style->latexparam() == "CDATA")
1264                                                 os << "<![CDATA[";
1265                                         else
1266                                                 sgml::openTag(os, depth + command_depth, false, style->latexparam());
1267                                 }
1268                                 break;
1269                         }
1270
1271                         desc_on = (style->labeltype == LABEL_MANUAL);
1272
1273                         environment_inner[depth] = desc_on ? "varlistentry" : "listitem";
1274                         sgml::openTag(os, depth + 1 + command_depth,
1275                                     false, environment_inner[depth]);
1276
1277                         item_name = desc_on ? "term" : "para";
1278                         sgml::openTag(os, depth + 1 + command_depth,
1279                                     false, item_name);
1280                         break;
1281                 default:
1282                         sgml::openTag(os, depth + command_depth,
1283                                     false, style->latexname());
1284                         break;
1285                 }
1286
1287                 par->simpleDocBookOnePar(buf, os, outerFont(par, paragraphs), desc_on,
1288                                          runparams, depth + 1 + command_depth);
1289
1290                 string end_tag;
1291                 // write closing SGML tags
1292                 switch (style->latextype) {
1293                 case LATEX_COMMAND:
1294                         end_tag = c_params.empty() ? "title" : c_params;
1295                         sgml::closeTag(os, depth + command_depth,
1296                                      false, end_tag);
1297                         break;
1298                 case LATEX_ENVIRONMENT:
1299                         if (!style->latexparam().empty()) {
1300                                 if (style->latexparam() == "CDATA")
1301                                         os << "]]>";
1302                                 else
1303                                         sgml::closeTag(os, depth + command_depth, false, style->latexparam());
1304                         }
1305                         break;
1306                 case LATEX_ITEM_ENVIRONMENT:
1307                         if (desc_on == 1) break;
1308                         end_tag = "para";
1309                         sgml::closeTag(os, depth + 1 + command_depth, false, end_tag);
1310                         break;
1311                 case LATEX_PARAGRAPH:
1312                         sgml::closeTag(os, depth + command_depth, false, style->latexname());
1313                         break;
1314                 default:
1315                         sgml::closeTag(os, depth + command_depth, false, style->latexname());
1316                         break;
1317                 }
1318         }
1319
1320         // Close open tags
1321         for (int d = depth; d >= 0; --d) {
1322                 if (!environment_stack[depth].empty()) {
1323                                 sgml::closeEnvTags(os, false, environment_inner[depth], 
1324                                         command_depth + depth);
1325                 }
1326         }
1327
1328         for (int j = command_depth; j >= 0 ; --j)
1329                 if (!command_stack[j].empty()) {
1330                         sgml::closeTag(os, j, false, command_stack[j]);
1331                         os << endl;
1332                 }
1333 }
1334
1335 namespace {
1336
1337 int readParToken(Buffer & buf, Paragraph & par, LyXLex & lex, string const & token)
1338 {
1339         static LyXFont font;
1340         static Change change;
1341
1342         BufferParams const & bp = buf.params();
1343
1344         if (token[0] != '\\') {
1345                 string::const_iterator cit = token.begin();
1346                 for (; cit != token.end(); ++cit) {
1347                         par.insertChar(par.size(), (*cit), font, change);
1348                 }
1349         } else if (token == "\\begin_layout") {
1350                 lex.eatLine();
1351                 string layoutname = lex.getString();
1352
1353                 font = LyXFont(LyXFont::ALL_INHERIT, bp.language);
1354                 change = Change();
1355
1356                 LyXTextClass const & tclass = bp.getLyXTextClass();
1357
1358                 if (layoutname.empty()) {
1359                         layoutname = tclass.defaultLayoutName();
1360                 }
1361
1362                 bool hasLayout = tclass.hasLayout(layoutname);
1363
1364                 if (!hasLayout) {
1365                         lyxerr << "Layout '" << layoutname << "' does not"
1366                                << " exist in textclass '" << tclass.name()
1367                                << "'." << endl;
1368                         lyxerr << "Trying to use default layout instead."
1369                                << endl;
1370                         layoutname = tclass.defaultLayoutName();
1371                 }
1372
1373                 par.layout(bp.getLyXTextClass()[layoutname]);
1374
1375                 // Test whether the layout is obsolete.
1376                 LyXLayout_ptr const & layout = par.layout();
1377                 if (!layout->obsoleted_by().empty())
1378                         par.layout(bp.getLyXTextClass()[layout->obsoleted_by()]);
1379
1380                 par.params().read(lex);
1381
1382         } else if (token == "\\end_layout") {
1383                 lyxerr << "Solitary \\end_layout in line " << lex.getLineNo() << "\n"
1384                        << "Missing \\begin_layout?.\n";
1385         } else if (token == "\\end_inset") {
1386                 lyxerr << "Solitary \\end_inset in line " << lex.getLineNo() << "\n"
1387                        << "Missing \\begin_inset?.\n";
1388         } else if (token == "\\begin_inset") {
1389                 InsetOld * inset = readInset(lex, buf);
1390                 if (inset)
1391                         par.insertInset(par.size(), inset, font, change);
1392                 else {
1393                         lex.eatLine();
1394                         string line = lex.getString();
1395                         buf.error(ErrorItem(_("Unknown Inset"), line,
1396                                             buf.paragraphs().back().id(),
1397                                             0, par.size()));
1398                         return 1;
1399                 }
1400         } else if (token == "\\family") {
1401                 lex.next();
1402                 font.setLyXFamily(lex.getString());
1403         } else if (token == "\\series") {
1404                 lex.next();
1405                 font.setLyXSeries(lex.getString());
1406         } else if (token == "\\shape") {
1407                 lex.next();
1408                 font.setLyXShape(lex.getString());
1409         } else if (token == "\\size") {
1410                 lex.next();
1411                 font.setLyXSize(lex.getString());
1412         } else if (token == "\\lang") {
1413                 lex.next();
1414                 string const tok = lex.getString();
1415                 Language const * lang = languages.getLanguage(tok);
1416                 if (lang) {
1417                         font.setLanguage(lang);
1418                 } else {
1419                         font.setLanguage(bp.language);
1420                         lex.printError("Unknown language `$$Token'");
1421                 }
1422         } else if (token == "\\numeric") {
1423                 lex.next();
1424                 font.setNumber(font.setLyXMisc(lex.getString()));
1425         } else if (token == "\\emph") {
1426                 lex.next();
1427                 font.setEmph(font.setLyXMisc(lex.getString()));
1428         } else if (token == "\\bar") {
1429                 lex.next();
1430                 string const tok = lex.getString();
1431
1432                 if (tok == "under")
1433                         font.setUnderbar(LyXFont::ON);
1434                 else if (tok == "no")
1435                         font.setUnderbar(LyXFont::OFF);
1436                 else if (tok == "default")
1437                         font.setUnderbar(LyXFont::INHERIT);
1438                 else
1439                         lex.printError("Unknown bar font flag "
1440                                        "`$$Token'");
1441         } else if (token == "\\noun") {
1442                 lex.next();
1443                 font.setNoun(font.setLyXMisc(lex.getString()));
1444         } else if (token == "\\color") {
1445                 lex.next();
1446                 font.setLyXColor(lex.getString());
1447         } else if (token == "\\InsetSpace" || token == "\\SpecialChar") {
1448
1449                 // Insets don't make sense in a free-spacing context! ---Kayvan
1450                 if (par.isFreeSpacing()) {
1451                         if (token == "\\InsetSpace")
1452                                 par.insertChar(par.size(), ' ', font, change);
1453                         else if (lex.isOK()) {
1454                                 lex.next();
1455                                 string const next_token = lex.getString();
1456                                 if (next_token == "\\-")
1457                                         par.insertChar(par.size(), '-', font, change);
1458                                 else {
1459                                         lex.printError("Token `$$Token' "
1460                                                        "is in free space "
1461                                                        "paragraph layout!");
1462                                 }
1463                         }
1464                 } else {
1465                         InsetOld * inset = 0;
1466                         if (token == "\\SpecialChar" )
1467                                 inset = new InsetSpecialChar;
1468                         else
1469                                 inset = new InsetSpace;
1470                         inset->read(buf, lex);
1471                         par.insertInset(par.size(), inset, font, change);
1472                 }
1473         } else if (token == "\\i") {
1474                 InsetOld * inset = new InsetLatexAccent;
1475                 inset->read(buf, lex);
1476                 par.insertInset(par.size(), inset, font, change);
1477         } else if (token == "\\backslash") {
1478                 par.insertChar(par.size(), '\\', font, change);
1479         } else if (token == "\\newline") {
1480                 InsetOld * inset = new InsetNewline;
1481                 inset->read(buf, lex);
1482                 par.insertInset(par.size(), inset, font, change);
1483         } else if (token == "\\LyXTable") {
1484                 InsetOld * inset = new InsetTabular(buf);
1485                 inset->read(buf, lex);
1486                 par.insertInset(par.size(), inset, font, change);
1487         } else if (token == "\\bibitem") {
1488                 InsetCommandParams p("bibitem", "dummy");
1489                 InsetBibitem * inset = new InsetBibitem(p);
1490                 inset->read(buf, lex);
1491                 par.insertInset(par.size(), inset, font, change);
1492         } else if (token == "\\hfill") {
1493                 par.insertInset(par.size(), new InsetHFill, font, change);
1494         } else if (token == "\\lyxline") {
1495                 par.insertInset(par.size(), new InsetLine, font, change);
1496         } else if (token == "\\newpage") {
1497                 par.insertInset(par.size(), new InsetPagebreak, font, change);
1498         } else if (token == "\\change_unchanged") {
1499                 // Hack ! Needed for empty paragraphs :/
1500                 // FIXME: is it still ??
1501                 if (!par.size())
1502                         par.cleanChanges();
1503                 change = Change(Change::UNCHANGED);
1504         } else if (token == "\\change_inserted") {
1505                 lex.nextToken();
1506                 istringstream is(lex.getString());
1507                 int aid;
1508                 lyx::time_type ct;
1509                 is >> aid >> ct;
1510                 change = Change(Change::INSERTED, bp.author_map[aid], ct);
1511         } else if (token == "\\change_deleted") {
1512                 lex.nextToken();
1513                 istringstream is(lex.getString());
1514                 int aid;
1515                 lyx::time_type ct;
1516                 is >> aid >> ct;
1517                 change = Change(Change::DELETED, bp.author_map[aid], ct);
1518         } else {
1519                 lex.eatLine();
1520                 string const s = bformat(_("Unknown token: %1$s %2$s\n"),
1521                         token, lex.getString());
1522
1523                 buf.error(ErrorItem(_("Unknown token"), s,
1524                                     buf.paragraphs().back().id(),
1525                                     0, par.size()));
1526                 return 1;
1527         }
1528         return 0;
1529 }
1530
1531 }
1532
1533
1534 int readParagraph(Buffer & buf, Paragraph & par, LyXLex & lex)
1535 {
1536         int unknown = 0;
1537
1538         lex.nextToken();
1539         string token = lex.getString();
1540
1541         while (lex.isOK()) {
1542
1543                 unknown += readParToken(buf, par, lex, token);
1544
1545                 lex.nextToken();
1546                 token = lex.getString();
1547
1548                 if (token.empty())
1549                         continue;
1550
1551                 if (token == "\\end_layout") {
1552                         //Ok, paragraph finished
1553                         break;
1554                 }
1555
1556                 lyxerr[Debug::PARSER] << "Handling paragraph token: `"
1557                                       << token << '\'' << endl;
1558                 if (token == "\\begin_layout" || token == "\\end_document"
1559                     || token == "\\end_inset" || token == "\\begin_deeper"
1560                     || token == "\\end_deeper") {
1561                         lex.pushToken(token);
1562                         lyxerr << "Paragraph ended in line "
1563                                << lex.getLineNo() << "\n"
1564                                << "Missing \\end_layout.\n";
1565                         break;
1566                 }
1567         }
1568
1569         return unknown;
1570 }
1571
1572
1573 LyXFont const outerFont(ParagraphList::iterator pit,
1574                         ParagraphList const & plist)
1575 {
1576         Paragraph::depth_type par_depth = pit->getDepth();
1577         LyXFont tmpfont(LyXFont::ALL_INHERIT);
1578
1579         // Resolve against environment font information
1580         while (pit != const_cast<ParagraphList&>(plist).end() &&
1581                par_depth && !tmpfont.resolved()) {
1582                 pit = outerHook(pit, plist);
1583                 if (pit != const_cast<ParagraphList&>(plist).end()) {
1584                         tmpfont.realize(pit->layout()->font);
1585                         par_depth = pit->getDepth();
1586                 }
1587         }
1588
1589         return tmpfont;
1590 }
1591
1592
1593 ParagraphList::iterator outerPar(Buffer const & buf, InsetOld const * inset)
1594 {
1595         ParIterator pit = const_cast<Buffer &>(buf).par_iterator_begin();
1596         ParIterator end = const_cast<Buffer &>(buf).par_iterator_end();
1597         for ( ; pit != end; ++pit) {
1598
1599                 ParagraphList * plist;
1600                 // the second '=' below is intentional
1601                 for (int i = 0; (plist = inset->getParagraphs(i)); ++i)
1602                         if (plist == &pit.plist())
1603                                 return pit.outerPar();
1604
1605                 InsetList::iterator ii = pit->insetlist.begin();
1606                 InsetList::iterator iend = pit->insetlist.end();
1607                 for ( ; ii != iend; ++ii)
1608                         if (ii->inset == inset)
1609                                 return pit.outerPar();
1610         }
1611         lyxerr << "outerPar: should not happen" << endl;
1612         BOOST_ASSERT(false);
1613         return const_cast<Buffer &>(buf).paragraphs().end(); // shut up compiler
1614 }
1615
1616
1617 Paragraph const & ownerPar(Buffer const & buf, InsetOld const * inset)
1618 {
1619         ParConstIterator pit = buf.par_iterator_begin();
1620         ParConstIterator end = buf.par_iterator_end();
1621         for ( ; pit != end; ++pit) {
1622                 ParagraphList * plist;
1623                 // the second '=' below is intentional
1624                 for (int i = 0; (plist = inset->getParagraphs(i)); ++i)
1625                         if (plist == &pit.plist())
1626                                 return *pit.pit();
1627
1628                 InsetList::const_iterator ii = pit->insetlist.begin();
1629                 InsetList::const_iterator iend = pit->insetlist.end();
1630                 for ( ; ii != iend; ++ii)
1631                         if (ii->inset == inset)
1632                                 return *pit.pit();
1633         }
1634         lyxerr << "ownerPar: should not happen" << endl;
1635         BOOST_ASSERT(false);
1636         return buf.paragraphs().front(); // shut up compiler
1637 }