]> git.lyx.org Git - lyx.git/blob - src/paragraph.C
3af82b6910fb2d9198e1263e054b680ccd13961b
[lyx.git] / src / paragraph.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team. 
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation "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 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, 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         // remember to set the inset_owner
968         tmp->SetInsetOwner(InInset());
969         
970         // this is an idea for a more userfriendly layout handling, I will
971         // see what the users say
972         
973         // layout stays the same with latex-environments
974         if (flag) {
975                 tmp->SetOnlyLayout(layout);
976                 tmp->SetLabelWidthString(params.labelWidthString());
977         }
978         
979         if (size() > pos || !size() || flag == 2) {
980                 tmp->SetOnlyLayout(layout);
981                 tmp->params.align(params.align());
982                 tmp->SetLabelWidthString(params.labelWidthString());
983                 
984                 tmp->params.lineBottom(params.lineBottom());
985                 params.lineBottom(false);
986                 tmp->params.pagebreakBottom(params.pagebreakBottom());
987                 params.pagebreakBottom(false);
988                 tmp->params.spaceBottom(params.spaceBottom());
989                 params.spaceBottom(VSpace(VSpace::NONE));
990                 
991                 tmp->params.depth(params.depth());
992                 tmp->params.noindent(params.noindent());
993                 
994                 // copy everything behind the break-position
995                 // to the new paragraph
996                 size_type pos_end = text.size() - 1;
997                 size_type i = pos;
998                 size_type j = pos;
999                 for (; i <= pos_end; ++i) {
1000                         CutIntoMinibuffer(bparams, i);
1001                         if (tmp->InsertFromMinibuffer(j - pos))
1002                                 ++j;
1003                 }
1004                 tmp->fitToSize();
1005                 for (i = pos_end; i >= pos; --i)
1006                         Erase(i);
1007                 
1008                 fitToSize();
1009         }
1010         
1011         // just an idea of me
1012         if (!pos) {
1013                 tmp->params.lineTop(params.lineTop());
1014                 tmp->params.pagebreakTop(params.pagebreakTop());
1015                 tmp->params.spaceTop(params.spaceTop());
1016                 tmp->bibkey = bibkey;
1017                 Clear();
1018                 // layout stays the same with latex-environments
1019                 if (flag) {
1020                         SetOnlyLayout(tmp->layout);
1021                         SetLabelWidthString(tmp->params.labelWidthString());
1022                         params.depth(tmp->params.depth());
1023                 }
1024         }
1025 }
1026         
1027
1028 void LyXParagraph::MakeSameLayout(LyXParagraph const * par)
1029 {
1030         layout = par->layout;
1031         params.makeSame(par->params);
1032         
1033         // This can be changed after NEW_INSETS is in effect. (Lgb)
1034         SetLabelWidthString(par->params.labelWidthString());
1035 }
1036
1037
1038 int LyXParagraph::StripLeadingSpaces(LyXTextClassList::size_type tclass) 
1039 {
1040         if (textclasslist.Style(tclass, GetLayout()).free_spacing)
1041                 return 0;
1042         
1043         int i = 0;
1044         while (size()
1045                && (IsNewline(0) || IsLineSeparator(0))){
1046                 Erase(0);
1047                 ++i;
1048         }
1049
1050         return i;
1051 }
1052
1053
1054 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1055 {
1056         return 
1057                 par->layout == layout &&
1058                 params.sameLayout(par->params);
1059 }
1060
1061
1062 void LyXParagraph::BreakParagraphConservative(BufferParams const & bparams,
1063                                               LyXParagraph::size_type pos)
1064 {
1065         // create a new paragraph
1066         LyXParagraph * tmp = new LyXParagraph(this);
1067         tmp->MakeSameLayout(this);
1068
1069         // When can pos > Last()?
1070         // I guess pos == Last() is possible.
1071         if (size() > pos) {
1072                 // copy everything behind the break-position to the new
1073                 // paragraph
1074                 size_type pos_end = text.size() - 1;
1075
1076                 size_type i, j;
1077                 for (i = j = pos; i <= pos_end; ++i) {
1078                         CutIntoMinibuffer(bparams, i);
1079                         if (tmp->InsertFromMinibuffer(j - pos))
1080                                 ++j;
1081                 }
1082
1083                 tmp->fitToSize();
1084                 
1085                 for (size_type i = pos_end; i >= pos; --i)
1086                         Erase(i);
1087
1088                 fitToSize();
1089         }
1090 }
1091    
1092
1093 // Be carefull, this does not make any check at all.
1094 // This method has wrong name, it combined this par with the next par.
1095 // In that sense it is the reverse of break paragraph. (Lgb)
1096 void LyXParagraph::PasteParagraph(BufferParams const & bparams)
1097 {
1098         // copy the next paragraph to this one
1099         LyXParagraph * the_next = next();
1100    
1101         // first the DTP-stuff
1102         params.lineBottom(the_next->params.lineBottom());
1103         params.spaceBottom(the_next->params.spaceBottom());
1104         params.pagebreakBottom(the_next->params.pagebreakBottom());
1105
1106         size_type pos_end = the_next->text.size() - 1;
1107         size_type pos_insert = size();
1108
1109         // ok, now copy the paragraph
1110         size_type i, j;
1111         for (i = j = 0; i <= pos_end; ++i) {
1112                 the_next->CutIntoMinibuffer(bparams, i);
1113                 if (InsertFromMinibuffer(pos_insert + j))
1114                         ++j;
1115         }
1116    
1117         // delete the next paragraph
1118         LyXParagraph * ppar = the_next->previous_;
1119         LyXParagraph * npar = the_next->next_;
1120         delete the_next;
1121         ppar->next(npar);
1122 }
1123
1124
1125 int LyXParagraph::GetEndLabel(BufferParams const & bparams) const
1126 {
1127         LyXParagraph const * par = this;
1128         int par_depth = GetDepth();
1129         while (par) {
1130                 LyXTextClass::LayoutList::size_type layout = par->GetLayout();
1131                 int const endlabeltype =
1132                         textclasslist.Style(bparams.textclass,
1133                                             layout).endlabeltype;
1134                 if (endlabeltype != END_LABEL_NO_LABEL) {
1135                         if (!next_)
1136                                 return endlabeltype;
1137
1138                         int const next_depth = next_->GetDepth();
1139                         if (par_depth > next_depth ||
1140                             (par_depth == next_depth
1141                              && layout != next_->GetLayout()))
1142                                 return endlabeltype;
1143                         break;
1144                 }
1145                 if (par_depth == 0)
1146                         break;
1147                 par = par->DepthHook(par_depth - 1);
1148                 if (par)
1149                         par_depth = par->GetDepth();
1150         }
1151         return END_LABEL_NO_LABEL;
1152 }
1153
1154
1155 char LyXParagraph::GetDepth() const
1156 {
1157         return params.depth();
1158 }
1159
1160
1161 char LyXParagraph::GetAlign() const
1162 {
1163         return params.align();
1164 }
1165
1166
1167 string const & LyXParagraph::GetLabelstring() const
1168 {
1169         return params.labelString();
1170 }
1171
1172
1173 int LyXParagraph::GetFirstCounter(int i) const
1174 {
1175         return counter_[i];
1176 }
1177
1178
1179 // the next two functions are for the manual labels
1180 string const LyXParagraph::GetLabelWidthString() const
1181 {
1182         if (!params.labelWidthString().empty())
1183                 return params.labelWidthString();
1184         else
1185                 return _("Senseless with this layout!");
1186 }
1187
1188
1189 void LyXParagraph::SetLabelWidthString(string const & s)
1190 {
1191         params.labelWidthString(s);
1192 }
1193
1194
1195 void LyXParagraph::SetOnlyLayout(LyXTextClass::size_type new_layout)
1196 {
1197         layout = new_layout;
1198 }
1199
1200
1201 void LyXParagraph::SetLayout(LyXTextClass::size_type new_layout)
1202 {
1203         layout = new_layout;
1204         params.labelWidthString(string());
1205         params.align(LYX_ALIGN_LAYOUT);
1206         params.spaceTop(VSpace(VSpace::NONE));
1207         params.spaceBottom(VSpace(VSpace::NONE));
1208         params.spacing(Spacing(Spacing::Default));
1209 }
1210
1211
1212 // if the layout of a paragraph contains a manual label, the beginning of the 
1213 // main body is the beginning of the second word. This is what the par-
1214 // function returns. If the layout does not contain a label, the main
1215 // body always starts with position 0. This differentiation is necessary,
1216 // because there cannot be a newline or a blank <= the beginning of the 
1217 // main body in TeX.
1218
1219 int LyXParagraph::BeginningOfMainBody() const
1220 {
1221         // Unroll the first two cycles of the loop
1222         // and remember the previous character to
1223         // remove unnecessary GetChar() calls
1224         size_type i = 0;
1225         if (i < size()
1226             && GetChar(i) != LyXParagraph::META_NEWLINE) {
1227                 ++i;
1228                 char previous_char = 0;
1229                 char temp = 0; 
1230                 if (i < size()
1231                     && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1232                         // Yes, this  ^ is supposed to be "= " not "=="
1233                         ++i;
1234                         while (i < size()
1235                                && previous_char != ' '
1236                                && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1237                                 ++i;
1238                                 previous_char = temp;
1239                         }
1240                 }
1241         }
1242
1243         return i;
1244 }
1245
1246
1247 LyXParagraph * LyXParagraph::DepthHook(int deth)
1248 {
1249         LyXParagraph * newpar = this;
1250         if (deth < 0)
1251                 return 0;
1252    
1253         do {
1254                 newpar = newpar->previous();
1255         } while (newpar && newpar->GetDepth() > deth);
1256    
1257         if (!newpar) {
1258                 if (previous() || GetDepth())
1259                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
1260                                 "no hook." << endl;
1261                 newpar = this;
1262         }
1263
1264         return newpar;
1265 }
1266
1267
1268 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
1269 {
1270         LyXParagraph const * newpar = this;
1271         if (deth < 0)
1272                 return 0;
1273    
1274         do {
1275                 newpar = newpar->previous();
1276         } while (newpar && newpar->GetDepth() > deth);
1277    
1278         if (!newpar) {
1279                 if (previous() || GetDepth())
1280                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
1281                                 "no hook." << endl;
1282                 newpar = this;
1283         }
1284
1285         return newpar;
1286 }
1287
1288
1289 int LyXParagraph::AutoDeleteInsets()
1290 {
1291         int count = 0;
1292         InsetList::size_type index = 0;
1293         while (index < insetlist.size()) {
1294                 if (insetlist[index].inset && insetlist[index].inset->AutoDelete()) {
1295                         Erase(insetlist[index].pos); 
1296                         // Erase() calls to insetlist.erase(&insetlist[index])
1297                         // so index shouldn't be increased.
1298                         ++count;
1299                 } else
1300                         ++index;
1301         }
1302         return count;
1303 }
1304
1305
1306 LyXParagraph::inset_iterator
1307 LyXParagraph::InsetIterator(LyXParagraph::size_type pos)
1308 {
1309         InsetTable search_inset(pos, 0);
1310         InsetList::iterator it = lower_bound(insetlist.begin(),
1311                                              insetlist.end(),
1312                                              search_inset, matchIT());
1313         return inset_iterator(it);
1314 }
1315
1316
1317 // returns -1 if inset not found
1318 int LyXParagraph::GetPositionOfInset(Inset * inset) const
1319 {
1320         // Find the entry.
1321         for (InsetList::const_iterator cit = insetlist.begin();
1322              cit != insetlist.end(); ++cit) {
1323                 if ((*cit).inset == inset) {
1324                         return (*cit).pos;
1325                 }
1326         }
1327         if (inset == bibkey)
1328                 return 0;
1329
1330         return -1;
1331 }
1332
1333
1334 LyXParagraph * LyXParagraph::TeXOnePar(Buffer const * buf,
1335                                        BufferParams const & bparams,
1336                                        ostream & os, TexRow & texrow,
1337                                        bool moving_arg)
1338 {
1339         lyxerr[Debug::LATEX] << "TeXOnePar...     " << this << endl;
1340         LyXLayout const & style =
1341                 textclasslist.Style(bparams.textclass,
1342                                     layout);
1343
1344         bool further_blank_line = false;
1345
1346         if (params.startOfAppendix()) {
1347                 os << "\\appendix\n";
1348                 texrow.newline();
1349         }
1350
1351         if (!params.spacing().isDefault()
1352             && (!previous() || !previous()->HasSameLayout(this))) {
1353                 os << params.spacing().writeEnvirBegin() << "\n";
1354                 texrow.newline();
1355         }
1356         
1357         if (tex_code_break_column && style.isCommand()){
1358                 os << '\n';
1359                 texrow.newline();
1360         }
1361
1362         if (params.pagebreakTop()) {
1363                 os << "\\newpage";
1364                 further_blank_line = true;
1365         }
1366         if (params.spaceTop().kind() != VSpace::NONE) {
1367                 os << params.spaceTop().asLatexCommand(bparams);
1368                 further_blank_line = true;
1369         }
1370       
1371         if (params.lineTop()) {
1372                 os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
1373                    << "\\vspace{-1\\parskip}";
1374                 further_blank_line = true;
1375         }
1376
1377         if (further_blank_line){
1378                 os << '\n';
1379                 texrow.newline();
1380         }
1381
1382         Language const * language = getParLanguage(bparams);
1383         Language const * doc_language = bparams.language;
1384         Language const * previous_language = previous_
1385                 ? previous_->getParLanguage(bparams) : doc_language;
1386         if (language->babel() != doc_language->babel() &&
1387             language->babel() != previous_language->babel()) {
1388                 os << subst(lyxrc.language_command_begin, "$$lang",
1389                             language->babel())
1390                    << endl;
1391                 texrow.newline();
1392         }
1393
1394         if (bparams.inputenc == "auto" &&
1395             language->encoding() != previous_language->encoding()) {
1396                 os << "\\inputencoding{"
1397                    << language->encoding()->LatexName()
1398                    << "}" << endl;
1399                 texrow.newline();
1400         }
1401         
1402         switch (style.latextype) {
1403         case LATEX_COMMAND:
1404                 os << '\\'
1405                    << style.latexname()
1406                    << style.latexparam();
1407                 break;
1408         case LATEX_ITEM_ENVIRONMENT:
1409                 if (bibkey) {
1410                         bibkey->Latex(buf, os, false, false);
1411                 } else
1412                         os << "\\item ";
1413                 break;
1414         case LATEX_LIST_ENVIRONMENT:
1415                 os << "\\item ";
1416                 break;
1417         default:
1418                 break;
1419         }
1420
1421         bool need_par = SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
1422  
1423         // Make sure that \\par is done with the font of the last
1424         // character if this has another size as the default.
1425         // This is necessary because LaTeX (and LyX on the screen)
1426         // calculates the space between the baselines according
1427         // to this font. (Matthias)
1428         //
1429         // Is this really needed ? (Dekel)
1430         // We do not need to use to change the font for the last paragraph
1431         // or for a command.
1432         LyXFont font = getFont(bparams, size() - 1);
1433
1434         bool is_command = textclasslist.Style(bparams.textclass,
1435                                               GetLayout()).isCommand();
1436         if (style.resfont.size() != font.size() && next_ && !is_command) {
1437                 if (!need_par)
1438                         os << "{";
1439                 os << "\\" << font.latexSize() << " \\par}";
1440         } else if (need_par) {
1441                 os << "\\par}";
1442         } else if (is_command)
1443                 os << "}";
1444
1445         if (language->babel() != doc_language->babel() &&
1446             (!next_
1447              || next_->getParLanguage(bparams)->babel() != language->babel())) {
1448                 os << endl 
1449                    << subst(lyxrc.language_command_end, "$$lang",
1450                             doc_language->babel());
1451         }
1452         
1453         switch (style.latextype) {
1454         case LATEX_ITEM_ENVIRONMENT:
1455         case LATEX_LIST_ENVIRONMENT:
1456                 if (next_ && (params.depth() < next_->params.depth())) {
1457                         os << '\n';
1458                         texrow.newline();
1459                 }
1460                 break;
1461         case LATEX_ENVIRONMENT:
1462                 // if its the last paragraph of the current environment
1463                 // skip it otherwise fall through
1464                 if (next_
1465                     && (next_->layout != layout
1466                         || next_->params.depth() != params.depth()))
1467                         break;
1468         default:
1469                 // we don't need it for the last paragraph!!!
1470                 // or for tables in floats
1471                 //   -- effectively creates a \par where there isn't one which
1472                 //      breaks a \subfigure or \subtable.
1473                 if (next_) {
1474                         os << '\n';
1475                         texrow.newline();
1476                 }
1477         }
1478         
1479         further_blank_line = false;
1480         if (params.lineBottom()) {
1481                 os << "\\lyxline{\\" << getFont(bparams,
1482                                                 size() - 1).latexSize() << '}';
1483                 further_blank_line = true;
1484         }
1485
1486         if (params.spaceBottom().kind() != VSpace::NONE) {
1487                 os << params.spaceBottom().asLatexCommand(bparams);
1488                 further_blank_line = true;
1489         }
1490       
1491         if (params.pagebreakBottom()) {
1492                 os << "\\newpage";
1493                 further_blank_line = true;
1494         }
1495
1496         if (further_blank_line){
1497                 os << '\n';
1498                 texrow.newline();
1499         }
1500
1501         if (!params.spacing().isDefault()
1502             && (!next_ || !next_->HasSameLayout(this))) {
1503                 os << params.spacing().writeEnvirEnd() << "\n";
1504                 texrow.newline();
1505         }
1506         
1507         // we don't need it for the last paragraph!!!
1508         if (next_) {
1509                 os << '\n';
1510                 texrow.newline();
1511         }
1512
1513         lyxerr[Debug::LATEX] << "TeXOnePar...done " << next_ << endl;
1514         return next_;
1515 }
1516
1517
1518 // This one spits out the text of the paragraph
1519 bool LyXParagraph::SimpleTeXOnePar(Buffer const * buf,
1520                                    BufferParams const & bparams,
1521                                    ostream & os, TexRow & texrow,
1522                                    bool moving_arg)
1523 {
1524         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...     " << this << endl;
1525
1526         bool return_value = false;
1527
1528         LyXLayout const & style =
1529                 textclasslist.Style(bparams.textclass,
1530                                     GetLayout());
1531         LyXFont basefont;
1532
1533         // Maybe we have to create a optional argument.
1534         size_type main_body;
1535         if (style.labeltype != LABEL_MANUAL)
1536                 main_body = 0;
1537         else
1538                 main_body = BeginningOfMainBody();
1539
1540         if (main_body > 0) {
1541                 os << '[';
1542                 basefont = getFont(bparams, -2); // Get label font
1543         } else {
1544                 basefont = getFont(bparams, -1); // Get layout font
1545         }
1546
1547         int column = 0;
1548
1549         if (main_body >= 0
1550             && !text.size()) {
1551                 if (style.isCommand()) {
1552                         os << '{';
1553                         ++column;
1554                 } else if (params.align() != LYX_ALIGN_LAYOUT) {
1555                         os << '{';
1556                         ++column;
1557                         return_value = true;
1558                 }
1559         }
1560
1561         moving_arg |= style.needprotect;
1562  
1563         // Which font is currently active?
1564         LyXFont running_font(basefont);
1565         // Do we have an open font change?
1566         bool open_font = false;
1567
1568         texrow.start(this, 0);
1569
1570         for (size_type i = 0; i < size(); ++i) {
1571                 ++column;
1572                 // First char in paragraph or after label?
1573                 if (i == main_body) {
1574                         if (main_body > 0) {
1575                                 if (open_font) {
1576                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
1577                                         open_font = false;
1578                                 }
1579                                 basefont = getFont(bparams, -1); // Now use the layout font
1580                                 running_font = basefont;
1581                                 os << ']';
1582                                 ++column;
1583                         }
1584                         if (style.isCommand()) {
1585                                 os << '{';
1586                                 ++column;
1587                         } else if (params.align() != LYX_ALIGN_LAYOUT && next_) {
1588                                 // We do not need \par here (Dekel)
1589                                 // os << "{\\par";
1590                                 os << "{";
1591                                 ++column;
1592                                 return_value = true;
1593                         }
1594
1595                         if (params.noindent()) {
1596                                 os << "\\noindent ";
1597                                 column += 10;
1598                         }
1599                         switch (params.align()) {
1600                         case LYX_ALIGN_NONE:
1601                         case LYX_ALIGN_BLOCK:
1602                         case LYX_ALIGN_LAYOUT:
1603                         case LYX_ALIGN_SPECIAL:
1604                                 break;
1605                         case LYX_ALIGN_LEFT:
1606                                 if (moving_arg)
1607                                         os << "\\protect";
1608                                 if (getParLanguage(bparams)->babel() != "hebrew") {
1609                                         os << "\\raggedright ";
1610                                         column+= 13;
1611                                 } else {
1612                                         os << "\\raggedleft ";
1613                                         column+= 12;
1614                                 }
1615                                 break;
1616                         case LYX_ALIGN_RIGHT:
1617                                 if (moving_arg)
1618                                         os << "\\protect";
1619                                 if (getParLanguage(bparams)->babel() != "hebrew") {
1620                                         os << "\\raggedleft ";
1621                                         column+= 12;
1622                                 } else {
1623                                         os << "\\raggedright ";
1624                                         column+= 13;
1625                                 }
1626                                 break;
1627                         case LYX_ALIGN_CENTER:
1628                                 if (moving_arg)
1629                                         os << "\\protect";
1630                                 os << "\\centering ";
1631                                 column+= 11;
1632                                 break;
1633                         }        
1634                 }
1635
1636                 value_type c = GetChar(i);
1637
1638                 // Fully instantiated font
1639                 LyXFont font = getFont(bparams, i);
1640
1641                 LyXFont last_font = running_font;
1642
1643                 // Spaces at end of font change are simulated to be
1644                 // outside font change, i.e. we write "\textXX{text} "
1645                 // rather than "\textXX{text }". (Asger)
1646                 if (open_font && c == ' ' && i <= size() - 2 
1647                     && !getFont(bparams, i + 1).equalExceptLatex(running_font) 
1648                     && !getFont(bparams, i + 1).equalExceptLatex(font)) {
1649                         font = getFont(bparams, i + 1);
1650                 }
1651                 // We end font definition before blanks
1652                 if (!font.equalExceptLatex(running_font) && open_font) {
1653                         column += running_font.latexWriteEndChanges(os,
1654                                                                     basefont,
1655                                                                     (i == main_body-1) ? basefont : font);
1656                         running_font = basefont;
1657                         open_font = false;
1658                 }
1659
1660                 // Blanks are printed before start of fontswitch
1661                 if (c == ' ') {
1662                         // Do not print the separation of the optional argument
1663                         if (i != main_body - 1) {
1664                                 SimpleTeXBlanks(os, texrow, i,
1665                                                 column, font, style);
1666                         }
1667                 }
1668
1669                 // Do we need to change font?
1670                 if (!font.equalExceptLatex(running_font)
1671                     && i != main_body-1) {
1672                         column += font.latexWriteStartChanges(os, basefont,
1673                                                               last_font);
1674                         running_font = font;
1675                         open_font = true;
1676                 }
1677
1678                 if (c == LyXParagraph::META_NEWLINE) {
1679                         // newlines are handled differently here than
1680                         // the default in SimpleTeXSpecialChars().
1681                         if (!style.newline_allowed
1682                             || font.latex() == LyXFont::ON) {
1683                                 os << '\n';
1684                         } else {
1685                                 if (open_font) {
1686                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
1687                                         open_font = false;
1688                                 }
1689                                 basefont = getFont(bparams, -1);
1690                                 running_font = basefont;
1691                                 if (font.family() == 
1692                                     LyXFont::TYPEWRITER_FAMILY) {
1693                                         os << "~";
1694                                 }
1695                                 if (moving_arg)
1696                                         os << "\\protect ";
1697                                 os << "\\\\\n";
1698                         }
1699                         texrow.newline();
1700                         texrow.start(this, i + 1);
1701                         column = 0;
1702                 } else {
1703                         SimpleTeXSpecialChars(buf, bparams,
1704                                               os, texrow, moving_arg,
1705                                               font, running_font, basefont,
1706                                               open_font, style, i, column, c);
1707                 }
1708         }
1709
1710         // If we have an open font definition, we have to close it
1711         if (open_font) {
1712                 if (next_) {
1713                         running_font
1714                                 .latexWriteEndChanges(os, basefont,
1715                                                       next_->getFont(bparams,
1716                                                                      0));
1717                 } else {
1718                         running_font.latexWriteEndChanges(os, basefont,
1719                                                           basefont);
1720                 }
1721         }
1722
1723         // Needed if there is an optional argument but no contents.
1724         if (main_body > 0 && main_body == size()) {
1725                 os << "]~";
1726                 return_value = false;
1727         }
1728
1729         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
1730         return return_value;
1731 }
1732
1733
1734 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
1735 {
1736         bool retval = false;
1737         switch (c) {
1738         case LyXParagraph::META_HFILL:
1739                 sgml_string.erase();
1740                 break;
1741         case LyXParagraph::META_NEWLINE:
1742                 sgml_string = '\n';
1743                 break;
1744         case '&': 
1745                 sgml_string = "&amp;";
1746                 break;
1747         case '<': 
1748                 sgml_string = "&lt;"; 
1749                 break;
1750         case '>':
1751                 sgml_string = "&gt;"; 
1752                 break;
1753         case '$': 
1754                 sgml_string = "&dollar;"; 
1755                 break;
1756         case '#': 
1757                 sgml_string = "&num;";
1758                 break;
1759         case '%': 
1760                 sgml_string = "&percnt;";
1761                 break;
1762         case '[': 
1763                 sgml_string = "&lsqb;";
1764                 break;
1765         case ']': 
1766                 sgml_string = "&rsqb;";
1767                 break;
1768         case '{': 
1769                 sgml_string = "&lcub;";
1770                 break;
1771         case '}': 
1772                 sgml_string = "&rcub;";
1773                 break;
1774         case '~': 
1775                 sgml_string = "&tilde;";
1776                 break;
1777         case '"': 
1778                 sgml_string = "&quot;";
1779                 break;
1780         case '\\': 
1781                 sgml_string = "&bsol;";
1782                 break;
1783         case ' ':
1784                 retval = true;
1785                 sgml_string = ' ';
1786                 break;
1787         case '\0': // Ignore :-)
1788                 sgml_string.erase();
1789                 break;
1790         default:
1791                 sgml_string = c;
1792                 break;
1793         }
1794         return retval;
1795 }
1796
1797
1798 void LyXParagraph::SimpleTeXBlanks(ostream & os, TexRow & texrow,
1799                                    LyXParagraph::size_type const i,
1800                                    int & column, LyXFont const & font,
1801                                    LyXLayout const & style)
1802 {
1803         if (column > tex_code_break_column
1804             && i 
1805             && GetChar(i - 1) != ' '
1806             && (i < size() - 1)
1807             // In LaTeX mode, we don't want to
1808             // break lines since some commands
1809             // do not like this
1810             && ! (font.latex() == LyXFont::ON)
1811             // same in FreeSpacing mode
1812             && !style.free_spacing
1813             // In typewriter mode, we want to avoid 
1814             // ! . ? : at the end of a line
1815             && !(font.family() == LyXFont::TYPEWRITER_FAMILY
1816                  && (GetChar(i-1) == '.'
1817                      || GetChar(i-1) == '?' 
1818                      || GetChar(i-1) == ':'
1819                      || GetChar(i-1) == '!'))) {
1820                 if (tex_code_break_column == 0) {
1821                         // in batchmode we need LaTeX to still
1822                         // see it as a space not as an extra '\n'
1823                         os << " %\n";
1824                 } else {
1825                         os << '\n';
1826                 }
1827                 texrow.newline();
1828                 texrow.start(this, i + 1);
1829                 column = 0;
1830         } else if (font.latex() == LyXFont::OFF) {
1831                 if (style.free_spacing) {
1832                         os << '~';
1833                 } else {
1834                         os << ' ';
1835                 }
1836         }
1837 }
1838
1839
1840 void LyXParagraph::SimpleTeXSpecialChars(Buffer const * buf,
1841                                          BufferParams const & bparams,
1842                                          ostream & os, TexRow & texrow,
1843                                          bool moving_arg,
1844                                          LyXFont & font,
1845                                          LyXFont & running_font,
1846                                          LyXFont & basefont,
1847                                          bool & open_font,
1848                                          LyXLayout const & style,
1849                                          LyXParagraph::size_type & i,
1850                                          int & column,
1851                                          LyXParagraph::value_type const c)
1852 {
1853         // Two major modes:  LaTeX or plain
1854         // Handle here those cases common to both modes
1855         // and then split to handle the two modes separately.
1856         switch (c) {
1857         case LyXParagraph::META_INSET: {
1858                 Inset * inset = GetInset(i);
1859                 if (inset) {
1860                         bool close = false;
1861                         int const len = os.tellp();
1862                         //ostream::pos_type const len = os.tellp();
1863                         if ((inset->LyxCode() == Inset::GRAPHICS_CODE
1864                              || inset->LyxCode() == Inset::MATH_CODE
1865                              || inset->LyxCode() == Inset::URL_CODE)
1866                             && running_font.isRightToLeft()) {
1867                                 os << "\\L{";
1868                                 close = true;
1869                         }
1870
1871                         int tmp = inset->Latex(buf, os, moving_arg,
1872                                                style.free_spacing);
1873
1874                         if (close)
1875                                 os << "}";
1876
1877                         if (tmp) {
1878                                 column = 0;
1879                         } else {
1880                                 column += int(os.tellp()) - len;
1881                         }
1882                         for (; tmp--;) {
1883                                 texrow.newline();
1884                         }
1885                 }
1886         }
1887         break;
1888
1889         case LyXParagraph::META_NEWLINE:
1890                 if (open_font) {
1891                         column += running_font.latexWriteEndChanges(os,
1892                                                                     basefont,
1893                                                                     basefont);
1894                         open_font = false;
1895                 }
1896                 basefont = getFont(bparams, -1);
1897                 running_font = basefont;
1898                 break;
1899
1900         case LyXParagraph::META_HFILL: 
1901                 os << "\\hfill{}";
1902                 column += 7;
1903                 break;
1904
1905         default:
1906                 // And now for the special cases within each mode
1907                 // Are we in LaTeX mode?
1908                 if (font.latex() == LyXFont::ON) {
1909                         // at present we only have one option
1910                         // but I'll leave it as a switch statement
1911                         // so its simpler to extend. (ARRae)
1912                         switch (c) {
1913                         default:
1914                                 // make sure that we will not print
1915                                 // error generating chars to the tex
1916                                 // file. This test would not be needed
1917                                 // if it were done in the buffer
1918                                 // itself.
1919                                 if (c != '\0') {
1920                                         os << c;
1921                                 }
1922                                 break;
1923                         }
1924                 } else {
1925                         // Plain mode (i.e. not LaTeX)
1926                         switch (c) {
1927                         case '\\': 
1928                                 os << "\\textbackslash{}";
1929                                 column += 15;
1930                                 break;
1931                 
1932                         case '°': case '±': case '²': case '³':  
1933                         case '×': case '÷': case '¹': case 'ª':
1934                         case 'º': case '¬': case 'µ':
1935                                 if (bparams.inputenc == "latin1" ||
1936                                     (bparams.inputenc == "auto" &&
1937                                      font.language()->encoding()->LatexName()
1938                                      == "latin1")) {
1939                                         os << "\\ensuremath{"
1940                                            << c
1941                                            << '}';
1942                                         column += 13;
1943                                 } else {
1944                                         os << c;
1945                                 }
1946                                 break;
1947
1948                         case '|': case '<': case '>':
1949                                 // In T1 encoding, these characters exist
1950                                 if (lyxrc.fontenc == "T1") {
1951                                         os << c;
1952                                         //... but we should avoid ligatures
1953                                         if ((c == '>' || c == '<')
1954                                             && i <= size() - 2
1955                                             && GetChar(i + 1) == c) {
1956                                                 //os << "\\textcompwordmark{}";
1957                                                 // Jean-Marc, have a look at
1958                                                 // this. I think this works
1959                                                 // equally well:
1960                                                 os << "\\,{}";
1961                                                 // Lgb
1962                                                 column += 19;
1963                                         }
1964                                         break;
1965                                 }
1966                                 // Typewriter font also has them
1967                                 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
1968                                         os << c;
1969                                         break;
1970                                 } 
1971                                 // Otherwise, we use what LaTeX
1972                                 // provides us.
1973                                 switch (c) {
1974                                 case '<':
1975                                         os << "\\textless{}";
1976                                         column += 10;
1977                                         break;
1978                                 case '>':
1979                                         os << "\\textgreater{}";
1980                                         column += 13;
1981                                         break;
1982                                 case '|':
1983                                         os << "\\textbar{}";
1984                                         column += 9;
1985                                         break;
1986                                 }
1987                                 break;
1988
1989                         case '-': // "--" in Typewriter mode -> "-{}-"
1990                                 if (i <= size() - 2
1991                                     && GetChar(i + 1) == '-'
1992                                     && font.family() == LyXFont::TYPEWRITER_FAMILY) {
1993                                         os << "-{}";
1994                                         column += 2;
1995                                 } else {
1996                                         os << '-';
1997                                 }
1998                                 break;
1999
2000                         case '\"': 
2001                                 os << "\\char`\\\"{}";
2002                                 column += 9;
2003                                 break;
2004
2005                         case '£':
2006                                 if (bparams.inputenc == "default") {
2007                                         os << "\\pounds{}";
2008                                         column += 8;
2009                                 } else {
2010                                         os << c;
2011                                 }
2012                                 break;
2013
2014                         case '$': case '&':
2015                         case '%': case '#': case '{':
2016                         case '}': case '_':
2017                                 os << '\\' << c;
2018                                 column += 1;
2019                                 break;
2020
2021                         case '~':
2022                                 os << "\\textasciitilde{}";
2023                                 column += 16;
2024                                 break;
2025
2026                         case '^':
2027                                 os << "\\textasciicircum{}";
2028                                 column += 17;
2029                                 break;
2030
2031                         case '*': case '[': case ']':
2032                                 // avoid being mistaken for optional arguments
2033                                 os << '{' << c << '}';
2034                                 column += 2;
2035                                 break;
2036
2037                         case ' ':
2038                                 // Blanks are printed before font switching.
2039                                 // Sure? I am not! (try nice-latex)
2040                                 // I am sure it's correct. LyX might be smarter
2041                                 // in the future, but for now, nothing wrong is
2042                                 // written. (Asger)
2043                                 break;
2044
2045                         default:
2046                                 /* idea for labels --- begin*/
2047                                 // Check for "LyX"
2048                                 if (c ==  'L'
2049                                     && i <= size() - 3
2050                                     && font.family() != LyXFont::TYPEWRITER_FAMILY
2051                                     && GetChar(i + 1) == 'y'
2052                                     && GetChar(i + 2) == 'X') {
2053                                         os << "\\LyX{}";
2054                                         i += 2;
2055                                         column += 5;
2056                                 }
2057                                 // Check for "TeX"
2058                                 else if (c == 'T'
2059                                          && i <= size() - 3
2060                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
2061                                          && GetChar(i + 1) == 'e'
2062                                          && GetChar(i + 2) == 'X') {
2063                                         os << "\\TeX{}";
2064                                         i += 2;
2065                                         column += 5;
2066                                 }
2067                                 // Check for "LaTeX2e"
2068                                 else if (c == 'L'
2069                                          && i <= size() - 7
2070                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
2071                                          && GetChar(i + 1) == 'a'
2072                                          && GetChar(i + 2) == 'T'
2073                                          && GetChar(i + 3) == 'e'
2074                                          && GetChar(i + 4) == 'X'
2075                                          && GetChar(i + 5) == '2'
2076                                          && GetChar(i + 6) == 'e') {
2077                                         os << "\\LaTeXe{}";
2078                                         i += 6;
2079                                         column += 8;
2080                                 }
2081                                 // Check for "LaTeX"
2082                                 else if (c == 'L'
2083                                          && i <= size() - 5
2084                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
2085                                          && GetChar(i + 1) == 'a'
2086                                          && GetChar(i + 2) == 'T'
2087                                          && GetChar(i + 3) == 'e'
2088                                          && GetChar(i + 4) == 'X') {
2089                                         os << "\\LaTeX{}";
2090                                         i += 4;
2091                                         column += 7;
2092                                         /* idea for labels --- end*/ 
2093                                 } else if (c != '\0') {
2094                                         os << c;
2095                                 }
2096                                 break;
2097                         }
2098                 }
2099         }
2100 }
2101
2102
2103 LyXParagraph * LyXParagraph::TeXDeeper(Buffer const * buf,
2104                                        BufferParams const & bparams,
2105                                        ostream & os, TexRow & texrow)
2106 {
2107         lyxerr[Debug::LATEX] << "TeXDeeper...     " << this << endl;
2108         LyXParagraph * par = this;
2109
2110         while (par && par->params.depth() == params.depth()) {
2111                 if (textclasslist.Style(bparams.textclass, 
2112                                         par->layout).isEnvironment()) {
2113                         par = par->TeXEnvironment(buf, bparams,
2114                                                   os, texrow);
2115                 } else {
2116                         par = par->TeXOnePar(buf, bparams,
2117                                              os, texrow, false);
2118                 }
2119         }
2120         lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
2121
2122         return par;
2123 }
2124
2125
2126 LyXParagraph * LyXParagraph::TeXEnvironment(Buffer const * buf,
2127                                             BufferParams const & bparams,
2128                                             ostream & os, TexRow & texrow)
2129 {
2130         lyxerr[Debug::LATEX] << "TeXEnvironment...     " << this << endl;
2131
2132         LyXLayout const & style =
2133                 textclasslist.Style(bparams.textclass,
2134                                     layout);
2135
2136         if (style.isEnvironment()){
2137                 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
2138                         os << "\\begin{" << style.latexname() << "}{"
2139                            << params.labelWidthString() << "}\n";
2140                 } else if (style.labeltype == LABEL_BIBLIO) {
2141                         // ale970405
2142                         os << "\\begin{" << style.latexname() << "}{"
2143                            <<  bibitemWidest(buf)
2144                            << "}\n";
2145                 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
2146                         os << "\\begin{" << style.latexname() << '}'
2147                            << style.latexparam() << '\n';
2148                 } else 
2149                         os << "\\begin{" << style.latexname() << '}'
2150                            << style.latexparam() << '\n';
2151                 texrow.newline();
2152         }
2153         LyXParagraph * par = this;
2154         do {
2155                 par = par->TeXOnePar(buf, bparams,
2156                                      os, texrow, false);
2157
2158                 if (par && par->params.depth() > params.depth()) {
2159                         if (textclasslist.Style(bparams.textclass,
2160                                                 par->layout).isParagraph()
2161                             // Thinko!
2162                             // How to handle this? (Lgb)
2163                             //&& !suffixIs(os, "\n\n")
2164                                 ) {
2165                                 // There should be at least one '\n' already
2166                                 // but we need there to be two for Standard 
2167                                 // paragraphs that are depth-increment'ed to be
2168                                 // output correctly.  However, tables can
2169                                 // also be paragraphs so don't adjust them.
2170                                 // ARRae
2171                                 // Thinkee:
2172                                 // Will it ever harm to have one '\n' too
2173                                 // many? i.e. that we sometimes will have
2174                                 // three in a row. (Lgb)
2175                                 os << '\n';
2176                                 texrow.newline();
2177                         }
2178                         par = par->TeXDeeper(buf, bparams, os, texrow);
2179                 }
2180         } while (par
2181                  && par->layout == layout
2182                  && par->params.depth() == params.depth());
2183  
2184         if (style.isEnvironment()) {
2185                 os << "\\end{" << style.latexname() << "}\n";
2186         }
2187
2188         lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
2189         return par;  // ale970302
2190 }
2191
2192
2193 bool LyXParagraph::IsHfill(size_type pos) const
2194 {
2195         return IsHfillChar(GetChar(pos));
2196 }
2197
2198
2199 bool LyXParagraph::IsInset(size_type pos) const
2200 {
2201         return IsInsetChar(GetChar(pos));
2202 }
2203
2204
2205 bool LyXParagraph::IsNewline(size_type pos) const
2206 {
2207         return pos >= 0 && IsNewlineChar(GetChar(pos));
2208 }
2209
2210
2211 bool LyXParagraph::IsSeparator(size_type pos) const
2212 {
2213         return IsSeparatorChar(GetChar(pos));
2214 }
2215
2216
2217 bool LyXParagraph::IsLineSeparator(size_type pos) const
2218 {
2219         return IsLineSeparatorChar(GetChar(pos));
2220 }
2221
2222
2223 bool LyXParagraph::IsKomma(size_type pos) const
2224 {
2225         return IsKommaChar(GetChar(pos));
2226 }
2227
2228
2229 /// Used by the spellchecker
2230 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
2231 {
2232         value_type const c = GetChar(pos);
2233         if (IsLetterChar(c))
2234                 return true;
2235         // '\0' is not a letter, allthough every string contains "" (below)
2236         if (c == '\0')
2237                 return false;
2238         // We want to pass the ' and escape chars to ispell
2239         string const extra = lyxrc.isp_esc_chars + '\'';
2240         char ch[2] = { c, 0 };
2241         return contains(extra, ch);
2242 }
2243  
2244  
2245 bool LyXParagraph::IsWord(size_type pos ) const
2246 {
2247         return IsWordChar(GetChar(pos)) ;
2248 }
2249
2250
2251 Language const *
2252 LyXParagraph::getParLanguage(BufferParams const & bparams) const 
2253 {
2254         if (size() > 0)
2255                 return GetFirstFontSettings().language();
2256         else if (previous_)
2257                 return previous_->getParLanguage(bparams);
2258         else
2259                 return bparams.language;
2260 }
2261
2262
2263 bool LyXParagraph::isRightToLeftPar(BufferParams const & bparams) const
2264 {
2265         return lyxrc.rtl_support
2266                 && getParLanguage(bparams)->RightToLeft();
2267 }
2268
2269
2270 void LyXParagraph::ChangeLanguage(BufferParams const & bparams,
2271                                   Language const * from, Language const * to)
2272 {
2273         for (size_type i = 0; i < size(); ++i) {
2274                 LyXFont font = GetFontSettings(bparams, i);
2275                 if (font.language() == from) {
2276                         font.setLanguage(to);
2277                         SetFont(i, font);
2278                 }
2279         }
2280 }
2281
2282
2283 bool LyXParagraph::isMultiLingual(BufferParams const & bparams)
2284 {
2285         Language const * doc_language = bparams.language;
2286         for (FontList::const_iterator cit = fontlist.begin();
2287              cit != fontlist.end(); ++cit)
2288                 if ((*cit).font().language() != doc_language)
2289                         return true;
2290         return false;
2291 }
2292
2293
2294 // Convert the paragraph to a string.
2295 // Used for building the table of contents
2296 string const LyXParagraph::String(Buffer const * buffer, bool label)
2297 {
2298         BufferParams const & bparams = buffer->params;
2299         string s;
2300         if (label && !params.labelString().empty())
2301                 s += params.labelString() + ' ';
2302         string::size_type const len = s.size();
2303
2304         for (LyXParagraph::size_type i = 0; i < size(); ++i) {
2305                 value_type c = GetChar(i);
2306                 if (IsPrintable(c))
2307                         s += c;
2308                 else if (c == META_INSET &&
2309                          GetInset(i)->LyxCode() == Inset::MATH_CODE) {
2310                         std::ostringstream ost;
2311                         GetInset(i)->Ascii(buffer, ost);
2312                         s += subst(ost.str().c_str(),'\n',' ');
2313                 }
2314         }
2315
2316         if (isRightToLeftPar(bparams))
2317                 reverse(s.begin() + len,s.end());
2318
2319         return s;
2320 }
2321
2322
2323 string const LyXParagraph::String(Buffer const * buffer, 
2324                             LyXParagraph::size_type beg,
2325                             LyXParagraph::size_type end)
2326 {
2327         std::ostringstream ost;
2328
2329         if (beg == 0 && !params.labelString().empty())
2330                 ost << params.labelString() << ' ';
2331
2332         for (LyXParagraph::size_type i = beg; i < end; ++i) {
2333                 value_type const c = GetUChar(buffer->params, i);
2334                 if (IsPrintable(c))
2335                         ost << c;
2336                 else if (c == META_INSET) {
2337                         GetInset(i)->Ascii(buffer, ost);
2338                 }
2339         }
2340
2341         return ost.str().c_str();
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, true);
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, true);
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 }