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