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