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