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