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