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