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