]> git.lyx.org Git - lyx.git/blob - src/paragraph.C
fix typo that put too many include paths for most people
[lyx.git] / src / paragraph.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "paragraph.h"
18 #include "paragraph_pimpl.h"
19 #include "lyxrc.h"
20 #include "layout.h"
21 #include "language.h"
22 #include "tex-strings.h"
23 #include "buffer.h"
24 #include "bufferparams.h"
25 #include "debug.h"
26 #include "LaTeXFeatures.h"
27 #include "texrow.h"
28 #include "BufferView.h"
29 #include "encoding.h"
30 #include "ParameterStruct.h"
31 #include "gettext.h"
32 #include "lyxtextclasslist.h"
33
34 #include "insets/insetinclude.h"
35 #include "insets/insetbib.h"
36 #include "insets/insettext.h"
37
38 #include "support/filetools.h"
39 #include "support/lstrings.h"
40 #include "support/lyxmanip.h"
41 #include "support/FileInfo.h"
42 #include "support/LAssert.h"
43 #include "support/textutils.h"
44
45 #include <algorithm>
46 #include <fstream>
47 #include <csignal>
48
49 using std::ostream;
50 using std::endl;
51 using std::fstream;
52 using std::ios;
53 using std::lower_bound;
54 using std::upper_bound;
55 using std::reverse;
56
57 using lyx::pos_type;
58
59 int tex_code_break_column = 72;  // needs non-zero initialization. set later.
60 // this is a bad idea, but how can Paragraph find its buffer to get
61 // parameters? (JMarc)
62
63 extern string bibitemWidest(Buffer const *);
64
65 // this is a minibuffer
66
67 namespace {
68
69 char minibuffer_char;
70 LyXFont minibuffer_font;
71 Inset * minibuffer_inset;
72
73 } // namespace anon
74
75
76 extern BufferView * current_view;
77
78
79 Paragraph::Paragraph()
80         : pimpl_(new Paragraph::Pimpl(this))
81 {
82         for (int i = 0; i < 10; ++i)
83                 setCounter(i, 0);
84         next_ = 0;
85         previous_ = 0;
86         enumdepth = 0;
87         itemdepth = 0;
88         bibkey = 0; // ale970302
89         params().clear();
90 }
91
92
93 // This constructor inserts the new paragraph in a list.
94 Paragraph::Paragraph(Paragraph * par)
95         : pimpl_(new Paragraph::Pimpl(this))
96 {
97         for (int i = 0; i < 10; ++i)
98                 setCounter(i, 0);
99         enumdepth = 0;
100         itemdepth = 0;
101
102         // double linked list begin
103         next_ = par->next_;
104         if (next_)
105                 next_->previous_ = this;
106         previous_ = par;
107         previous_->next_ = this;
108         // end
109
110         bibkey = 0; // ale970302
111         params().clear();
112 }
113
114
115 Paragraph::Paragraph(Paragraph const & lp, bool same_ids)
116         : pimpl_(new Paragraph::Pimpl(*lp.pimpl_, this, same_ids))
117 {
118         for (int i = 0; i < 10; ++i)
119                 setCounter(i, 0);
120         enumdepth = 0;
121         itemdepth = 0;
122         next_     = 0;
123         previous_ = 0;
124
125         // this is because of the dummy layout of the paragraphs that
126         // follow footnotes
127         layout_ = lp.layout();
128
129         // ale970302
130         if (lp.bibkey) {
131                 bibkey = static_cast<InsetBibKey *>
132                         (lp.bibkey->clone(*current_view->buffer()));
133         } else {
134                 bibkey = 0;
135         }
136
137         // copy everything behind the break-position to the new paragraph
138         insetlist = lp.insetlist;
139         for (InsetList::iterator it = insetlist.begin();
140              it != insetlist.end(); ++it)
141         {
142                 it->inset = it->inset->clone(*current_view->buffer(), same_ids);
143                 // tell the new inset who is the boss now
144                 it->inset->parOwner(this);
145         }
146 }
147
148
149 // the destructor removes the new paragraph from the list
150 Paragraph::~Paragraph()
151 {
152         if (previous_)
153                 previous_->next_ = next_;
154         if (next_)
155                 next_->previous_ = previous_;
156
157         for (InsetList::iterator it = insetlist.begin();
158              it != insetlist.end(); ++it) {
159                 delete it->inset;
160         }
161
162         // ale970302
163         delete bibkey;
164
165         delete pimpl_;
166         //
167         //lyxerr << "Paragraph::paragraph_id = "
168         //       << Paragraph::paragraph_id << endl;
169 }
170
171
172 void Paragraph::writeFile(Buffer const * buf, ostream & os,
173                           BufferParams const & bparams,
174                           depth_type dth) const
175 {
176         // The beginning or end of a deeper (i.e. nested) area?
177         if (dth != params().depth()) {
178                 if (params().depth() > dth) {
179                         while (params().depth() > dth) {
180                                 os << "\n\\begin_deeper ";
181                                 ++dth;
182                         }
183                 } else {
184                         while (params().depth() < dth) {
185                                 os << "\n\\end_deeper ";
186                                 --dth;
187                         }
188                 }
189         }
190
191         // First write the layout
192         string lay = layout();
193         if (lay.empty()) {
194                 lay = textclasslist[bparams.textclass].defaultLayoutName();
195         }
196
197         os << "\n\\layout " << layout() << "\n";
198
199         // Maybe some vertical spaces.
200         if (params().spaceTop().kind() != VSpace::NONE)
201                 os << "\\added_space_top "
202                    << params().spaceTop().asLyXCommand() << " ";
203         if (params().spaceBottom().kind() != VSpace::NONE)
204                 os << "\\added_space_bottom "
205                    << params().spaceBottom().asLyXCommand() << " ";
206
207         // Maybe the paragraph has special spacing
208         params().spacing().writeFile(os, true);
209
210         // The labelwidth string used in lists.
211         if (!params().labelWidthString().empty())
212                 os << "\\labelwidthstring "
213                    << params().labelWidthString() << '\n';
214
215         // Lines above or below?
216         if (params().lineTop())
217                 os << "\\line_top ";
218         if (params().lineBottom())
219                 os << "\\line_bottom ";
220
221         // Pagebreaks above or below?
222         if (params().pagebreakTop())
223                 os << "\\pagebreak_top ";
224         if (params().pagebreakBottom())
225                 os << "\\pagebreak_bottom ";
226
227         // Start of appendix?
228         if (params().startOfAppendix())
229                 os << "\\start_of_appendix ";
230
231         // Noindent?
232         if (params().noindent())
233                 os << "\\noindent ";
234
235         // Alignment?
236         if (params().align() != LYX_ALIGN_LAYOUT) {
237                 int h = 0;
238                 switch (params().align()) {
239                 case LYX_ALIGN_LEFT: h = 1; break;
240                 case LYX_ALIGN_RIGHT: h = 2; break;
241                 case LYX_ALIGN_CENTER: h = 3; break;
242                 default: h = 0; break;
243                 }
244                 os << "\\align " << string_align[h] << " ";
245         }
246
247         // bibitem  ale970302
248         if (bibkey)
249                 bibkey->write(buf, os);
250
251         LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
252
253         int column = 0;
254         for (pos_type i = 0; i < size(); ++i) {
255                 if (!i) {
256                         os << "\n";
257                         column = 0;
258                 }
259
260                 // Write font changes
261                 LyXFont font2 = getFontSettings(bparams, i);
262                 if (font2 != font1) {
263 #ifndef INHERIT_LANGUAGE
264                         font2.lyxWriteChanges(font1, os);
265 #else
266                         font2.lyxWriteChanges(font1, bparams.language, os);
267 #endif
268                         column = 0;
269                         font1 = font2;
270                 }
271
272                 value_type const c = getChar(i);
273                 switch (c) {
274                 case META_INSET:
275                 {
276                         Inset const * inset = getInset(i);
277                         if (inset)
278                                 if (inset->directWrite()) {
279                                         // international char, let it write
280                                         // code directly so it's shorter in
281                                         // the file
282                                         inset->write(buf, os);
283                                 } else {
284                                         os << "\n\\begin_inset ";
285                                         inset->write(buf, os);
286                                         os << "\n\\end_inset \n\n";
287                                         column = 0;
288                                 }
289                 }
290                 break;
291                 case META_NEWLINE:
292                         os << "\n\\newline \n";
293                         column = 0;
294                         break;
295                 case META_HFILL:
296                         os << "\n\\hfill \n";
297                         column = 0;
298                         break;
299                 case '\\':
300                         os << "\n\\backslash \n";
301                         column = 0;
302                         break;
303                 case '.':
304                         if (i + 1 < size() && getChar(i + 1) == ' ') {
305                                 os << ".\n";
306                                 column = 0;
307                         } else
308                                 os << ".";
309                         break;
310                 default:
311                         if ((column > 70 && c == ' ')
312                             || column > 79) {
313                                 os << "\n";
314                                 column = 0;
315                         }
316                         // this check is to amend a bug. LyX sometimes
317                         // inserts '\0' this could cause problems.
318                         if (c != '\0')
319                                 os << c;
320                         else
321                                 lyxerr << "ERROR (Paragraph::writeFile):"
322                                         " NULL char in structure." << endl;
323                         ++column;
324                         break;
325                 }
326         }
327
328         // now write the next paragraph
329         if (next_)
330                 next_->writeFile(buf, os, bparams, dth);
331 }
332
333
334 void Paragraph::validate(LaTeXFeatures & features) const
335 {
336         BufferParams const & bparams = features.bufferParams();
337
338         // check the params.
339         if (params().lineTop() || params().lineBottom())
340                 features.require("lyxline");
341         if (!params().spacing().isDefault())
342                 features.require("setspace");
343
344         // then the layouts
345         features.useLayout(layout());
346
347         // then the fonts
348         Language const * doc_language = bparams.language;
349
350         Pimpl::FontList::const_iterator fcit = pimpl_->fontlist.begin();
351         Pimpl::FontList::const_iterator fend = pimpl_->fontlist.end();
352         for (; fcit != fend; ++fcit) {
353                 if (fcit->font().noun() == LyXFont::ON) {
354                         lyxerr[Debug::LATEX] << "font.noun: "
355                                              << fcit->font().noun()
356                                              << endl;
357                         features.require("noun");
358                         lyxerr[Debug::LATEX] << "Noun enabled. Font: "
359                                              << fcit->font().stateText(0)
360                                              << endl;
361                 }
362                 switch (fcit->font().color()) {
363                 case LColor::none:
364                 case LColor::inherit:
365                 case LColor::ignore:
366                         // probably we should put here all interface colors used for
367                         // font displaying! For now I just add this ones I know of (Jug)
368                 case LColor::latex:
369                 case LColor::note:
370                         break;
371                 default:
372                         features.require("color");
373                         lyxerr[Debug::LATEX] << "Color enabled. Font: "
374                                              << fcit->font().stateText(0)
375                                              << endl;
376                 }
377
378                 Language const * language = fcit->font().language();
379                 if (language->babel() != doc_language->babel() &&
380                     language != ignore_language &&
381 #ifdef INHERIT_LANGUAGE
382                     language != inherit_language &&
383 #endif
384                     language != latex_language)
385                 {
386                         features.useLanguage(language);
387                         lyxerr[Debug::LATEX] << "Found language "
388                                              << language->babel() << endl;
389                 }
390         }
391
392         // then the insets
393         LyXLayout const & lout = textclasslist[bparams.textclass][layout()];
394
395         InsetList::const_iterator icit = insetlist.begin();
396         InsetList::const_iterator iend = insetlist.end();
397         for (; icit != iend; ++icit) {
398                 if (icit->inset) {
399                         icit->inset->validate(features);
400                         if (lout.needprotect &&
401                             icit->inset->lyxCode() == Inset::FOOT_CODE)
402                                 features.require("NeedLyXFootnoteCode");
403                 }
404         }
405 }
406
407
408 // First few functions needed for cut and paste and paragraph breaking.
409 void Paragraph::copyIntoMinibuffer(Buffer const & buffer, pos_type pos) const
410 {
411         BufferParams bparams = buffer.params;
412
413         minibuffer_char = getChar(pos);
414         minibuffer_font = getFontSettings(bparams, pos);
415         minibuffer_inset = 0;
416         if (minibuffer_char == Paragraph::META_INSET) {
417                 if (getInset(pos)) {
418                         minibuffer_inset = getInset(pos)->clone(buffer);
419                 } else {
420                         minibuffer_inset = 0;
421                         minibuffer_char = ' ';
422                         // This reflects what GetInset() does (ARRae)
423                 }
424         }
425 }
426
427
428 void Paragraph::cutIntoMinibuffer(BufferParams const & bparams, pos_type pos)
429 {
430         minibuffer_char = getChar(pos);
431         minibuffer_font = getFontSettings(bparams, pos);
432         minibuffer_inset = 0;
433         if (minibuffer_char == Paragraph::META_INSET) {
434                 if (getInset(pos)) {
435                         minibuffer_inset = getInset(pos);
436                         // This is a little hack since I want exactly
437                         // the inset, not just a clone. Otherwise
438                         // the inset would be deleted when calling Erase(pos)
439                         // find the entry
440                         InsetList::iterator it = insetlist.begin();
441                         InsetList::iterator end = insetlist.end();
442                         for (; it != end; ++it) {
443                                 if (it->pos == pos)
444                                         break;
445                         }
446
447                         if (it != end && it->pos == pos)
448                                 it->inset = 0;
449                         // the inset is not in a paragraph anymore
450                         minibuffer_inset->parOwner(0);
451                 } else {
452                         minibuffer_inset = 0;
453                         minibuffer_char = ' ';
454                         // This reflects what GetInset() does (ARRae)
455                 }
456
457         }
458
459         // Erase(pos); now the caller is responsible for that.
460 }
461
462
463 bool Paragraph::insertFromMinibuffer(pos_type pos)
464 {
465         if (minibuffer_char == Paragraph::META_INSET) {
466                 if (!insetAllowed(minibuffer_inset->lyxCode())) {
467                         return false;
468                 }
469                 insertInset(pos, minibuffer_inset, minibuffer_font);
470         } else {
471                 LyXFont f = minibuffer_font;
472                 if (!checkInsertChar(f)) {
473                         return false;
474                 }
475                 insertChar(pos, minibuffer_char, f);
476         }
477         return true;
478 }
479
480 // end of minibuffer
481
482
483 void Paragraph::erase(pos_type pos)
484 {
485         pimpl_->erase(pos);
486 }
487
488
489 bool Paragraph::checkInsertChar(LyXFont & font)
490 {
491         if (pimpl_->inset_owner)
492                 return pimpl_->inset_owner->checkInsertChar(font);
493         return true;
494 }
495
496
497 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c)
498 {
499         LyXFont const f(LyXFont::ALL_INHERIT);
500         insertChar(pos, c, f);
501 }
502
503
504 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
505                            LyXFont const & font)
506 {
507         pimpl_->insertChar(pos, c, font);
508 }
509
510
511 void Paragraph::insertInset(pos_type pos, Inset * inset)
512 {
513         LyXFont const f(LyXFont::ALL_INHERIT);
514         insertInset(pos, inset, f);
515 }
516
517
518 void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font)
519 {
520         pimpl_->insertInset(pos, inset, font);
521 }
522
523
524 bool Paragraph::insetAllowed(Inset::Code code)
525 {
526         //lyxerr << "Paragraph::InsertInsetAllowed" << endl;
527
528         if (pimpl_->inset_owner)
529                 return pimpl_->inset_owner->insetAllowed(code);
530         return true;
531 }
532
533
534 Inset * Paragraph::getInset(pos_type pos)
535 {
536         lyx::Assert(pos < size());
537
538         // Find the inset.
539         InsetList::iterator it = insetlist.begin();
540         InsetList::iterator end = insetlist.end();
541         for (; it != end; ++it) {
542                 if (it->pos == pos)
543                         break;
544         }
545
546         if (it != end && it->pos == pos)
547                 return it->inset;
548
549         lyxerr << "ERROR (Paragraph::getInset): "
550                << "Inset does not exist: " << pos << endl;
551         //::raise(SIGSTOP);
552
553         // text[pos] = ' '; // WHY!!! does this set the pos to ' '????
554         // Did this commenting out introduce a bug? So far I have not
555         // see any, please enlighten me. (Lgb)
556         // My guess is that since the inset does not exist, we might
557         // as well replace it with a space to prevent craches. (Asger)
558         return 0;
559 }
560
561
562 Inset const * Paragraph::getInset(pos_type pos) const
563 {
564         lyx::Assert(pos < size());
565
566         // Find the inset.
567         InsetList::const_iterator cit = insetlist.begin();
568         InsetList::const_iterator end = insetlist.end();
569         for (; cit != end; ++cit) {
570                 if (cit->pos == pos)
571                         break;
572         }
573
574         if (cit != end && cit->pos == pos)
575                 return cit->inset;
576
577         lyxerr << "ERROR (Paragraph::getInset): "
578                << "Inset does not exist: " << pos << endl;
579         //::raise(SIGSTOP);
580         //text[pos] = ' '; // WHY!!! does this set the pos to ' '????
581         // Did this commenting out introduce a bug? So far I have not
582         // see any, please enlighten me. (Lgb)
583         // My guess is that since the inset does not exist, we might
584         // as well replace it with a space to prevent craches. (Asger)
585         return 0;
586 }
587
588
589 // Gets uninstantiated font setting at position.
590 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
591                                          pos_type pos) const
592 {
593         lyx::Assert(pos <= size());
594
595         Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
596         Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
597         for (; cit != end; ++cit) {
598                 if (cit->pos() >= pos)
599                         break;
600         }
601
602         LyXFont retfont;
603         if (cit != end) {
604                 retfont = cit->font();
605         } else if (pos == size() && size()) {
606                 retfont = getFontSettings(bparams, pos - 1);
607         } else
608                 retfont = LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
609 #ifdef INHERIT_LANGUAGE
610         if (retfont.language() == inherit_language)
611                 retfont.setLanguage(bparams.language);
612 #endif
613
614         return retfont;
615 }
616
617
618 // Gets uninstantiated font setting at position 0
619 LyXFont const Paragraph::getFirstFontSettings() const
620 {
621         if (size() > 0 && !pimpl_->fontlist.empty())
622                 return pimpl_->fontlist[0].font();
623
624         return LyXFont(LyXFont::ALL_INHERIT);
625 }
626
627
628 // Gets the fully instantiated font at a given position in a paragraph
629 // This is basically the same function as LyXText::GetFont() in text2.C.
630 // The difference is that this one is used for generating the LaTeX file,
631 // and thus cosmetic "improvements" are disallowed: This has to deliver
632 // the true picture of the buffer. (Asger)
633 // If position is -1, we get the layout font of the paragraph.
634 // If position is -2, we get the font of the manual label of the paragraph.
635 LyXFont const Paragraph::getFont(BufferParams const & bparams,
636                                  pos_type pos) const
637 {
638         lyx::Assert(pos >= 0);
639
640         LyXLayout const & lout =
641                 textclasslist[bparams.textclass][layout()];
642         pos_type main_body = 0;
643         if (lout.labeltype == LABEL_MANUAL)
644                 main_body = beginningOfMainBody();
645
646         LyXFont layoutfont;
647         if (pos < main_body)
648                 layoutfont = lout.labelfont;
649         else
650                 layoutfont = lout.font;
651
652         LyXFont tmpfont = getFontSettings(bparams, pos);
653 #ifndef INHERIT_LANGUAGE
654         tmpfont.realize(layoutfont);
655 #else
656         tmpfont.realize(layoutfont, bparams.language);
657 #endif
658
659         return pimpl_->realizeFont(tmpfont, bparams);
660 }
661
662
663 LyXFont const Paragraph::getLabelFont(BufferParams const & bparams) const
664 {
665         LyXLayout const & lout =
666                 textclasslist[bparams.textclass][layout()];
667
668         LyXFont tmpfont = lout.labelfont;
669         tmpfont.setLanguage(getParLanguage(bparams));
670
671         return pimpl_->realizeFont(tmpfont, bparams);
672 }
673
674
675 LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams) const
676 {
677         LyXLayout const & lout =
678                 textclasslist[bparams.textclass][layout()];
679
680         LyXFont tmpfont = lout.font;
681         tmpfont.setLanguage(getParLanguage(bparams));
682
683         return pimpl_->realizeFont(tmpfont, bparams);
684 }
685
686
687 /// Returns the height of the highest font in range
688 LyXFont::FONT_SIZE
689 Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
690                               LyXFont::FONT_SIZE const def_size) const
691 {
692         if (pimpl_->fontlist.empty())
693                 return def_size;
694
695         Pimpl::FontList::const_iterator end_it = pimpl_->fontlist.begin();
696         Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
697         for (; end_it != end; ++end_it) {
698                 if (end_it->pos() >= endpos)
699                         break;
700         }
701
702         if (end_it != end)
703                 ++end_it;
704
705         Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
706         for (; cit != end; ++cit) {
707                 if (cit->pos() >= startpos)
708                         break;
709         }
710
711         LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
712         for (; cit != end_it; ++cit) {
713                 LyXFont::FONT_SIZE size = cit->font().size();
714                 if (size == LyXFont::INHERIT_SIZE)
715                         size = def_size;
716                 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
717                         maxsize = size;
718         }
719         return maxsize;
720 }
721
722
723 Paragraph::value_type
724 Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
725 {
726         value_type c = getChar(pos);
727         if (!lyxrc.rtl_support)
728                 return c;
729
730         value_type uc = c;
731         switch (c) {
732         case '(':
733                 uc = ')';
734                 break;
735         case ')':
736                 uc = '(';
737                 break;
738         case '[':
739                 uc = ']';
740                 break;
741         case ']':
742                 uc = '[';
743                 break;
744         case '{':
745                 uc = '}';
746                 break;
747         case '}':
748                 uc = '{';
749                 break;
750         case '<':
751                 uc = '>';
752                 break;
753         case '>':
754                 uc = '<';
755                 break;
756         }
757         if (uc != c && getFontSettings(bparams, pos).isRightToLeft())
758                 return uc;
759         else
760                 return c;
761 }
762
763
764 void Paragraph::setFont(pos_type pos, LyXFont const & font)
765 {
766         lyx::Assert(pos <= size());
767
768         // First, reduce font against layout/label font
769         // Update: The SetCharFont() routine in text2.C already
770         // reduces font, so we don't need to do that here. (Asger)
771         // No need to simplify this because it will disappear
772         // in a new kernel. (Asger)
773         // Next search font table
774
775         Pimpl::FontList::iterator beg = pimpl_->fontlist.begin();
776         Pimpl::FontList::iterator it = beg;
777         Pimpl::FontList::iterator endit = pimpl_->fontlist.end();
778         for (; it != endit; ++it) {
779                 if (it->pos() >= pos)
780                         break;
781         }
782         unsigned int i = std::distance(beg, it);
783         bool notfound = (it == endit);
784
785         if (!notfound && pimpl_->fontlist[i].font() == font)
786                 return;
787
788         bool begin = pos == 0 || notfound ||
789                 (i > 0 && pimpl_->fontlist[i - 1].pos() == pos - 1);
790         // Is position pos is a beginning of a font block?
791         bool end = !notfound && pimpl_->fontlist[i].pos() == pos;
792         // Is position pos is the end of a font block?
793         if (begin && end) { // A single char block
794                 if (i + 1 < pimpl_->fontlist.size() &&
795                     pimpl_->fontlist[i + 1].font() == font) {
796                         // Merge the singleton block with the next block
797                         pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
798                         if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
799                                 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i-1);
800                 } else if (i > 0 && pimpl_->fontlist[i - 1].font() == font) {
801                         // Merge the singleton block with the previous block
802                         pimpl_->fontlist[i - 1].pos(pos);
803                         pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
804                 } else
805                         pimpl_->fontlist[i].font(font);
806         } else if (begin) {
807                 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
808                         pimpl_->fontlist[i - 1].pos(pos);
809                 else
810                         pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
811                                         Pimpl::FontTable(pos, font));
812         } else if (end) {
813                 pimpl_->fontlist[i].pos(pos - 1);
814                 if (!(i + 1 < pimpl_->fontlist.size() &&
815                       pimpl_->fontlist[i + 1].font() == font))
816                         pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
817                                         Pimpl::FontTable(pos, font));
818         } else { // The general case. The block is splitted into 3 blocks
819                 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
820                                 Pimpl::FontTable(pos - 1, pimpl_->fontlist[i].font()));
821                 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
822                                 Pimpl::FontTable(pos, font));
823         }
824 }
825
826
827
828 void Paragraph::next(Paragraph * p)
829 {
830         next_ = p;
831 }
832
833
834 // This function is able to hide closed footnotes.
835 Paragraph * Paragraph::next()
836 {
837         return next_;
838 }
839
840
841 Paragraph const * Paragraph::next() const
842 {
843         return next_;
844 }
845
846
847 void Paragraph::previous(Paragraph * p)
848 {
849         previous_ = p;
850 }
851
852
853 // This function is able to hide closed footnotes.
854 Paragraph * Paragraph::previous()
855 {
856         return previous_;
857 }
858
859
860 // This function is able to hide closed footnotes.
861 Paragraph const * Paragraph::previous() const
862 {
863         return previous_;
864 }
865
866
867 void Paragraph::breakParagraph(BufferParams const & bparams,
868                                   pos_type pos,
869                                   int flag)
870 {
871         // create a new paragraph
872         Paragraph * tmp = new Paragraph(this);
873         tmp->layout(textclasslist[bparams.textclass].defaultLayoutName());
874
875         // remember to set the inset_owner
876         tmp->setInsetOwner(inInset());
877
878         // this is an idea for a more userfriendly layout handling, I will
879         // see what the users say
880
881         // layout stays the same with latex-environments
882         if (flag) {
883                 tmp->layout(layout());
884                 tmp->setLabelWidthString(params().labelWidthString());
885         }
886
887         if (size() > pos || !size() || flag == 2) {
888                 tmp->layout(layout());
889                 tmp->params().align(params().align());
890                 tmp->setLabelWidthString(params().labelWidthString());
891
892                 tmp->params().lineBottom(params().lineBottom());
893                 params().lineBottom(false);
894                 tmp->params().pagebreakBottom(params().pagebreakBottom());
895                 params().pagebreakBottom(false);
896                 tmp->params().spaceBottom(params().spaceBottom());
897                 params().spaceBottom(VSpace(VSpace::NONE));
898
899                 tmp->params().depth(params().depth());
900                 tmp->params().noindent(params().noindent());
901
902                 // copy everything behind the break-position
903                 // to the new paragraph
904                 pos_type pos_end = size() - 1;
905                 pos_type i = pos;
906                 pos_type j = pos;
907                 for (; i <= pos_end; ++i) {
908                         cutIntoMinibuffer(bparams, i);
909                         if (tmp->insertFromMinibuffer(j - pos))
910                                 ++j;
911                 }
912                 for (i = pos_end; i >= pos; --i) {
913                         erase(i);
914                 }
915         }
916
917         // just an idea of me
918         if (!pos) {
919                 tmp->params().lineTop(params().lineTop());
920                 tmp->params().pagebreakTop(params().pagebreakTop());
921                 tmp->params().spaceTop(params().spaceTop());
922                 tmp->bibkey = bibkey;
923
924                 bibkey = 0;
925                 params().clear();
926                 layout(textclasslist[bparams.textclass].defaultLayoutName());
927
928                 // layout stays the same with latex-environments
929                 if (flag) {
930                         layout(tmp->layout());
931                         setLabelWidthString(tmp->params().labelWidthString());
932                         params().depth(tmp->params().depth());
933                 }
934         }
935 }
936
937
938 void Paragraph::makeSameLayout(Paragraph const * par)
939 {
940         layout(par->layout());
941         // move to pimpl?
942         params() = par->params();
943 }
944
945
946 int Paragraph::stripLeadingSpaces(lyx::textclass_type tclass)
947 {
948         if (textclasslist[tclass][layout()].free_spacing ||
949             isFreeSpacing()) {
950                 return 0;
951         }
952
953         int i = 0;
954         while (size() && (isNewline(0) || isLineSeparator(0))) {
955                 erase(0);
956                 ++i;
957         }
958
959         return i;
960 }
961
962
963 bool Paragraph::hasSameLayout(Paragraph const * par) const
964 {
965         return
966                 par->layout() == layout() &&
967                 params().sameLayout(par->params());
968 }
969
970
971 void Paragraph::breakParagraphConservative(BufferParams const & bparams,
972                                            pos_type pos)
973 {
974         // create a new paragraph
975         Paragraph * tmp = new Paragraph(this);
976         tmp->makeSameLayout(this);
977
978         // When can pos > Last()?
979         // I guess pos == Last() is possible.
980         if (size() > pos) {
981                 // copy everything behind the break-position to the new
982                 // paragraph
983                 pos_type pos_end = size() - 1;
984
985                 //pos_type i = pos;
986                 //pos_type j = pos;
987                 for (pos_type i = pos, j = pos; i <= pos_end; ++i) {
988                         cutIntoMinibuffer(bparams, i);
989                         if (tmp->insertFromMinibuffer(j - pos))
990                                 ++j;
991                 }
992
993                 for (pos_type k = pos_end; k >= pos; --k) {
994                         erase(k);
995                 }
996         }
997 }
998
999
1000 // Be carefull, this does not make any check at all.
1001 // This method has wrong name, it combined this par with the next par.
1002 // In that sense it is the reverse of break paragraph. (Lgb)
1003 void Paragraph::pasteParagraph(BufferParams const & bparams)
1004 {
1005         // copy the next paragraph to this one
1006         Paragraph * the_next = next();
1007
1008         // first the DTP-stuff
1009         params().lineBottom(the_next->params().lineBottom());
1010         params().spaceBottom(the_next->params().spaceBottom());
1011         params().pagebreakBottom(the_next->params().pagebreakBottom());
1012
1013         pos_type pos_end = the_next->pimpl_->size() - 1;
1014         pos_type pos_insert = size();
1015
1016         // ok, now copy the paragraph
1017         for (pos_type i = 0, j = 0; i <= pos_end; ++i) {
1018                 the_next->cutIntoMinibuffer(bparams, i);
1019                 if (insertFromMinibuffer(pos_insert + j))
1020                         ++j;
1021         }
1022
1023         // delete the next paragraph
1024         Paragraph * ppar = the_next->previous_;
1025         Paragraph * npar = the_next->next_;
1026         delete the_next;
1027         ppar->next(npar);
1028 }
1029
1030
1031 int Paragraph::getEndLabel(BufferParams const & bparams) const
1032 {
1033         Paragraph const * par = this;
1034         depth_type par_depth = getDepth();
1035         while (par) {
1036                 string const & layout = par->layout();
1037                 int const endlabeltype =
1038                         textclasslist[bparams.textclass][layout].endlabeltype;
1039                 if (endlabeltype != END_LABEL_NO_LABEL) {
1040                         if (!next_)
1041                                 return endlabeltype;
1042
1043                         depth_type const next_depth = next_->getDepth();
1044                         if (par_depth > next_depth ||
1045                             (par_depth == next_depth
1046                              && layout != next_->layout()))
1047                                 return endlabeltype;
1048                         break;
1049                 }
1050                 if (par_depth == 0)
1051                         break;
1052                 par = par->outerHook();
1053                 if (par)
1054                         par_depth = par->getDepth();
1055         }
1056         return END_LABEL_NO_LABEL;
1057 }
1058
1059
1060 Paragraph::depth_type Paragraph::getDepth() const
1061 {
1062         return params().depth();
1063 }
1064
1065
1066 Paragraph::depth_type Paragraph::getMaxDepthAfter(Buffer const * buffer) const
1067 {
1068         bool const isenv = textclasslist[buffer->params.textclass][layout()].isEnvironment();
1069
1070         if (isenv)
1071                 return params().depth() + 1;
1072         else
1073                 return params().depth();
1074
1075 }
1076
1077 char Paragraph::getAlign() const
1078 {
1079         return params().align();
1080 }
1081
1082
1083 string const & Paragraph::getLabelstring() const
1084 {
1085         return params().labelString();
1086 }
1087
1088
1089 int Paragraph::getFirstCounter(int i) const
1090 {
1091         return pimpl_->counter_[i];
1092 }
1093
1094
1095 // the next two functions are for the manual labels
1096 string const Paragraph::getLabelWidthString() const
1097 {
1098         if (!params().labelWidthString().empty())
1099                 return params().labelWidthString();
1100         else
1101                 return _("Senseless with this layout!");
1102 }
1103
1104
1105 void Paragraph::setLabelWidthString(string const & s)
1106 {
1107         params().labelWidthString(s);
1108 }
1109
1110
1111 void Paragraph::applyLayout(string const & new_layout)
1112 {
1113         layout(new_layout);
1114         params().labelWidthString(string());
1115         params().align(LYX_ALIGN_LAYOUT);
1116         params().spaceTop(VSpace(VSpace::NONE));
1117         params().spaceBottom(VSpace(VSpace::NONE));
1118         params().spacing(Spacing(Spacing::Default));
1119 }
1120
1121
1122 // if the layout of a paragraph contains a manual label, the beginning of the
1123 // main body is the beginning of the second word. This is what the par-
1124 // function returns. If the layout does not contain a label, the main
1125 // body always starts with position 0. This differentiation is necessary,
1126 // because there cannot be a newline or a blank <= the beginning of the
1127 // main body in TeX.
1128
1129 int Paragraph::beginningOfMainBody() const
1130 {
1131         // Unroll the first two cycles of the loop
1132         // and remember the previous character to
1133         // remove unnecessary GetChar() calls
1134         pos_type i = 0;
1135         if (i < size()
1136             && getChar(i) != Paragraph::META_NEWLINE) {
1137                 ++i;
1138                 char previous_char = 0;
1139                 char temp = 0;
1140                 if (i < size()
1141                     && (previous_char = getChar(i)) != Paragraph::META_NEWLINE) {
1142                         // Yes, this  ^ is supposed to be "= " not "=="
1143                         ++i;
1144                         while (i < size()
1145                                && previous_char != ' '
1146                                && (temp = getChar(i)) != Paragraph::META_NEWLINE) {
1147                                 ++i;
1148                                 previous_char = temp;
1149                         }
1150                 }
1151         }
1152
1153         return i;
1154 }
1155
1156
1157 Paragraph * Paragraph::depthHook(depth_type depth)
1158 {
1159         Paragraph * newpar = this;
1160
1161         do {
1162                 newpar = newpar->previous();
1163         } while (newpar && newpar->getDepth() > depth);
1164
1165         if (!newpar) {
1166                 if (previous() || getDepth())
1167                         lyxerr << "ERROR (Paragraph::DepthHook): "
1168                                 "no hook." << endl;
1169                 newpar = this;
1170         }
1171
1172         return newpar;
1173 }
1174
1175
1176 Paragraph const * Paragraph::depthHook(depth_type depth) const
1177 {
1178         Paragraph const * newpar = this;
1179
1180         do {
1181                 newpar = newpar->previous();
1182         } while (newpar && newpar->getDepth() > depth);
1183
1184         if (!newpar) {
1185                 if (previous() || getDepth())
1186                         lyxerr << "ERROR (Paragraph::DepthHook): "
1187                                 "no hook." << endl;
1188                 newpar = this;
1189         }
1190
1191         return newpar;
1192 }
1193
1194 Paragraph * Paragraph::outerHook()
1195 {
1196         if (!getDepth())
1197                 return 0;
1198         return depthHook(depth_type(getDepth() - 1));
1199 }
1200
1201 Paragraph const * Paragraph::outerHook() const
1202 {
1203         if (!getDepth())
1204                 return 0;
1205         return depthHook(depth_type(getDepth() - 1));
1206 }
1207
1208
1209 Paragraph::inset_iterator
1210 Paragraph::InsetIterator(pos_type pos)
1211 {
1212         InsetList::iterator it = insetlist.begin();
1213         InsetList::iterator end = insetlist.end();
1214         for (; it != end; ++it) {
1215                 if (it->pos == pos)
1216                         break;
1217         }
1218
1219         return inset_iterator(it);
1220 }
1221
1222
1223 // returns -1 if inset not found
1224 int Paragraph::getPositionOfInset(Inset const * inset) const
1225 {
1226         // Find the entry.
1227         InsetList::const_iterator cit = insetlist.begin();
1228         InsetList::const_iterator end = insetlist.end();
1229         for (; cit != end; ++cit) {
1230                 if (cit->inset == inset) {
1231                         return cit->pos;
1232                 }
1233         }
1234         if (inset == bibkey)
1235                 return 0;
1236
1237         return -1;
1238 }
1239
1240
1241 Paragraph * Paragraph::TeXOnePar(Buffer const * buf,
1242                                  BufferParams const & bparams,
1243                                  ostream & os, TexRow & texrow,
1244                                  bool moving_arg)
1245 {
1246         lyxerr[Debug::LATEX] << "TeXOnePar...     " << this << endl;
1247         Inset const * in = inInset();
1248         bool further_blank_line = false;
1249         LyXLayout style;
1250
1251         // well we have to check if we are in an inset with unlimited
1252         // lenght (all in one row) if that is true then we don't allow
1253         // any special options in the paragraph and also we don't allow
1254         // any environment other then "Standard" to be valid!
1255         if ((in == 0) || !in->forceDefaultParagraphs(in)) {
1256                 style = textclasslist[bparams.textclass][layout()];
1257
1258                 if (params().startOfAppendix()) {
1259                         os << "\\appendix\n";
1260                         texrow.newline();
1261                 }
1262
1263                 if (!params().spacing().isDefault()
1264                         && (!previous() || !previous()->hasSameLayout(this))) {
1265                         os << params().spacing().writeEnvirBegin() << "\n";
1266                         texrow.newline();
1267                 }
1268
1269                 if (tex_code_break_column && style.isCommand()) {
1270                         os << '\n';
1271                         texrow.newline();
1272                 }
1273
1274                 if (params().pagebreakTop()) {
1275                         os << "\\newpage";
1276                         further_blank_line = true;
1277                 }
1278                 if (params().spaceTop().kind() != VSpace::NONE) {
1279                         os << params().spaceTop().asLatexCommand(bparams);
1280                         further_blank_line = true;
1281                 }
1282
1283                 if (params().lineTop()) {
1284                         os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
1285                            << "\\vspace{-1\\parskip}";
1286                         further_blank_line = true;
1287                 }
1288
1289                 if (further_blank_line) {
1290                         os << '\n';
1291                         texrow.newline();
1292                 }
1293         } else {
1294                 style = textclasslist[bparams.textclass].defaultLayout();
1295         }
1296
1297         Language const * language = getParLanguage(bparams);
1298         Language const * doc_language = bparams.language;
1299         Language const * previous_language = previous()
1300                 ? previous()->getParLanguage(bparams) : doc_language;
1301
1302         if (language->babel() != previous_language->babel()
1303             // check if we already put language command in TeXEnvironment()
1304             && !(style.isEnvironment()
1305                  && (!previous() || previous()->layout() != layout() ||
1306                          previous()->params().depth() != params().depth())))
1307         {
1308                 if (!lyxrc.language_command_end.empty() &&
1309                     previous_language->babel() != doc_language->babel())
1310                 {
1311                         os << subst(lyxrc.language_command_end, "$$lang",
1312                                     previous_language->babel())
1313                            << endl;
1314                         texrow.newline();
1315                 }
1316
1317                 if (lyxrc.language_command_end.empty() ||
1318                     language->babel() != doc_language->babel())
1319                 {
1320                         os << subst(lyxrc.language_command_begin, "$$lang",
1321                                     language->babel())
1322                            << endl;
1323                         texrow.newline();
1324                 }
1325         }
1326
1327         if (bparams.inputenc == "auto" &&
1328             language->encoding() != previous_language->encoding()) {
1329                 os << "\\inputencoding{"
1330                    << language->encoding()->LatexName()
1331                    << "}" << endl;
1332                 texrow.newline();
1333         }
1334
1335         switch (style.latextype) {
1336         case LATEX_COMMAND:
1337                 os << '\\'
1338                    << style.latexname()
1339                    << style.latexparam();
1340                 break;
1341         case LATEX_ITEM_ENVIRONMENT:
1342                 if (bibkey) {
1343                         bibkey->latex(buf, os, false, false);
1344                 } else
1345                         os << "\\item ";
1346                 break;
1347         case LATEX_LIST_ENVIRONMENT:
1348                 os << "\\item ";
1349                 break;
1350         default:
1351                 break;
1352         }
1353
1354         bool need_par = simpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
1355
1356         // Make sure that \\par is done with the font of the last
1357         // character if this has another size as the default.
1358         // This is necessary because LaTeX (and LyX on the screen)
1359         // calculates the space between the baselines according
1360         // to this font. (Matthias)
1361         //
1362         // Is this really needed ? (Dekel)
1363         // We do not need to use to change the font for the last paragraph
1364         // or for a command.
1365         LyXFont const font =
1366                 (size() == 0
1367                  ? getLayoutFont(bparams) : getFont(bparams, size() - 1));
1368
1369         bool is_command = style.isCommand();
1370
1371         if (style.resfont.size() != font.size() && next_ && !is_command) {
1372                 if (!need_par)
1373                         os << "{";
1374                 os << "\\" << font.latexSize() << " \\par}";
1375         } else if (need_par) {
1376                 os << "\\par}";
1377         } else if (is_command)
1378                 os << "}";
1379
1380         switch (style.latextype) {
1381         case LATEX_ITEM_ENVIRONMENT:
1382         case LATEX_LIST_ENVIRONMENT:
1383                 if (next_ && (params().depth() < next_->params().depth())) {
1384                         os << '\n';
1385                         texrow.newline();
1386                 }
1387                 break;
1388         case LATEX_ENVIRONMENT:
1389                 // if its the last paragraph of the current environment
1390                 // skip it otherwise fall through
1391                 if (next_
1392                     && (next_->layout() != layout()
1393                         || next_->params().depth() != params().depth()))
1394                         break;
1395                 // fall through possible
1396         default:
1397                 // we don't need it for the last paragraph!!!
1398                 if (next_) {
1399                         os << '\n';
1400                         texrow.newline();
1401                 }
1402         }
1403
1404         if ((in == 0) || !in->forceDefaultParagraphs(in)) {
1405                 further_blank_line = false;
1406                 if (params().lineBottom()) {
1407                         os << "\\lyxline{\\" << font.latexSize() << '}';
1408                         further_blank_line = true;
1409                 }
1410
1411                 if (params().spaceBottom().kind() != VSpace::NONE) {
1412                         os << params().spaceBottom().asLatexCommand(bparams);
1413                         further_blank_line = true;
1414                 }
1415
1416                 if (params().pagebreakBottom()) {
1417                         os << "\\newpage";
1418                         further_blank_line = true;
1419                 }
1420
1421                 if (further_blank_line) {
1422                         os << '\n';
1423                         texrow.newline();
1424                 }
1425
1426                 if (!params().spacing().isDefault()
1427                         && (!next_ || !next_->hasSameLayout(this))) {
1428                         os << params().spacing().writeEnvirEnd() << "\n";
1429                         texrow.newline();
1430                 }
1431         }
1432
1433         // we don't need it for the last paragraph!!!
1434         if (next_) {
1435                 os << '\n';
1436                 texrow.newline();
1437         } else {
1438                 // Since \selectlanguage write the language to the aux file,
1439                 // we need to reset the language at the end of footnote or
1440                 // float.
1441
1442                 if (language->babel() != doc_language->babel()) {
1443                         if (lyxrc.language_command_end.empty())
1444                                 os << subst(lyxrc.language_command_begin,
1445                                             "$$lang",
1446                                             doc_language->babel())
1447                                    << endl;
1448                         else
1449                                 os << subst(lyxrc.language_command_end,
1450                                             "$$lang",
1451                                             language->babel())
1452                                    << endl;
1453                         texrow.newline();
1454                 }
1455         }
1456
1457         lyxerr[Debug::LATEX] << "TeXOnePar...done " << next_ << endl;
1458         return next_;
1459 }
1460
1461 // This could go to ParagraphParameters if we want to
1462 int Paragraph::startTeXParParams(BufferParams const & bparams,
1463                                  ostream & os) const
1464 {
1465         int column = 0;
1466
1467         if (params().noindent()) {
1468                 os << "\\noindent ";
1469                 column += 10;
1470         }
1471
1472         switch (params().align()) {
1473         case LYX_ALIGN_NONE:
1474         case LYX_ALIGN_BLOCK:
1475         case LYX_ALIGN_LAYOUT:
1476         case LYX_ALIGN_SPECIAL:
1477                 break;
1478         case LYX_ALIGN_LEFT:
1479                 if (getParLanguage(bparams)->babel() != "hebrew") {
1480                         os << "\\begin{flushleft}";
1481                         column += 17;
1482                 } else {
1483                         os << "\\begin{flushright}";
1484                         column += 18;
1485                 }
1486                 break;
1487         case LYX_ALIGN_RIGHT:
1488                 if (getParLanguage(bparams)->babel() != "hebrew") {
1489                         os << "\\begin{flushright}";
1490                         column += 18;
1491                 } else {
1492                         os << "\\begin{flushleft}";
1493                         column += 17;
1494                 }
1495                 break;
1496         case LYX_ALIGN_CENTER:
1497                 os << "\\begin{center}";
1498                 column += 14;
1499                 break;
1500         }
1501
1502         return column;
1503 }
1504
1505 // This could go to ParagraphParameters if we want to
1506 int Paragraph::endTeXParParams(BufferParams const & bparams,
1507                                ostream & os) const
1508 {
1509         int column = 0;
1510
1511         switch (params().align()) {
1512         case LYX_ALIGN_NONE:
1513         case LYX_ALIGN_BLOCK:
1514         case LYX_ALIGN_LAYOUT:
1515         case LYX_ALIGN_SPECIAL:
1516                 break;
1517         case LYX_ALIGN_LEFT:
1518                 if (getParLanguage(bparams)->babel() != "hebrew") {
1519                         os << "\\end{flushleft}";
1520                         column = 15;
1521                 } else {
1522                         os << "\\end{flushright}";
1523                         column = 16;
1524                 }
1525                 break;
1526         case LYX_ALIGN_RIGHT:
1527                 if (getParLanguage(bparams)->babel() != "hebrew") {
1528                         os << "\\end{flushright}";
1529                         column+= 16;
1530                 } else {
1531                         os << "\\end{flushleft}";
1532                         column = 15;
1533                 }
1534                 break;
1535         case LYX_ALIGN_CENTER:
1536                 os << "\\end{center}";
1537                 column = 12;
1538                 break;
1539         }
1540         return column;
1541 }
1542
1543
1544 // This one spits out the text of the paragraph
1545 bool Paragraph::simpleTeXOnePar(Buffer const * buf,
1546                                 BufferParams const & bparams,
1547                                 ostream & os, TexRow & texrow,
1548                                 bool moving_arg)
1549 {
1550         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...     " << this << endl;
1551
1552         bool return_value = false;
1553
1554         LyXLayout style;
1555
1556         // well we have to check if we are in an inset with unlimited
1557         // lenght (all in one row) if that is true then we don't allow
1558         // any special options in the paragraph and also we don't allow
1559         // any environment other then "Standard" to be valid!
1560         bool asdefault =
1561                 (inInset() && inInset()->forceDefaultParagraphs(inInset()));
1562
1563         if (asdefault) {
1564                 style = textclasslist[bparams.textclass].defaultLayout();
1565         } else {
1566                 style = textclasslist[bparams.textclass][layout()];
1567         }
1568
1569         LyXFont basefont;
1570
1571         // Maybe we have to create a optional argument.
1572         pos_type main_body;
1573         if (style.labeltype != LABEL_MANUAL)
1574                 main_body = 0;
1575         else
1576                 main_body = beginningOfMainBody();
1577
1578         int column = 0;
1579
1580         if (main_body > 0) {
1581                 os << '[';
1582                 ++column;
1583                 basefont = getLabelFont(bparams);
1584         } else {
1585                 basefont = getLayoutFont(bparams);
1586         }
1587
1588         moving_arg |= style.needprotect;
1589
1590         // Which font is currently active?
1591         LyXFont running_font(basefont);
1592         // Do we have an open font change?
1593         bool open_font = false;
1594
1595         texrow.start(this, 0);
1596
1597         // if the paragraph is empty, the loop will not be entered at all
1598         if (!size()) {
1599                 if (style.isCommand()) {
1600                         os << '{';
1601                         ++column;
1602                 }
1603                 if (!asdefault)
1604                         column += startTeXParParams(bparams, os);
1605
1606         }
1607
1608         for (pos_type i = 0; i < size(); ++i) {
1609                 ++column;
1610                 // First char in paragraph or after label?
1611                 if (i == main_body) {
1612                         if (main_body > 0) {
1613                                 if (open_font) {
1614                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
1615                                         open_font = false;
1616                                 }
1617                                 basefont = getLayoutFont(bparams);
1618                                 running_font = basefont;
1619                                 os << ']';
1620                                 ++column;
1621                         }
1622                         if (style.isCommand()) {
1623                                 os << '{';
1624                                 ++column;
1625                         }
1626
1627                         if (!asdefault)
1628                                 column += startTeXParParams(bparams, os);
1629                 }
1630
1631                 value_type c = getChar(i);
1632
1633                 // Fully instantiated font
1634                 LyXFont font = getFont(bparams, i);
1635
1636                 LyXFont const & last_font = running_font;
1637
1638                 // Spaces at end of font change are simulated to be
1639                 // outside font change, i.e. we write "\textXX{text} "
1640                 // rather than "\textXX{text }". (Asger)
1641                 if (open_font && c == ' ' && i <= size() - 2) {
1642                         LyXFont const & next_font = getFont(bparams, i + 1);
1643                         if (next_font != running_font
1644                             && next_font != font) {
1645                                 font = next_font;
1646                         }
1647                 }
1648
1649                 // We end font definition before blanks
1650                 if (font != running_font && open_font) {
1651                         column += running_font.latexWriteEndChanges(os,
1652                                                                     basefont,
1653                                                                     (i == main_body-1) ? basefont : font);
1654                         running_font = basefont;
1655                         open_font = false;
1656                 }
1657
1658                 // Blanks are printed before start of fontswitch
1659                 if (c == ' ') {
1660                         // Do not print the separation of the optional argument
1661                         if (i != main_body - 1) {
1662                                 pimpl_->simpleTeXBlanks(os, texrow, i,
1663                                                        column, font, style);
1664                         }
1665                 }
1666
1667                 // Do we need to change font?
1668                 if (font != running_font && i != main_body - 1) {
1669                         column += font.latexWriteStartChanges(os, basefont,
1670                                                               last_font);
1671                         running_font = font;
1672                         open_font = true;
1673                 }
1674
1675                 if (c == Paragraph::META_NEWLINE) {
1676                         // newlines are handled differently here than
1677                         // the default in SimpleTeXSpecialChars().
1678                         if (!style.newline_allowed) {
1679                                 os << '\n';
1680                         } else {
1681                                 if (open_font) {
1682                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
1683                                         open_font = false;
1684                                 }
1685                                 basefont = getLayoutFont(bparams);
1686                                 running_font = basefont;
1687                                 if (font.family() ==
1688                                     LyXFont::TYPEWRITER_FAMILY) {
1689                                         os << "~";
1690                                 }
1691                                 if (moving_arg)
1692                                         os << "\\protect ";
1693                                 os << "\\\\\n";
1694                         }
1695                         texrow.newline();
1696                         texrow.start(this, i + 1);
1697                         column = 0;
1698                 } else {
1699                         pimpl_->simpleTeXSpecialChars(buf, bparams,
1700                                                       os, texrow, moving_arg,
1701                                                       font, running_font,
1702                                                       basefont, open_font,
1703                                                       style, i, column, c);
1704                 }
1705         }
1706
1707         // If we have an open font definition, we have to close it
1708         if (open_font) {
1709 #ifdef FIXED_LANGUAGE_END_DETECTION
1710                 if (next_) {
1711                         running_font
1712                                 .latexWriteEndChanges(os, basefont,
1713                                                       next_->getFont(bparams,
1714                                                       0));
1715                 } else {
1716                         running_font.latexWriteEndChanges(os, basefont,
1717                                                           basefont);
1718                 }
1719 #else
1720 #ifdef WITH_WARNINGS
1721 //#warning For now we ALWAYS have to close the foreign font settings if they are
1722 //#warning there as we start another \selectlanguage with the next paragraph if
1723 //#warning we are in need of this. This should be fixed sometime (Jug)
1724 #endif
1725                 running_font.latexWriteEndChanges(os, basefont,  basefont);
1726 #endif
1727         }
1728
1729         // Needed if there is an optional argument but no contents.
1730         if (main_body > 0 && main_body == size()) {
1731                 os << "]~";
1732                 return_value = false;
1733         }
1734
1735         if (!asdefault) {
1736                 column += endTeXParParams(bparams, os);
1737         }
1738
1739         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
1740         return return_value;
1741 }
1742
1743
1744 bool Paragraph::sgmlConvertChar(char c, string & sgml_string)
1745 {
1746         bool retval = false;
1747         switch (c) {
1748         case Paragraph::META_HFILL:
1749                 sgml_string.erase();
1750                 break;
1751         case Paragraph::META_NEWLINE:
1752                 sgml_string = '\n';
1753                 break;
1754         case '&':
1755                 sgml_string = "&amp;";
1756                 break;
1757         case '<':
1758                 sgml_string = "&lt;";
1759                 break;
1760         case '>':
1761                 sgml_string = "&gt;";
1762                 break;
1763         case '$':
1764                 sgml_string = "&dollar;";
1765                 break;
1766         case '#':
1767                 sgml_string = "&num;";
1768                 break;
1769         case '%':
1770                 sgml_string = "&percnt;";
1771                 break;
1772         case '[':
1773                 sgml_string = "&lsqb;";
1774                 break;
1775         case ']':
1776                 sgml_string = "&rsqb;";
1777                 break;
1778         case '{':
1779                 sgml_string = "&lcub;";
1780                 break;
1781         case '}':
1782                 sgml_string = "&rcub;";
1783                 break;
1784         case '~':
1785                 sgml_string = "&tilde;";
1786                 break;
1787         case '"':
1788                 sgml_string = "&quot;";
1789                 break;
1790         case '\\':
1791                 sgml_string = "&bsol;";
1792                 break;
1793         case ' ':
1794                 retval = true;
1795                 sgml_string = ' ';
1796                 break;
1797         case '\0': // Ignore :-)
1798                 sgml_string.erase();
1799                 break;
1800         default:
1801                 sgml_string = c;
1802                 break;
1803         }
1804         return retval;
1805 }
1806
1807
1808 Paragraph * Paragraph::TeXEnvironment(Buffer const * buf,
1809                                             BufferParams const & bparams,
1810                                             ostream & os, TexRow & texrow)
1811 {
1812         lyxerr[Debug::LATEX] << "TeXEnvironment...     " << this << endl;
1813
1814         LyXLayout const & style =
1815                 textclasslist[bparams.textclass][layout()];
1816
1817         Language const * language = getParLanguage(bparams);
1818         Language const * doc_language = bparams.language;
1819         Language const * previous_language = previous_
1820                 ? previous_->getParLanguage(bparams) : doc_language;
1821         if (language->babel() != previous_language->babel()) {
1822
1823                 if (!lyxrc.language_command_end.empty() &&
1824                     previous_language->babel() != doc_language->babel()) {
1825                         os << subst(lyxrc.language_command_end, "$$lang",
1826                                     previous_language->babel())
1827                            << endl;
1828                         texrow.newline();
1829                 }
1830
1831                 if (lyxrc.language_command_end.empty() ||
1832                     language->babel() != doc_language->babel()) {
1833                         os << subst(lyxrc.language_command_begin, "$$lang",
1834                                     language->babel())
1835                            << endl;
1836                         texrow.newline();
1837                 }
1838         }
1839
1840         if (style.isEnvironment()) {
1841                 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
1842                         os << "\\begin{" << style.latexname() << "}{"
1843                            << params().labelWidthString() << "}\n";
1844                 } else if (style.labeltype == LABEL_BIBLIO) {
1845                         // ale970405
1846                         os << "\\begin{" << style.latexname() << "}{"
1847                            <<  bibitemWidest(buf)
1848                            << "}\n";
1849                 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
1850                         os << "\\begin{" << style.latexname() << '}'
1851                            << style.latexparam() << '\n';
1852                 } else
1853                         os << "\\begin{" << style.latexname() << '}'
1854                            << style.latexparam() << '\n';
1855                 texrow.newline();
1856         }
1857         Paragraph * par = this;
1858         do {
1859                 par = par->TeXOnePar(buf, bparams, os, texrow, false);
1860
1861                 if (par && par->params().depth() > params().depth()) {
1862                         if (textclasslist[bparams.textclass][par->layout()].isParagraph()
1863                             // Thinko!
1864                             // How to handle this? (Lgb)
1865                             //&& !suffixIs(os, "\n\n")
1866                                 ) {
1867                                 // There should be at least one '\n' already
1868                                 // but we need there to be two for Standard
1869                                 // paragraphs that are depth-increment'ed to be
1870                                 // output correctly.  However, tables can
1871                                 // also be paragraphs so don't adjust them.
1872                                 // ARRae
1873                                 // Thinkee:
1874                                 // Will it ever harm to have one '\n' too
1875                                 // many? i.e. that we sometimes will have
1876                                 // three in a row. (Lgb)
1877                                 os << '\n';
1878                                 texrow.newline();
1879                         }
1880                         par = par->pimpl_->TeXDeeper(buf, bparams, os, texrow);
1881                 }
1882         } while (par
1883                  && par->layout() == layout()
1884                  && par->params().depth() == params().depth());
1885
1886         if (style.isEnvironment()) {
1887                 os << "\\end{" << style.latexname() << "}\n";
1888                 texrow.newline();
1889         }
1890
1891         lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
1892         return par;  // ale970302
1893 }
1894
1895
1896 bool Paragraph::isHfill(pos_type pos) const
1897 {
1898         return IsHfillChar(getChar(pos));
1899 }
1900
1901
1902 bool Paragraph::isInset(pos_type pos) const
1903 {
1904         return IsInsetChar(getChar(pos));
1905 }
1906
1907
1908 bool Paragraph::isNewline(pos_type pos) const
1909 {
1910         return pos >= 0 && IsNewlineChar(getChar(pos));
1911 }
1912
1913
1914 bool Paragraph::isSeparator(pos_type pos) const
1915 {
1916         return IsSeparatorChar(getChar(pos));
1917 }
1918
1919
1920 bool Paragraph::isLineSeparator(pos_type pos) const
1921 {
1922         value_type const c = getChar(pos);
1923         return IsLineSeparatorChar(c)
1924                 || (IsInsetChar(c) && getInset(pos) &&
1925                 getInset(pos)->isLineSeparator());
1926 }
1927
1928
1929 bool Paragraph::isKomma(pos_type pos) const
1930 {
1931         return IsKommaChar(getChar(pos));
1932 }
1933
1934
1935 /// Used by the spellchecker
1936 bool Paragraph::isLetter(pos_type pos) const
1937 {
1938         value_type const c = getChar(pos);
1939         if (IsLetterChar(c))
1940                 return true;
1941         if (isInset(pos))
1942                 return getInset(pos)->isLetter();
1943         // We want to pass the ' and escape chars to ispell
1944         string const extra = lyxrc.isp_esc_chars + '\'';
1945         return contains(extra, c);
1946 }
1947
1948
1949 bool Paragraph::isWord(pos_type pos) const
1950 {
1951         return IsWordChar(getChar(pos)) ;
1952 }
1953
1954
1955 Language const *
1956 Paragraph::getParLanguage(BufferParams const & bparams) const
1957 {
1958         if (size() > 0) {
1959 #ifndef INHERIT_LANGUAGE
1960                 return getFirstFontSettings().language();
1961 #else
1962                 Language const * lang = getFirstFontSettings().language();
1963 #ifdef WITH_WARNINGS
1964 #warning We should make this somewhat better, any ideas? (Jug)
1965 #endif
1966                 if (lang == inherit_language || lang == ignore_language)
1967                         lang = bparams.language;
1968                 return lang;
1969 #endif
1970         } else if (previous_)
1971                 return previous_->getParLanguage(bparams);
1972         else
1973                 return bparams.language;
1974 }
1975
1976
1977 bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
1978 {
1979         return lyxrc.rtl_support
1980                 && getParLanguage(bparams)->RightToLeft();
1981 }
1982
1983
1984 void Paragraph::changeLanguage(BufferParams const & bparams,
1985                                   Language const * from, Language const * to)
1986 {
1987         for (pos_type i = 0; i < size(); ++i) {
1988                 LyXFont font = getFontSettings(bparams, i);
1989                 if (font.language() == from) {
1990                         font.setLanguage(to);
1991                         setFont(i, font);
1992                 }
1993         }
1994 }
1995
1996
1997 bool Paragraph::isMultiLingual(BufferParams const & bparams)
1998 {
1999         Language const * doc_language = bparams.language;
2000         Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
2001         Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
2002
2003         for (; cit != end; ++cit)
2004                 if (cit->font().language() != ignore_language &&
2005                     cit->font().language() != latex_language &&
2006 #ifdef INHERIT_LANGUAGE
2007                         cit->font().language() != inherit_language &&
2008 #endif
2009                         cit->font().language() != doc_language)
2010                         return true;
2011         return false;
2012 }
2013
2014
2015 // Convert the paragraph to a string.
2016 // Used for building the table of contents
2017 string const Paragraph::asString(Buffer const * buffer, bool label)
2018 {
2019         BufferParams const & bparams = buffer->params;
2020         string s;
2021         if (label && !params().labelString().empty())
2022                 s += params().labelString() + ' ';
2023         string::size_type const len = s.size();
2024
2025         for (pos_type i = 0; i < size(); ++i) {
2026                 value_type c = getChar(i);
2027                 if (IsPrintable(c))
2028                         s += c;
2029                 else if (c == META_INSET &&
2030                          getInset(i)->lyxCode() == Inset::MATH_CODE) {
2031                         ostringstream ost;
2032                         getInset(i)->ascii(buffer, ost);
2033                         s += subst(ost.str().c_str(),'\n',' ');
2034                 }
2035         }
2036
2037         if (isRightToLeftPar(bparams))
2038                 reverse(s.begin() + len,s.end());
2039
2040         return s;
2041 }
2042
2043
2044 string const Paragraph::asString(Buffer const * buffer,
2045                                  pos_type beg, pos_type end, bool label)
2046 {
2047         ostringstream ost;
2048
2049         if (beg == 0 && label && !params().labelString().empty())
2050                 ost << params().labelString() << ' ';
2051
2052         for (pos_type i = beg; i < end; ++i) {
2053                 value_type const c = getUChar(buffer->params, i);
2054                 if (IsPrintable(c))
2055                         ost << c;
2056                 else if (c == META_NEWLINE)
2057                         ost << '\n';
2058                 else if (c == META_HFILL)
2059                         ost << '\t';
2060                 else if (c == META_INSET) {
2061                         getInset(i)->ascii(buffer, ost);
2062                 }
2063         }
2064
2065         return ost.str().c_str();
2066 }
2067
2068
2069 void Paragraph::setInsetOwner(Inset * i)
2070 {
2071         pimpl_->inset_owner = i;
2072         InsetList::const_iterator cit = insetlist.begin();
2073         InsetList::const_iterator end = insetlist.end();
2074         for (; cit != end; ++cit) {
2075                 if (cit->inset)
2076                         cit->inset->setOwner(i);
2077         }
2078 }
2079
2080
2081 void Paragraph::deleteInsetsLyXText(BufferView * bv)
2082 {
2083         // then the insets
2084         InsetList::const_iterator cit = insetlist.begin();
2085         InsetList::const_iterator end = insetlist.end();
2086         for (; cit != end; ++cit) {
2087                 if (cit->inset && cit->inset->isTextInset()) {
2088                         static_cast<UpdatableInset *>
2089                                 (cit->inset)->deleteLyXText(bv, true);
2090                 }
2091         }
2092 }
2093
2094
2095 void Paragraph::resizeInsetsLyXText(BufferView * bv)
2096 {
2097         // then the insets
2098         InsetList::const_iterator cit = insetlist.begin();
2099         InsetList::const_iterator end = insetlist.end();
2100         for (; cit != end; ++cit) {
2101                 if (cit->inset) {
2102                         if (cit->inset->isTextInset()) {
2103                                 static_cast<UpdatableInset *>
2104                                         (cit->inset)->resizeLyXText(bv, true);
2105                         }
2106                 }
2107         }
2108 }
2109
2110
2111 void Paragraph::setContentsFromPar(Paragraph * par)
2112 {
2113         pimpl_->setContentsFromPar(par);
2114 }
2115
2116
2117 lyx::pos_type Paragraph::size() const
2118 {
2119         return pimpl_->size();
2120 }
2121
2122
2123 Paragraph::value_type Paragraph::getChar(pos_type pos) const
2124 {
2125         return pimpl_->getChar(pos);
2126 }
2127
2128
2129 int Paragraph::id() const
2130 {
2131         return pimpl_->id_;
2132 }
2133
2134
2135 void  Paragraph::id(int id_arg)
2136 {
2137         pimpl_->id_ = id_arg;
2138 }
2139
2140
2141 string const & Paragraph::layout() const
2142 {
2143         return layout_;
2144 }
2145
2146
2147 void Paragraph::layout(string const & new_layout)
2148 {
2149         lyx::Assert(!new_layout.empty());
2150
2151         layout_ = new_layout;
2152 }
2153
2154
2155 bool Paragraph::isFirstInSequence() const
2156 {
2157         Paragraph const * dhook = depthHook(getDepth());
2158         return (dhook == this
2159                 || dhook->layout() != layout()
2160                 || dhook->getDepth() != getDepth());
2161 }
2162
2163
2164 Inset * Paragraph::inInset() const
2165 {
2166         return pimpl_->inset_owner;
2167 }
2168
2169
2170 void Paragraph::clearContents()
2171 {
2172         pimpl_->clear();
2173 }
2174
2175
2176 void Paragraph::setCounter(int i, int v)
2177 {
2178         pimpl_->counter_[i] = v;
2179 }
2180
2181
2182 int Paragraph::getCounter(int i) const
2183 {
2184         return pimpl_->counter_[i];
2185 }
2186
2187
2188 void Paragraph::incCounter(int i)
2189 {
2190         pimpl_->counter_[i]++;
2191 }
2192
2193
2194 void Paragraph::setChar(pos_type pos, value_type c)
2195 {
2196         pimpl_->setChar(pos, c);
2197 }
2198
2199
2200 Paragraph::inset_iterator::inset_iterator(Paragraph::InsetList::iterator const & iter)
2201  : it(iter)
2202 {}
2203
2204
2205 Paragraph::inset_iterator Paragraph::inset_iterator_begin()
2206 {
2207         return inset_iterator(insetlist.begin());
2208 }
2209
2210
2211 Paragraph::inset_iterator Paragraph::inset_iterator_end()
2212 {
2213         return inset_iterator(insetlist.end());
2214 }
2215
2216
2217 ParagraphParameters & Paragraph::params()
2218 {
2219         return pimpl_->params;
2220 }
2221
2222
2223 ParagraphParameters const & Paragraph::params() const
2224 {
2225         return pimpl_->params;
2226 }
2227
2228
2229 Paragraph * Paragraph::getParFromID(int id) const
2230 {
2231         return pimpl_->getParFromID(id);
2232 }
2233
2234
2235 bool Paragraph::isFreeSpacing() const
2236 {
2237         // for now we just need this, later should we need this in some
2238         // other way we can always add a function to Inset::() too.
2239         if (pimpl_->inset_owner && pimpl_->inset_owner->owner())
2240                 return (pimpl_->inset_owner->owner()->lyxCode() == Inset::ERT_CODE);
2241         return false;
2242 }