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