]> git.lyx.org Git - lyx.git/blob - src/paragraph.C
02023d9b0af87f5879e48e6da07f9a8bcb4d812e
[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
20 #include "lyxparagraph.h"
21 #include "support/textutils.h"
22 #include "lyxrc.h"
23 #include "layout.h"
24 #include "tex-strings.h"
25 #include "bufferparams.h"
26 #include "support/FileInfo.h"
27 #include "support/LAssert.h"
28 #include "debug.h"
29 #include "LaTeXFeatures.h"
30 #include "insets/insetinclude.h"
31 #include "insets/insetbib.h"
32 #include "support/filetools.h"
33 #include "lyx_gui_misc.h"
34 #include "texrow.h"
35 #include "support/lyxmanip.h"
36
37 using std::ostream;
38 using std::endl;
39 using std::fstream;
40 using std::ios;
41 using std::lower_bound;
42 using std::upper_bound;
43 using std::reverse;
44
45 int tex_code_break_column = 72;  // needs non-zero initialization. set later.
46 // this is a bad idea, but how can LyXParagraph find its buffer to get
47 // parameters? (JMarc)
48 extern BufferView * current_view;
49 extern string bibitemWidest(Painter &);
50
51 // this is a minibuffer
52 static char minibuffer_char;
53 static LyXFont minibuffer_font;
54 static Inset * minibuffer_inset;
55
56
57 // Initialization of the counter for the paragraph id's,
58 // declared in lyxparagraph.h
59 unsigned int LyXParagraph::paragraph_id = 0;
60
61
62 LyXParagraph::LyXParagraph()
63 {
64         text.reserve(500); // is this number too big?
65
66         for (int i = 0; i < 10; ++i) setCounter(i , 0);
67         appendix = false;
68         enumdepth = 0;
69         itemdepth = 0;
70         next = 0;
71         previous = 0;
72         footnoteflag = LyXParagraph::NO_FOOTNOTE;
73         footnotekind = LyXParagraph::FOOTNOTE; // should not be needed
74         
75         align = LYX_ALIGN_BLOCK;
76
77 #ifndef NEW_TABULAR
78         /* table stuff -- begin*/ 
79         table = 0;
80         /* table stuff -- end*/
81 #endif
82         inset_owner = 0;
83         id_ = paragraph_id++;
84         bibkey = 0; // ale970302
85         Clear();
86 }
87
88
89 // This konstruktor inserts the new paragraph in a list.
90 LyXParagraph::LyXParagraph(LyXParagraph * par)
91 {
92         text.reserve(500);
93         par->text.resize(par->text.size());
94
95         for (int i = 0; i < 10; ++i) setCounter(i, 0);
96         appendix = false;
97         enumdepth = 0;
98         itemdepth = 0;
99         // double linked list begin
100         next = par->next;
101         if (next)
102                 next->previous = this;
103         previous = par;
104         previous->next = this;
105         // end
106         footnoteflag = LyXParagraph::NO_FOOTNOTE;
107         footnotekind = LyXParagraph::FOOTNOTE;
108
109 #ifndef NEW_TABULAR
110         /* table stuff -- begin*/ 
111         table = 0;
112         /* table stuff -- end*/
113 #endif
114         inset_owner = 0;
115         id_ = paragraph_id++;
116
117         bibkey = 0; // ale970302        
118     
119         Clear();
120 }
121
122
123 void LyXParagraph::writeFile(ostream & os, BufferParams const & params,
124                              char footflag, char dth) const
125 {
126         LyXFont font1, font2;
127         int column = 0;
128         int h = 0;
129         char c = 0;
130
131         if (footnoteflag != LyXParagraph::NO_FOOTNOTE
132             || !previous
133             || previous->footnoteflag == LyXParagraph::NO_FOOTNOTE){
134                 
135                 // The beginning or the end of a footnote environment?
136                 if (footflag != footnoteflag) {
137                         footflag = footnoteflag;
138                         if (footflag) {
139                                 os << "\n\\begin_float "
140                                    << string_footnotekinds[footnotekind]
141                                    << " ";
142                         } else {
143                                 os << "\n\\end_float ";
144                         }
145                 }
146
147                 // The beginning or end of a deeper (i.e. nested) area?
148                 if (dth != depth) {
149                         if (depth > dth) {
150                                 while (depth > dth) {
151                                         os << "\n\\begin_deeper ";
152                                         ++dth;
153                                 }
154                         } else {
155                                 while (depth < dth) {
156                                         os << "\n\\end_deeper ";
157                                         --dth;
158                                 }
159                         }
160                 }
161
162                 // First write the layout
163                 os << "\n\\layout "
164                    << textclasslist.NameOfLayout(params.textclass, layout)
165                    << "\n";
166
167                 // Maybe some vertical spaces.
168                 if (added_space_top.kind() != VSpace::NONE)
169                         os << "\\added_space_top "
170                            << added_space_top.asLyXCommand() << " ";
171                 if (added_space_bottom.kind() != VSpace::NONE)
172                         os << "\\added_space_bottom "
173                            << added_space_bottom.asLyXCommand() << " ";
174
175                 // Maybe the paragraph has special spacing
176                 spacing.writeFile(os, true);
177                 
178                 // The labelwidth string used in lists.
179                 if (!labelwidthstring.empty())
180                         os << "\\labelwidthstring "
181                            << labelwidthstring << '\n';
182
183                 // Lines above or below?
184                 if (line_top)
185                         os << "\\line_top ";
186                 if (line_bottom)
187                         os << "\\line_bottom ";
188
189                 // Pagebreaks above or below?
190                 if (pagebreak_top)
191                         os << "\\pagebreak_top ";
192                 if (pagebreak_bottom)
193                         os << "\\pagebreak_bottom ";
194                         
195                 // Start of appendix?
196                 if (start_of_appendix)
197                         os << "\\start_of_appendix ";
198
199                 // Noindent?
200                 if (noindent)
201                         os << "\\noindent ";
202                         
203                 // Alignment?
204                 if (align != LYX_ALIGN_LAYOUT) {
205                         switch (align) {
206                         case LYX_ALIGN_LEFT: h = 1; break;
207                         case LYX_ALIGN_RIGHT: h = 2; break;
208                         case LYX_ALIGN_CENTER: h = 3; break;
209                         default: h = 0; break;
210                         }
211                         os << "\\align " << string_align[h] << " ";
212                 }
213                 if (pextra_type != PEXTRA_NONE) {
214                         os << "\\pextra_type " << pextra_type;
215                         if (pextra_type == PEXTRA_MINIPAGE) {
216                                 os << " \\pextra_alignment "
217                                    << pextra_alignment;
218                                 if (pextra_hfill)
219                                         os << " \\pextra_hfill "
220                                            << pextra_hfill;
221                                 if (pextra_start_minipage)
222                                         os << " \\pextra_start_minipage "
223                                            << pextra_start_minipage;
224                         }
225                         if (!pextra_width.empty()) {
226                                 os << " \\pextra_width "
227                                    << VSpace(pextra_width).asLyXCommand();
228                         } else if (!pextra_widthp.empty()) {
229                                 os << " \\pextra_widthp "
230                                    << pextra_widthp;
231                         }
232                         os << '\n';
233                 }
234         } else {
235                 // Dummy layout. This means that a footnote ended.
236                 os << "\n\\end_float ";
237                 footflag = LyXParagraph::NO_FOOTNOTE;
238         }
239 #ifndef NEW_TABULAR     
240         // It might be a table.
241         if (table){
242                 os << "\\LyXTable\n";
243                 table->Write(os);
244         }
245 #endif
246         // bibitem  ale970302
247         if (bibkey)
248                 bibkey->Write(os);
249
250         font1 = LyXFont(LyXFont::ALL_INHERIT,params.language_info);
251
252         column = 0;
253         for (size_type i = 0; i < size(); ++i) {
254                 if (!i) {
255                         os << "\n";
256                         column = 0;
257                 }
258                 
259                 // Write font changes
260                 font2 = GetFontSettings(params, i);
261                 if (font2 != font1) {
262                         font2.lyxWriteChanges(font1, os);
263                         column = 0;
264                         font1 = font2;
265                 }
266
267                 c = GetChar(i);
268                 switch (c) {
269                 case META_INSET:
270                 {
271                         Inset const * inset = GetInset(i);
272                         if (inset)
273                                 if (inset->DirectWrite()) {
274                                         // international char, let it write
275                                         // code directly so it's shorter in
276                                         // the file
277                                         inset->Write(os);
278                                 } else {
279                                         os << "\n\\begin_inset ";
280                                         inset->Write(os);
281                                         os << "\n\\end_inset \n\n";
282                                         column = 0;
283                                 }
284                 }
285                 break;
286                 case META_NEWLINE: 
287                         os << "\n\\newline \n";
288                         column = 0;
289                         break;
290                 case META_HFILL: 
291                         os << "\n\\hfill \n";
292                         column = 0;
293                         break;
294                 case '\\':
295                         os << "\n\\backslash \n";
296                         column = 0;
297                         break;
298                 case '.':
299                         if (i + 1 < size() && GetChar(i + 1) == ' ') {
300                                 os << ".\n";
301                                 column = 0;
302                         } else
303                                 os << ".";
304                         break;
305                 default:
306                         if ((column > 70 && c == ' ')
307                             || column > 79) {
308                                 os << "\n";
309                                 column = 0;
310                         }
311                         // this check is to amend a bug. LyX sometimes
312                         // inserts '\0' this could cause problems.
313                         if (c != '\0')
314                                 os << c;
315                         else
316                                 lyxerr << "ERROR (LyXParagraph::writeFile):"
317                                         " NULL char in structure." << endl;
318                         ++column;
319                         break;
320                 }
321         }
322
323         // now write the next paragraph
324         if (next)
325                 next->writeFile(os, params, footflag, dth);
326 }
327
328
329 void LyXParagraph::validate(LaTeXFeatures & features) const
330 {
331         BufferParams const & params = features.bufferParams();
332         
333         // this will be useful later
334         LyXLayout const & layout =
335                 textclasslist.Style(params.textclass, 
336                                     GetLayout());
337         
338         // check the params.
339         if (line_top || line_bottom)
340                 features.lyxline = true;
341         if (!spacing.isDefault())
342                 features.setspace = true;
343         
344         // then the layouts
345         features.layout[GetLayout()] = true;
346
347         // then the fonts
348         Language const * doc_language = params.language_info;
349         
350         for (FontList::const_iterator cit = fontlist.begin();
351              cit != fontlist.end(); ++cit) {
352                 if ((*cit).font.noun() == LyXFont::ON) {
353                         lyxerr[Debug::LATEX] << "font.noun: "
354                                              << (*cit).font.noun()
355                                              << endl;
356                         features.noun = true;
357                         lyxerr[Debug::LATEX] << "Noun enabled. Font: "
358                                              << (*cit).font.stateText(0)
359                                              << endl;
360                 }
361                 switch ((*cit).font.color()) {
362                 case LColor::none:
363                 case LColor::inherit:
364                 case LColor::ignore:
365                         break;
366                 default:
367                         features.color = true;
368                         lyxerr[Debug::LATEX] << "Color enabled. Font: "
369                                              << (*cit).font.stateText(0)
370                                              << endl;
371                 }
372 #if 0
373                 Language const * language = (*cit).font.language();
374                 if (language != doc_language) {
375                         features.UsedLanguages.insert(language);
376                         lyxerr[Debug::LATEX] << "Found language "
377                                              << language->lang << endl;
378                 }
379 #endif
380         }
381
382         // This is not efficient. I plan to use the code above, after I
383         // change the fontlist handling.
384         for (size_type i = 0; i < size(); ++i) {
385                 Language const * language =
386                         GetFontSettings(params, i).language();
387                 if (language != doc_language)
388                         features.UsedLanguages.insert(language);
389         }
390
391         // then the insets
392         for (InsetList::const_iterator cit = insetlist.begin();
393              cit != insetlist.end(); ++cit) {
394                 if ((*cit).inset)
395                         (*cit).inset->Validate(features);
396         }
397
398         if (table && table->IsLongTable())
399                 features.longtable = true;
400         if (pextra_type == PEXTRA_INDENT)
401                 features.LyXParagraphIndent = true;
402         if (pextra_type == PEXTRA_FLOATFLT)
403                 features.floatflt = true;
404         if (layout.needprotect 
405             && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
406                 features.NeedLyXFootnoteCode = true;
407         if (params.paragraph_separation == BufferParams::PARSEP_INDENT
408             && pextra_type == LyXParagraph::PEXTRA_MINIPAGE)
409                 features.NeedLyXMinipageIndent = true;
410         if (table && table->NeedRotating())
411                 features.rotating = true;
412         if (footnoteflag != NO_FOOTNOTE && footnotekind == ALGORITHM)
413                 features.algorithm = true;
414 }
415
416
417 // First few functions needed for cut and paste and paragraph breaking.
418 void LyXParagraph::CopyIntoMinibuffer(BufferParams const & bparams,
419                                       LyXParagraph::size_type pos) const
420 {
421         minibuffer_char = GetChar(pos);
422         minibuffer_font = GetFontSettings(bparams, pos);
423         minibuffer_inset = 0;
424         if (minibuffer_char == LyXParagraph::META_INSET) {
425                 if (GetInset(pos)) {
426                         minibuffer_inset = GetInset(pos)->Clone();
427                 } else {
428                         minibuffer_inset = 0;
429                         minibuffer_char = ' ';
430                         // This reflects what GetInset() does (ARRae)
431                 }
432         }
433 }
434
435
436 void LyXParagraph::CutIntoMinibuffer(BufferParams const & bparams,
437                                      LyXParagraph::size_type pos)
438 {
439         minibuffer_char = GetChar(pos);
440         minibuffer_font = GetFontSettings(bparams, pos);
441         minibuffer_inset = 0;
442         if (minibuffer_char == LyXParagraph::META_INSET) {
443                 if (GetInset(pos)) {
444                         minibuffer_inset = GetInset(pos);
445                         // This is a little hack since I want exactly
446                         // the inset, not just a clone. Otherwise
447                         // the inset would be deleted when calling Erase(pos)
448                         // find the entry
449                         InsetList::iterator it = lower_bound(insetlist.begin(),
450                                                              insetlist.end(),
451                                                              pos, matchIT());
452                         if (it != insetlist.end() && (*it).pos == pos)
453                                 (*it).inset = 0;
454                 } else {
455                         minibuffer_inset = 0;
456                         minibuffer_char = ' ';
457                         // This reflects what GetInset() does (ARRae)
458                 }
459
460         }
461
462         // Erase(pos); now the caller is responsible for that.
463 }
464
465
466 bool LyXParagraph::InsertFromMinibuffer(LyXParagraph::size_type pos)
467 {
468         if ((minibuffer_char == LyXParagraph::META_INSET) &&
469             !InsertInsetAllowed(minibuffer_inset))
470                 return false;
471         InsertChar(pos, minibuffer_char);
472         SetFont(pos, minibuffer_font);
473         if (minibuffer_char == LyXParagraph::META_INSET)
474                 InsertInset(pos, minibuffer_inset);
475         return true;
476 }
477
478 // end of minibuffer
479
480
481
482 void LyXParagraph::Clear()
483 {
484         line_top = false;
485         line_bottom = false;
486    
487         pagebreak_top = false;
488         pagebreak_bottom = false;
489
490         added_space_top = VSpace(VSpace::NONE);
491         added_space_bottom = VSpace(VSpace::NONE);
492         spacing.set(Spacing::Default);
493         
494         align = LYX_ALIGN_LAYOUT;
495         depth = 0;
496         noindent = false;
497
498         pextra_type = PEXTRA_NONE;
499         pextra_width.erase();
500         pextra_widthp.erase();
501         pextra_alignment = MINIPAGE_ALIGN_TOP;
502         pextra_hfill = false;
503         pextra_start_minipage = false;
504
505         labelstring.erase();
506         labelwidthstring.erase();
507         layout = 0;
508         bibkey = 0;
509         
510         start_of_appendix = false;
511 }
512
513
514 // the destructor removes the new paragraph from the list
515 LyXParagraph::~LyXParagraph()
516 {
517         if (previous)
518                 previous->next = next;
519         if (next)
520                 next->previous = previous;
521
522         for (InsetList::iterator it = insetlist.begin();
523              it != insetlist.end(); ++it) {
524                 delete (*it).inset;
525         }
526 #ifndef NEW_TABULAR
527         /* table stuff -- begin*/ 
528         delete table;
529         /* table stuff -- end*/
530 #endif
531
532         // ale970302
533         delete bibkey;
534         //
535         //lyxerr << "LyXParagraph::paragraph_id = "
536         //       << LyXParagraph::paragraph_id << endl;
537 }
538
539
540 void LyXParagraph::Erase(LyXParagraph::size_type pos)
541 {
542         // > because last is the next unused position, and you can 
543         // use it if you want
544         if (pos > size()) {
545                 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
546                         NextAfterFootnote()->Erase(pos - text.size() - 1);
547                 else 
548                         lyxerr.debug() << "ERROR (LyXParagraph::Erase): "
549                                 "position does not exist." << endl;
550                 return;
551         }
552         if (pos < size()) { // last is free for insertation, but should be empty
553                 // if it is an inset, delete the inset entry 
554                 if (text[pos] == LyXParagraph::META_INSET) {
555                         // find the entry
556                         InsetList::iterator it = lower_bound(insetlist.begin(),
557                                                              insetlist.end(),
558                                                              pos, matchIT());
559                         if (it != insetlist.end() && (*it).pos == pos) {
560                                 delete (*it).inset;
561                                 insetlist.erase(it);
562                         }
563                 }
564                 text.erase(text.begin() + pos);
565                 // Erase entries in the tables.
566                 for (FontList::iterator it = fontlist.begin();
567                      it != fontlist.end(); ++it) {
568                         if (pos >= (*it).pos && pos <= (*it).pos_end) {
569                                 if ((*it).pos == (*it).pos_end) {
570                                         // If it is a multi-character font
571                                         // entry, we just make it smaller
572                                         // (see update below), otherwise we
573                                         // should delete it.
574                                         fontlist.erase(it);
575                                         break;
576                                 }
577                         }
578                 }
579                 // Update all other entries.
580                 for (FontList::iterator it = fontlist.begin();
581                      it != fontlist.end(); ++it) {
582                         if ((*it).pos > pos)
583                                 (*it).pos--;
584                         if ((*it).pos_end >= pos)
585                                 (*it).pos_end--;
586                 }
587
588                 // Update the inset table.
589                 for (InsetList::iterator it = upper_bound(insetlist.begin(),
590                                                           insetlist.end(),
591                                                           pos, matchIT());
592                      it != insetlist.end(); ++it)
593                         --(*it).pos;
594         } else {
595                 lyxerr << "ERROR (LyXParagraph::Erase): "
596                         "can't erase non-existant char." << endl;
597         }
598 }
599
600
601 void LyXParagraph::InsertChar(LyXParagraph::size_type pos, char c)
602 {
603         // > because last is the next unused position, and you can 
604         // use it if you want
605         if (pos > size()) {
606                 if (next
607                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
608                         NextAfterFootnote()->InsertChar(pos - text.size() - 1,
609                                                         c);
610                 else 
611                         lyxerr.debug() << "ERROR (LyXParagraph::InsertChar): "
612                                 "position does not exist." << endl;
613                 return;
614         }
615         text.insert(text.begin() + pos, c);
616         // Update the font table.
617         for (FontList::iterator it = fontlist.begin();
618              it != fontlist.end(); ++it) {
619                 if ((*it).pos >= pos)
620                         (*it).pos++;
621                 if ((*it).pos_end >= pos)
622                         (*it).pos_end++;
623         }
624    
625         // Update the inset table.
626         for (InsetList::iterator it = lower_bound(insetlist.begin(),
627                                                   insetlist.end(),
628                                                   pos, matchIT());
629              it != insetlist.end(); ++it)
630                 ++(*it).pos;
631 }
632
633
634 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
635                                Inset * inset)
636 {
637         // > because last is the next unused position, and you can 
638         // use it if you want
639         if (pos > size()) {
640                 if (next
641                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
642                         NextAfterFootnote()
643                                 ->InsertInset(pos - text.size() - 1, inset);
644                 else 
645                         lyxerr << "ERROR (LyXParagraph::InsertInset): " 
646                                 "position does not exist: " << pos << endl;
647                 return;
648         }
649         if (text[pos] != LyXParagraph::META_INSET) {
650                 lyxerr << "ERROR (LyXParagraph::InsertInset): "
651                         "there is no LyXParagraph::META_INSET" << endl;
652                 return;
653         }
654
655         if (inset) {
656                 // Add a new entry in the inset table.
657                 InsetList::iterator it = lower_bound(insetlist.begin(),
658                                                      insetlist.end(),
659                                                      pos, matchIT());
660                 if (it != insetlist.end() && (*it).pos == pos)
661                         lyxerr << "ERROR (LyXParagraph::InsertInset): "
662                                 "there is an inset in position: " << pos << endl;
663                 else
664                         insetlist.insert(it, InsetTable(pos,inset));
665                 if (inset_owner)
666                         inset->setOwner(inset_owner);
667         }
668 }
669
670
671 bool LyXParagraph::InsertInsetAllowed(Inset * inset)
672 {
673         if (inset_owner)
674                 return inset_owner->InsertInsetAllowed(inset);
675         return true;
676 }
677
678
679 Inset * LyXParagraph::GetInset(LyXParagraph::size_type pos)
680 {
681         if (pos >= size()) {
682                 if (next
683                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
684                         return NextAfterFootnote()
685                                 ->GetInset(pos - text.size() - 1);
686                 else { 
687                         lyxerr << "ERROR (LyXParagraph::GetInset): "
688                                 "position does not exist: "
689                                << pos << endl;
690                 }
691                 return 0;
692         }
693         // Find the inset.
694         InsetList::iterator it = lower_bound(insetlist.begin(),
695                                              insetlist.end(),
696                                              pos, matchIT());
697         if (it != insetlist.end() && (*it).pos == pos)
698                 return (*it).inset;
699
700         lyxerr << "ERROR (LyXParagraph::GetInset): "
701                 "Inset does not exist: " << pos << endl;
702         // text[pos] = ' '; // WHY!!! does this set the pos to ' '????
703         // Did this commenting out introduce a bug? So far I have not
704         // see any, please enlighten me. (Lgb)
705         // My guess is that since the inset does not exist, we might
706         // as well replace it with a space to prevent craches. (Asger)
707         return 0;
708 }
709
710
711 Inset const * LyXParagraph::GetInset(LyXParagraph::size_type pos) const
712 {
713         if (pos >= size()) {
714                 if (next
715                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
716                         return NextAfterFootnote()
717                                 ->GetInset(pos - text.size() - 1);
718                 else { 
719                         lyxerr << "ERROR (LyXParagraph::GetInset): "
720                                 "position does not exist: "
721                                << pos << endl;
722                 }
723                 return 0;
724         }
725         // Find the inset.
726         InsetList::const_iterator cit = lower_bound(insetlist.begin(),
727                                                     insetlist.end(),
728                                                     pos, matchIT());
729         if (cit != insetlist.end() && (*cit).pos == pos)
730                 return (*cit).inset;
731
732         lyxerr << "ERROR (LyXParagraph::GetInset): "
733                 "Inset does not exist: " << pos << endl;
734         //text[pos] = ' '; // WHY!!! does this set the pos to ' '????
735         // Did this commenting out introduce a bug? So far I have not
736         // see any, please enlighten me. (Lgb)
737         // My guess is that since the inset does not exist, we might
738         // as well replace it with a space to prevent craches. (Asger)
739         return 0;
740 }
741
742
743 // Gets uninstantiated font setting at position.
744 // Optimized after profiling. (Asger)
745 LyXFont LyXParagraph::GetFontSettings(BufferParams const & bparams,
746                                       LyXParagraph::size_type pos) const
747 {
748         if (pos < size()) {
749 #ifdef SORTED_FONT_LIST
750                 for (FontList::const_iterator cit = fontlist.begin();
751                      cit != fontlist.end() && pos <= (*cit).pos_end; ++cit)
752                         if (pos >= (*cit).pos)
753                                 return (*cit).font;
754 #else
755                 for (FontList::const_iterator cit = fontlist.begin();
756                      cit != fontlist.end(); ++cit)
757                         if (pos >= (*cit).pos && pos <= (*cit).pos_end)
758                                 return (*cit).font;
759 #endif
760         }
761         // > because last is the next unused position, and you can 
762         // use it if you want
763         else if (pos > size()) {
764                 if (next
765                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
766                         return NextAfterFootnote()
767                                 ->GetFontSettings(bparams,
768                                                   pos - text.size() - 1);
769                 else {
770                         // Why is it an error to ask for the font of a
771                         // position that does not exist? Would it be
772                         // enough for this to be enabled on debug?
773                         // We want strict error checking, but it's ok to only
774                         // have it when debugging. (Asger)
775                         lyxerr << "ERROR (LyXParagraph::GetFontSettings): "
776                                 "position does not exist. "
777                                << pos << " (" << static_cast<int>(pos)
778                                << ")" << endl;
779                 }
780         } else if (pos > 0) {
781                 return GetFontSettings(bparams, pos - 1);
782         } else // pos = size() = 0
783                 return LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
784
785         return LyXFont(LyXFont::ALL_INHERIT);
786 }
787
788 // Gets uninstantiated font setting at position 0
789 LyXFont LyXParagraph::GetFirstFontSettings() const
790 {
791         if (size() > 0) {
792 #ifdef SORTED_FONT_LIST
793                 if (!fontlist.empty() && fontlist.front().pos == 0)
794                         return fontlist.front().font;
795 #else
796                 for (FontList::const_iterator cit = fontlist.begin();
797                      cit != fontlist.end(); ++cit)
798                         if (0 >= (*cit).pos && 0 <= (*cit).pos_end)
799                                 return (*cit).font;
800 #endif
801         } else if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) 
802                 return NextAfterFootnote()->GetFirstFontSettings();
803         return LyXFont(LyXFont::ALL_INHERIT);
804 }
805
806
807 // Gets the fully instantiated font at a given position in a paragraph
808 // This is basically the same function as LyXText::GetFont() in text2.C.
809 // The difference is that this one is used for generating the LaTeX file,
810 // and thus cosmetic "improvements" are disallowed: This has to deliver
811 // the true picture of the buffer. (Asger)
812 // If position is -1, we get the layout font of the paragraph.
813 // If position is -2, we get the font of the manual label of the paragraph.
814 LyXFont LyXParagraph::getFont(BufferParams const & bparams,
815                               LyXParagraph::size_type pos) const
816 {
817         LyXFont tmpfont;
818         LyXLayout const & layout =
819                 textclasslist.Style(bparams.textclass, 
820                                     GetLayout());
821         LyXParagraph::size_type main_body = 0;
822         if (layout.labeltype == LABEL_MANUAL)
823                 main_body = BeginningOfMainBody();
824
825         if (pos >= 0) {
826                 LyXFont layoutfont;
827                 if (pos < main_body)
828                         layoutfont = layout.labelfont;
829                 else
830                         layoutfont = layout.font;
831                 tmpfont = GetFontSettings(bparams, pos);
832                 tmpfont.realize(layoutfont);
833         } else {
834                 // process layoutfont for pos == -1 and labelfont for pos < -1
835                 if (pos == -1)
836                         tmpfont = layout.font;
837                 else
838                         tmpfont = layout.labelfont;
839                 tmpfont.setLanguage(getParLanguage(bparams));
840         }
841
842         // check for environment font information
843         char par_depth = GetDepth();
844         LyXParagraph const * par = this;
845         while (par && par_depth && !tmpfont.resolved()) {
846                 par = par->DepthHook(par_depth - 1);
847                 if (par) {
848                         tmpfont.realize(textclasslist.
849                                         Style(bparams.textclass,
850                                               par->GetLayout()).font);
851                         par_depth = par->GetDepth();
852                 }
853         }
854
855         tmpfont.realize(textclasslist
856                         .TextClass(bparams.textclass)
857                         .defaultfont());
858         return tmpfont;
859 }
860
861
862 /// Returns the height of the highest font in range
863 LyXFont::FONT_SIZE
864 LyXParagraph::HighestFontInRange(LyXParagraph::size_type startpos,
865                                  LyXParagraph::size_type endpos) const
866 {
867         LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
868         for (FontList::const_iterator cit = fontlist.begin();
869              cit != fontlist.end(); ++cit) {
870                 if (startpos <= (*cit).pos_end && endpos >= (*cit).pos) {
871                         LyXFont::FONT_SIZE size = (*cit).font.size();
872                         if (size > maxsize && size <= LyXFont::SIZE_HUGER)
873                                 maxsize = size;
874                 }
875         }
876         return maxsize;
877 }
878
879
880 char LyXParagraph::GetChar(LyXParagraph::size_type pos)
881 {
882         Assert(pos >= 0);
883
884         if (pos < size()) {
885                 return text[pos];
886         }
887         // > because last is the next unused position, and you can 
888         // use it if you want
889         else if (pos > size()) {
890                 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) 
891                         return NextAfterFootnote()
892                                 ->GetChar(pos - text.size() - 1);
893                 else {
894                         lyxerr << "ERROR (LyXParagraph::GetChar): "
895                                 "position does not exist."
896                                << pos << " (" << static_cast<int>(pos)
897                                << ")\n";
898                         // Assert(false); // This triggers sometimes...
899                         // Why?
900                 }
901                 return '\0';
902         } else {
903                 // We should have a footnote environment.
904                 if (!next || next->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
905                         // Notice that LyX does request the
906                         // last char from time to time. (Asger)
907                         //lyxerr << "ERROR (LyXParagraph::GetChar): "
908                         //      "expected footnote." << endl;
909                         return '\0';
910                 }
911                 switch (next->footnotekind) {
912                 case LyXParagraph::FOOTNOTE:
913                         return LyXParagraph::META_FOOTNOTE;
914                 case LyXParagraph::MARGIN:
915                         return LyXParagraph::META_MARGIN;
916                 case LyXParagraph::FIG:
917                 case LyXParagraph::WIDE_FIG:
918                         return LyXParagraph::META_FIG;
919                 case LyXParagraph::TAB:
920                 case LyXParagraph::WIDE_TAB:
921                         return LyXParagraph::META_TAB;
922                 case LyXParagraph::ALGORITHM:
923                         return LyXParagraph::META_ALGORITHM;
924                 }
925                 return '\0'; // to shut up gcc
926         }
927 }
928
929
930 char LyXParagraph::GetChar(LyXParagraph::size_type pos) const
931 {
932         Assert(pos >= 0);
933
934         if (pos < size()) {
935                 return text[pos];
936         }
937         // > because last is the next unused position, and you can 
938         // use it if you want
939         else if (pos > size()) {
940                 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) 
941                         return NextAfterFootnote()
942                                 ->GetChar(pos - text.size() - 1);
943                 else {
944                         lyxerr << "ERROR (LyXParagraph::GetChar const): "
945                                 "position does not exist."
946                                << pos << " (" << static_cast<int>(pos)
947                                << ")\n";
948                         Assert(false);
949                 }
950                 return '\0';
951         } else {
952                 // We should have a footnote environment.
953                 if (!next || next->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
954                         // Notice that LyX does request the
955                         // last char from time to time. (Asger)
956                         //lyxerr << "ERROR (LyXParagraph::GetChar): "
957                         //      "expected footnote." << endl;
958                         return '\0';
959                 }
960                 switch (next->footnotekind) {
961                 case LyXParagraph::FOOTNOTE:
962                         return LyXParagraph::META_FOOTNOTE;
963                 case LyXParagraph::MARGIN:
964                         return LyXParagraph::META_MARGIN;
965                 case LyXParagraph::FIG:
966                 case LyXParagraph::WIDE_FIG:
967                         return LyXParagraph::META_FIG;
968                 case LyXParagraph::TAB:
969                 case LyXParagraph::WIDE_TAB:
970                         return LyXParagraph::META_TAB;
971                 case LyXParagraph::ALGORITHM:
972                         return LyXParagraph::META_ALGORITHM;
973                 }
974                 return '\0'; // to shut up gcc
975         }
976 }
977
978
979 // return an string of the current word, and the end of the word in lastpos.
980 string LyXParagraph::GetWord(LyXParagraph::size_type & lastpos) const
981 {
982         Assert(lastpos>=0);
983
984         // the current word is defined as starting at the first character
985         // from the immediate left of lastpospos which meets the definition
986         // of IsLetter(), continuing to the last character to the right
987         // of this meeting IsLetter.
988
989         string theword;
990
991         // grab a word
992                 
993         // move back until we have a letter
994
995         //there's no real reason to have firstpos & lastpos as
996         //separate variables as this is written, but maybe someon
997         // will want to return firstpos in the future.
998
999         //since someone might have typed a punctuation first
1000         int firstpos = lastpos;
1001         
1002         while ((firstpos >= 0) && !IsLetter(firstpos))
1003                 --firstpos;
1004
1005         // now find the beginning by looking for a nonletter
1006         
1007         while ((firstpos>= 0) && IsLetter(firstpos))
1008                 --firstpos;
1009
1010         // the above is now pointing to the preceeding non-letter
1011         ++firstpos;
1012         lastpos = firstpos;
1013
1014         // so copy characters into theword  until we get a nonletter
1015         // note that this can easily exceed lastpos, wich means
1016         // that if used in the middle of a word, the whole word
1017         // is included
1018
1019         while (IsLetter(lastpos)) theword += GetChar(lastpos++);
1020         
1021         return theword;
1022
1023 }
1024
1025  
1026 LyXParagraph::size_type LyXParagraph::Last() const
1027 {
1028         if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1029                 return text.size() + NextAfterFootnote()->Last() + 1;
1030         // the 1 is the symbol
1031         // for the footnote
1032         else
1033                 return text.size();
1034 }
1035
1036
1037 LyXParagraph * LyXParagraph::ParFromPos(LyXParagraph::size_type pos)
1038 {
1039         // > because last is the next unused position, and you can 
1040         // use it if you want
1041         if (pos > size()) {
1042                 if (next
1043                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
1044                         return NextAfterFootnote()
1045                                 ->ParFromPos(pos - text.size() - 1);
1046                 else 
1047                         lyxerr << "ERROR (LyXParagraph::ParFromPos): "
1048                                 "position does not exist." << endl;
1049                 return this;
1050         } else
1051                 return this;
1052 }
1053
1054
1055 int LyXParagraph::PositionInParFromPos(LyXParagraph::size_type pos) const
1056 {
1057         // > because last is the next unused position, and you can 
1058         // use it if you want
1059         if (pos > size()) {
1060                 if (next
1061                     && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) 
1062                         return NextAfterFootnote()
1063                                 ->PositionInParFromPos(pos - text.size() - 1);
1064                 else 
1065                         lyxerr <<
1066                                 "ERROR (LyXParagraph::PositionInParFromPos): "
1067                                 "position does not exist." << endl;
1068                 return pos;
1069         }
1070         else
1071                 return pos;
1072 }
1073
1074
1075 void LyXParagraph::SetFont(LyXParagraph::size_type pos,
1076                            LyXFont const & font)
1077 {
1078         // > because last is the next unused position, and you can 
1079         // use it if you want
1080         if (pos > size()) {
1081                 if (next &&
1082                     next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1083                         NextAfterFootnote()->SetFont(pos - text.size() - 1,
1084                                                      font);
1085                 } else {
1086                         lyxerr << "ERROR (LyXParagraph::SetFont): "
1087                                 "position does not exist." << endl;
1088                 }
1089                 return;
1090         }
1091         LyXFont patternfont(LyXFont::ALL_INHERIT);
1092
1093         // First, reduce font against layout/label font
1094         // Update: The SetCharFont() routine in text2.C already
1095         // reduces font, so we don't need to do that here. (Asger)
1096         // No need to simplify this because it will disappear
1097         // in a new kernel. (Asger)
1098         // Next search font table
1099         FontList::iterator tmp = fontlist.begin();
1100         for (; tmp != fontlist.end(); ++tmp) {
1101                 if (pos >= (*tmp).pos && pos <= (*tmp).pos_end) {
1102                         break;
1103                 }
1104         }
1105         if (tmp == fontlist.end()) { // !found
1106                 // if we did not find a font entry, but if the font at hand
1107                 // is the same as default, we just forget it
1108                 if (font == patternfont) return;
1109
1110                 // ok, we did not find a font entry. But maybe there is exactly
1111                 // the needed font ientry one position left
1112                 FontList::iterator tmp2 = fontlist.begin();
1113                 for (; tmp2 != fontlist.end(); ++tmp2) {
1114                         if (pos - 1 >= (*tmp2).pos
1115                             && pos - 1 <= (*tmp2).pos_end)
1116                                 break;
1117                 }
1118                 if (tmp2 != fontlist.end()) {
1119                         // ok there is one, maybe it is exactly
1120                         // the needed font
1121                         if ((*tmp2).font == font) {
1122                                 // put the position under the font
1123                                 (*tmp2).pos_end++;
1124                                 return;
1125                         }
1126                 }
1127                 // Add a new entry in the
1128                 // fontlist for the position
1129                 FontTable ft;
1130                 ft.pos = pos;
1131                 ft.pos_end = pos;
1132                 ft.font = font; // or patternfont
1133                 // It seems that using font instead of patternfont here
1134                 // fixes all the problems. This also surfaces a "bug" in
1135                 // the old code.
1136                 fontlist.insert(fontlist.begin(), ft);
1137         } else if ((*tmp).pos != (*tmp).pos_end) { // we found a font entry. maybe we have to split it and create a new one.
1138
1139 // more than one character
1140                 if (pos == (*tmp).pos) {
1141                         // maybe we should enlarge the left fonttable
1142                         FontList::iterator tmp2 = fontlist.begin();
1143                         for (; tmp2 != fontlist.end(); ++tmp2) {
1144                                 if (pos - 1 >= (*tmp2).pos
1145                                     && pos - 1 <= (*tmp2).pos_end)
1146                                         break;
1147                         }
1148                         // Is there is one, and is it exactly
1149                         // the needed font?
1150                         if (tmp2 != fontlist.end() &&
1151                             (*tmp2).font == font) {
1152                                 // Put the position under the font
1153                                 (*tmp2).pos_end++;
1154                                 (*tmp).pos++;
1155                                 return;
1156                         }
1157
1158                         // Add a new entry in the
1159                         // fontlist for the position
1160                         FontTable ft;
1161                         ft.pos = pos + 1;
1162                         ft.pos_end = (*tmp).pos_end;
1163                         ft.font = (*tmp).font;
1164                         (*tmp).pos_end = pos;
1165                         (*tmp).font = font;
1166                         fontlist.insert(fontlist.begin(), ft);
1167                 } else if (pos == (*tmp).pos_end) {
1168                         // Add a new entry in the
1169                         // fontlist for the position
1170                         FontTable ft;
1171                         ft.pos = (*tmp).pos;
1172                         ft.pos_end = (*tmp).pos_end - 1;
1173                         ft.font = (*tmp).font;
1174                         (*tmp).pos = (*tmp).pos_end;
1175                         (*tmp).font = font;
1176                         fontlist.insert(fontlist.begin(), ft);
1177                 } else {
1178                         // Add a new entry in the
1179                         // fontlist for the position
1180                         FontTable ft;
1181                         ft.pos = (*tmp).pos;
1182                         ft.pos_end = pos - 1;
1183                         ft.font = (*tmp).font;
1184                         
1185                         FontTable ft2;
1186                         ft2.pos = pos + 1;
1187                         ft2.pos_end = (*tmp).pos_end;
1188                         ft2.font = (*tmp).font;
1189                         
1190                         (*tmp).pos = pos;
1191                         (*tmp).pos_end = pos;
1192                         (*tmp).font = font;
1193                         
1194                         fontlist.insert(fontlist.begin(), ft);
1195                         fontlist.insert(fontlist.begin(), ft2);
1196                 }
1197         } else {
1198                 (*tmp).font = font;
1199         }
1200 }
1201
1202    
1203 // This function is able to hide closed footnotes.
1204 LyXParagraph * LyXParagraph::Next()
1205 {
1206         if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1207                 LyXParagraph * tmp = next;
1208                 while (tmp
1209                        && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1210                         tmp = tmp->next;
1211                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1212                         return tmp->Next(); /* there can be more than one
1213                                                footnote in a logical
1214                                                paragraph */
1215                 else
1216                         return next;  // This should never happen!
1217         } else
1218                 return next;
1219 }
1220
1221
1222 LyXParagraph * LyXParagraph::NextAfterFootnote()
1223 {
1224         if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1225                 LyXParagraph * tmp = next;
1226                 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1227                         tmp = tmp->next;
1228                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1229                         return tmp;   /* there can be more than one footnote
1230                                          in a logical paragraph */
1231                 else
1232                         return next;  // This should never happen!
1233         } else
1234                 return next;
1235 }
1236
1237
1238 LyXParagraph const * LyXParagraph::NextAfterFootnote() const
1239 {
1240         if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1241                 LyXParagraph * tmp = next;
1242                 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1243                         tmp = tmp->next;
1244                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1245                         return tmp;   /* there can be more than one footnote
1246                                          in a logical paragraph */
1247                 else
1248                         return next;  // This should never happen!
1249         } else
1250                 return next;
1251 }
1252
1253
1254 LyXParagraph * LyXParagraph::PreviousBeforeFootnote()
1255 {
1256         LyXParagraph * tmp;
1257         if (previous && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1258                 tmp = previous;
1259                 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1260                         tmp = tmp->previous;
1261                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1262                         return tmp;    /* there can be more than one footnote
1263                                           in a logical paragraph */
1264                 else
1265                         return previous;  // This should never happen!
1266         } else
1267                 return previous;
1268 }
1269
1270
1271 LyXParagraph * LyXParagraph::LastPhysicalPar()
1272 {
1273         if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1274                 return this;
1275    
1276         LyXParagraph * tmp = this;
1277         while (tmp->next
1278                && tmp->next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1279                 tmp = tmp->NextAfterFootnote();
1280    
1281         return tmp;
1282 }
1283
1284 LyXParagraph const * LyXParagraph::LastPhysicalPar() const
1285 {
1286         if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1287                 return this;
1288    
1289         LyXParagraph const * tmp = this;
1290         while (tmp->next
1291                && tmp->next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1292                 tmp = tmp->NextAfterFootnote();
1293    
1294         return tmp;  
1295 }
1296
1297 LyXParagraph * LyXParagraph::FirstPhysicalPar()
1298 {
1299         if (!IsDummy())
1300                 return this;
1301         LyXParagraph * tmppar = this;
1302
1303         while (tmppar &&
1304                (tmppar->IsDummy()
1305                 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1306                 tmppar = tmppar->previous;
1307    
1308         if (!tmppar) {
1309                 return this;
1310         } else
1311                 return tmppar;
1312 }
1313
1314
1315 LyXParagraph const * LyXParagraph::FirstPhysicalPar() const
1316 {
1317         if (!IsDummy())
1318                 return this;
1319         LyXParagraph const * tmppar = this;
1320
1321         while (tmppar &&
1322                (tmppar->IsDummy()
1323                 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1324                 tmppar = tmppar->previous;
1325    
1326         if (!tmppar) {
1327                 return this;
1328         } else
1329                 return tmppar;
1330 }
1331
1332
1333 // This function is able to hide closed footnotes.
1334 LyXParagraph * LyXParagraph::Previous()
1335 {
1336         LyXParagraph * tmp = previous;
1337         if (!tmp)
1338                 return tmp;
1339    
1340         if (tmp->previous
1341             && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1342                 tmp = tmp->previous;
1343                 while (tmp
1344                        && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1345                         tmp = tmp->previous;
1346                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1347                         return tmp->next->Previous();   
1348
1349                 else
1350                         return previous; 
1351         } else
1352                 return previous;
1353 }
1354
1355
1356 // This function is able to hide closed footnotes.
1357 LyXParagraph const * LyXParagraph::Previous() const
1358 {
1359         LyXParagraph * tmp = previous;
1360         if (!tmp)
1361                 return tmp;
1362    
1363         if (tmp->previous
1364             && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1365                 tmp = tmp->previous;
1366                 while (tmp
1367                        && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1368                         tmp = tmp->previous;
1369                 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE) 
1370                         return tmp->next->Previous();   
1371
1372                 else
1373                         return previous; 
1374         } else
1375                 return previous;
1376 }
1377
1378
1379 void LyXParagraph::BreakParagraph(BufferParams const & bparams,
1380                                   LyXParagraph::size_type pos,
1381                                   int flag)
1382 {
1383         size_type i, j, pos_end, pos_first;
1384         // create a new paragraph
1385         LyXParagraph * par = ParFromPos(pos);
1386         LyXParagraph * firstpar = FirstPhysicalPar();
1387    
1388         LyXParagraph * tmp = new LyXParagraph(par);
1389         
1390         tmp->footnoteflag = footnoteflag;
1391         tmp->footnotekind = footnotekind;
1392    
1393         // this is an idea for a more userfriendly layout handling, I will
1394         // see what the users say
1395    
1396         // layout stays the same with latex-environments
1397         if (flag) {
1398                 tmp->SetOnlyLayout(bparams, firstpar->layout);
1399                 tmp->SetLabelWidthString(firstpar->labelwidthstring);
1400         }
1401
1402         if (Last() > pos || !Last() || flag == 2) {
1403                 tmp->SetOnlyLayout(bparams, firstpar->layout);
1404                 tmp->align = firstpar->align;
1405                 tmp->SetLabelWidthString(firstpar->labelwidthstring);
1406       
1407                 tmp->line_bottom = firstpar->line_bottom;
1408                 firstpar->line_bottom = false;
1409                 tmp->pagebreak_bottom = firstpar->pagebreak_bottom;
1410                 firstpar->pagebreak_bottom = false;
1411                 tmp->added_space_bottom = firstpar->added_space_bottom;
1412                 firstpar->added_space_bottom = VSpace(VSpace::NONE);
1413       
1414                 tmp->depth = firstpar->depth;
1415                 tmp->noindent = firstpar->noindent;
1416    
1417                 // copy everything behind the break-position
1418                 // to the new paragraph
1419                 pos_first = 0;
1420                 while (ParFromPos(pos_first) != par)
1421                         ++pos_first;
1422
1423                 pos_end = pos_first + par->text.size() - 1;
1424
1425                 for (i = j = pos; i <= pos_end; ++i) {
1426                         par->CutIntoMinibuffer(bparams, i - pos_first);
1427                         if (tmp->InsertFromMinibuffer(j - pos))
1428                                 ++j;
1429                 }
1430                 tmp->text.resize(tmp->text.size());
1431                 for (i = pos_end; i >= pos; --i)
1432                         par->Erase(i - pos_first);
1433
1434                 par->text.resize(par->text.size());
1435         }
1436
1437         // just an idea of me
1438         if (!pos) {
1439                 tmp->line_top = firstpar->line_top;
1440                 tmp->pagebreak_top = firstpar->pagebreak_top;
1441                 tmp->added_space_top = firstpar->added_space_top;
1442                 tmp->bibkey = firstpar->bibkey;
1443                 firstpar->Clear();
1444                 // layout stays the same with latex-environments
1445                 if (flag) {
1446                         firstpar->SetOnlyLayout(bparams, tmp->layout);
1447                         firstpar->SetLabelWidthString(tmp->labelwidthstring);
1448                         firstpar->depth = tmp->depth;
1449                 }
1450         }
1451 }
1452
1453
1454 void LyXParagraph::MakeSameLayout(LyXParagraph const * par)
1455 {
1456         par = par->FirstPhysicalPar();
1457         footnoteflag = par->footnoteflag;
1458         footnotekind = par->footnotekind;
1459
1460         layout = par->layout;
1461         align = par-> align;
1462         SetLabelWidthString(par->labelwidthstring);
1463
1464         line_bottom = par->line_bottom;
1465         pagebreak_bottom = par->pagebreak_bottom;
1466         added_space_bottom = par->added_space_bottom;
1467
1468         line_top = par->line_top;
1469         pagebreak_top = par->pagebreak_top;
1470         added_space_top = par->added_space_top;
1471
1472         spacing = par->spacing;
1473         
1474         pextra_type = par->pextra_type;
1475         pextra_width = par->pextra_width;
1476         pextra_widthp = par->pextra_widthp;
1477         pextra_alignment = par->pextra_alignment;
1478         pextra_hfill = par->pextra_hfill;
1479         pextra_start_minipage = par->pextra_start_minipage;
1480
1481         noindent = par->noindent;
1482         depth = par->depth;
1483 }
1484
1485
1486 LyXParagraph * LyXParagraph::FirstSelfrowPar()
1487 {
1488         LyXParagraph * tmppar = this;
1489         while (tmppar && (
1490                 (tmppar->IsDummy()
1491                  && tmppar->previous->footnoteflag == 
1492                  LyXParagraph::CLOSED_FOOTNOTE)
1493                 || tmppar->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))
1494                 tmppar = tmppar->previous;
1495    
1496         if (!tmppar)
1497                 return this;  // This should never happen!
1498         else
1499                 return tmppar;
1500 }
1501
1502 int LyXParagraph::StripLeadingSpaces(LyXTextClassList::size_type tclass) 
1503 {
1504         if (textclasslist.Style(tclass, GetLayout()).free_spacing)
1505                 return 0;
1506         
1507         int i = 0;
1508         if (!IsDummy() && !table){
1509                 while (Last()
1510                        && (IsNewline(0) || IsLineSeparator(0))){
1511                         Erase(0);
1512                         ++i;
1513                 }
1514         }
1515         return i;
1516 }
1517
1518
1519 LyXParagraph * LyXParagraph::Clone() const
1520 {
1521         // create a new paragraph
1522         LyXParagraph * result = new LyXParagraph;
1523    
1524         result->MakeSameLayout(this);
1525
1526         // this is because of the dummy layout of the paragraphs that
1527         // follow footnotes
1528         result->layout = layout;
1529
1530 #ifndef NEW_TABULAR
1531         /* table stuff -- begin*/ 
1532         if (table)
1533                 result->table = table->Clone();
1534         else
1535                 result->table = 0;
1536         /* table stuff -- end*/ 
1537 #endif
1538         result->inset_owner = inset_owner;
1539    
1540         // ale970302
1541         result->bibkey = (bibkey) ? new InsetBibKey(bibkey): 0;
1542                
1543     
1544         // copy everything behind the break-position to the new paragraph
1545
1546         result->text = text;
1547         result->fontlist = fontlist;
1548         result->insetlist = insetlist;
1549         for (InsetList::iterator it = result->insetlist.begin();
1550              it != result->insetlist.end(); ++it)
1551                 (*it).inset = (*it).inset->Clone();
1552         return result;
1553 }
1554
1555
1556 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1557 {
1558         par = par->FirstPhysicalPar();
1559
1560         return (
1561                 par->footnoteflag == footnoteflag &&
1562                 par->footnotekind == footnotekind &&
1563
1564                 par->layout == layout &&
1565
1566                 par->align == align &&
1567
1568                 par->line_bottom == line_bottom &&
1569                 par->pagebreak_bottom == pagebreak_bottom &&
1570                 par->added_space_bottom == added_space_bottom &&
1571
1572                 par->line_top == line_top &&
1573                 par->pagebreak_top == pagebreak_top &&
1574                 par->added_space_top == added_space_top &&
1575
1576                 par->spacing == spacing &&
1577                 
1578                 par->pextra_type == pextra_type &&
1579                 par->pextra_width == pextra_width && 
1580                 par->pextra_widthp == pextra_widthp && 
1581                 par->pextra_alignment == pextra_alignment && 
1582                 par->pextra_hfill == pextra_hfill && 
1583                 par->pextra_start_minipage == pextra_start_minipage && 
1584 #ifndef NEW_TABULAR
1585                 par->table == table && // what means: NO TABLE AT ALL
1586 #endif
1587
1588                 par->noindent == noindent &&
1589                 par->depth == depth);
1590 }
1591
1592
1593 void LyXParagraph::BreakParagraphConservative(BufferParams const & bparams,
1594                                               LyXParagraph::size_type pos)
1595 {
1596         // create a new paragraph
1597         LyXParagraph * par = ParFromPos(pos);
1598
1599         LyXParagraph * tmp = new LyXParagraph(par);
1600    
1601         tmp->MakeSameLayout(par);
1602
1603         // When can pos < Last()?
1604         // I guess pos == Last() is possible.
1605         if (Last() > pos) {
1606                 // copy everything behind the break-position to the new
1607                 // paragraph
1608                 size_type pos_first = 0;
1609                 while (ParFromPos(pos_first) != par)
1610                         ++pos_first;
1611                 size_type pos_end = pos_first + par->text.size() - 1;
1612
1613                 size_type i, j;
1614                 for (i = j = pos; i <= pos_end; ++i) {
1615                         par->CutIntoMinibuffer(bparams, i - pos_first);
1616                         if (tmp->InsertFromMinibuffer(j - pos))
1617                                 ++j;
1618                 }
1619                 tmp->text.resize(tmp->text.size());
1620                 for (size_type i = pos_end; i >= pos; --i)
1621                         par->Erase(i - pos_first);
1622
1623                 par->text.resize(par->text.size());
1624         }
1625 }
1626    
1627
1628 // Be carefull, this does not make any check at all.
1629 void LyXParagraph::PasteParagraph(BufferParams const & bparams)
1630 {
1631         // copy the next paragraph to this one
1632         LyXParagraph * the_next = Next();
1633    
1634         LyXParagraph * firstpar = FirstPhysicalPar();
1635    
1636         // first the DTP-stuff
1637         firstpar->line_bottom = the_next->line_bottom;
1638         firstpar->added_space_bottom = the_next->added_space_bottom;
1639         firstpar->pagebreak_bottom = the_next->pagebreak_bottom;
1640
1641         size_type pos_end = the_next->text.size() - 1;
1642         size_type pos_insert = Last();
1643
1644         // ok, now copy the paragraph
1645         size_type i, j;
1646         for (i = j = 0; i <= pos_end; ++i) {
1647                 the_next->CutIntoMinibuffer(bparams, i);
1648                 if (InsertFromMinibuffer(pos_insert + j))
1649                         ++j;
1650         }
1651    
1652         // delete the next paragraph
1653         LyXParagraph *ppar = the_next->previous;
1654         LyXParagraph *npar = the_next->next;
1655         delete the_next;
1656         ppar->next = npar;
1657 }
1658
1659
1660 void LyXParagraph::OpenFootnote(LyXParagraph::size_type pos)
1661 {
1662         LyXParagraph * par = ParFromPos(pos);
1663         par = par->next;
1664         while (par && par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1665                 par->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
1666                 par = par->next;
1667         }
1668 }
1669
1670
1671 void LyXParagraph::CloseFootnote(LyXParagraph::size_type pos)
1672 {
1673         LyXParagraph * par = ParFromPos(pos);
1674         par = par->next;
1675         while (par && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1676                 par->footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
1677                 par = par->next;
1678         }
1679 }
1680
1681 int LyXParagraph::GetEndLabel(BufferParams const & bparams) const
1682 {
1683         LyXParagraph const * par = this;
1684         int par_depth = GetDepth();
1685         while (par) {
1686                 LyXTextClass::LayoutList::size_type layout = par->GetLayout();
1687                 int endlabeltype =
1688                         textclasslist.Style(bparams.textclass,
1689                                             layout).endlabeltype;
1690                 if (endlabeltype != END_LABEL_NO_LABEL) {
1691                         LyXParagraph const * last = this;
1692                         if( footnoteflag == NO_FOOTNOTE)
1693                                 last = LastPhysicalPar();
1694                         else if (next->footnoteflag == NO_FOOTNOTE)
1695                                 return endlabeltype;
1696
1697                         if (!last || !last->next)
1698                                 return endlabeltype;
1699
1700                         int next_depth = last->next->GetDepth();
1701                         if (par_depth > next_depth ||
1702                             (par_depth == next_depth && layout != last->next->GetLayout() ))
1703                                 return endlabeltype;
1704                         break;
1705                 }
1706                 if (par_depth == 0)
1707                         break;
1708                 par = par->DepthHook(par_depth - 1);
1709                 if (par)
1710                         par_depth = par->GetDepth();
1711         }
1712         return END_LABEL_NO_LABEL;
1713 }
1714
1715
1716 LyXTextClass::size_type LyXParagraph::GetLayout() const
1717 {
1718         return FirstPhysicalPar()->layout;
1719 }
1720
1721
1722 char LyXParagraph::GetDepth() const
1723 {
1724         return FirstPhysicalPar()->depth;
1725 }
1726
1727
1728 char LyXParagraph::GetAlign() const
1729 {
1730         return FirstPhysicalPar()->align;
1731 }
1732
1733
1734 string LyXParagraph::GetLabelstring() const
1735 {
1736         return FirstPhysicalPar()->labelstring;
1737 }
1738
1739
1740 int LyXParagraph::GetFirstCounter(int i) const
1741 {
1742         return FirstPhysicalPar()->counter_[i];
1743 }
1744
1745
1746 // the next two functions are for the manual labels
1747 string LyXParagraph::GetLabelWidthString() const
1748 {
1749         if (!FirstPhysicalPar()->labelwidthstring.empty())
1750                 return FirstPhysicalPar()->labelwidthstring;
1751         else
1752                 return _("Senseless with this layout!");
1753 }
1754
1755
1756 void LyXParagraph::SetLabelWidthString(string const & s)
1757 {
1758         LyXParagraph * par = FirstPhysicalPar();
1759
1760         par->labelwidthstring = s;
1761 }
1762
1763
1764 void LyXParagraph::SetOnlyLayout(BufferParams const & bparams,
1765                                  LyXTextClass::size_type new_layout)
1766 {
1767         LyXParagraph * par = FirstPhysicalPar();
1768         LyXParagraph * ppar = 0;
1769         LyXParagraph * npar = 0;
1770
1771         par->layout = new_layout;
1772 #ifndef NEW_TABULAR
1773         /* table stuff -- begin*/ 
1774         if (table) 
1775                 par->layout = 0;
1776         /* table stuff -- end*/
1777 #endif
1778         if (par->pextra_type == PEXTRA_NONE) {
1779                 if (par->Previous()) {
1780                         ppar = par->Previous()->FirstPhysicalPar();
1781                         while(ppar
1782                               && ppar->Previous()
1783                               && (ppar->depth > par->depth))
1784                                 ppar = ppar->Previous()->FirstPhysicalPar();
1785                 }
1786                 if (par->Next()) {
1787                         npar = par->Next()->NextAfterFootnote();
1788                         while(npar
1789                               && npar->Next()
1790                               && (npar->depth > par->depth))
1791                                 npar = npar->Next()->NextAfterFootnote();
1792                 }
1793                 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
1794                         string
1795                                 p1 = ppar->pextra_width,
1796                                 p2 = ppar->pextra_widthp;
1797                         ppar->SetPExtraType(bparams, ppar->pextra_type,
1798                                             p1.c_str(), p2.c_str());
1799                 }
1800                 if ((par->pextra_type == PEXTRA_NONE) &&
1801                     npar && (npar->pextra_type != PEXTRA_NONE)) {
1802                         string
1803                                 p1 = npar->pextra_width,
1804                                 p2 = npar->pextra_widthp;
1805                         npar->SetPExtraType(bparams, npar->pextra_type,
1806                                             p1.c_str(), p2.c_str());
1807                 }
1808         }
1809 }
1810
1811
1812 void LyXParagraph::SetLayout(BufferParams const & bparams,
1813                              LyXTextClass::size_type new_layout)
1814 {
1815         LyXParagraph
1816                 * par = FirstPhysicalPar(),
1817                 * ppar = 0,
1818                 * npar = 0;
1819
1820         par->layout = new_layout;
1821         par->labelwidthstring.erase();
1822         par->align = LYX_ALIGN_LAYOUT;
1823         par->added_space_top = VSpace(VSpace::NONE);
1824         par->added_space_bottom = VSpace(VSpace::NONE);
1825         par->spacing.set(Spacing::Default);
1826
1827 #ifndef NEW_TABULAR
1828         /* table stuff -- begin*/ 
1829         if (table) 
1830                 par->layout = 0;
1831         /* table stuff -- end*/
1832 #endif
1833         if (par->pextra_type == PEXTRA_NONE) {
1834                 if (par->Previous()) {
1835                         ppar = par->Previous()->FirstPhysicalPar();
1836                         while(ppar
1837                               && ppar->Previous()
1838                               && (ppar->depth > par->depth))
1839                                 ppar = ppar->Previous()->FirstPhysicalPar();
1840                 }
1841                 if (par->Next()) {
1842                         npar = par->Next()->NextAfterFootnote();
1843                         while(npar
1844                               && npar->Next()
1845                               && (npar->depth > par->depth))
1846                                 npar = npar->Next()->NextAfterFootnote();
1847                 }
1848                 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
1849                         string
1850                                 p1 = ppar->pextra_width,
1851                                 p2 = ppar->pextra_widthp;
1852                         ppar->SetPExtraType(bparams, ppar->pextra_type,
1853                                             p1.c_str(), p2.c_str());
1854                 }
1855                 if ((par->pextra_type == PEXTRA_NONE) &&
1856                     npar && (npar->pextra_type != PEXTRA_NONE)) {
1857                         string
1858                                 p1 = npar->pextra_width,
1859                                 p2 = npar->pextra_widthp;
1860                         npar->SetPExtraType(bparams, npar->pextra_type,
1861                                             p1.c_str(), p2.c_str());
1862                 }
1863         }
1864 }
1865
1866
1867 // if the layout of a paragraph contains a manual label, the beginning of the 
1868 // main body is the beginning of the second word. This is what the par-
1869 // function returns. If the layout does not contain a label, the main
1870 // body always starts with position 0. This differentiation is necessary,
1871 // because there cannot be a newline or a blank <= the beginning of the 
1872 // main body in TeX.
1873
1874 int LyXParagraph::BeginningOfMainBody() const
1875 {
1876         if (FirstPhysicalPar() != this)
1877                 return -1;
1878    
1879         // Unroll the first two cycles of the loop
1880         // and remember the previous character to
1881         // remove unnecessary GetChar() calls
1882         size_type i = 0;
1883         if (i < size()
1884             && GetChar(i) != LyXParagraph::META_NEWLINE
1885                 ) {
1886                 ++i;
1887                 char previous_char = 0, temp = 0; 
1888                 if (i < size()
1889                     && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1890                         // Yes, this  ^ is supposed to be "= " not "=="
1891                         ++i;
1892                         while (i < size()
1893                                && previous_char != ' '
1894                                && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
1895                                 ++i;
1896                                 previous_char = temp;
1897                         }
1898                 }
1899         }
1900
1901         if (i == 0 && i == size() &&
1902             !(footnoteflag == LyXParagraph::NO_FOOTNOTE
1903               && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1904                 ++i;                           /* the cursor should not jump  
1905                                                 * to the main body if there
1906                                                 * is nothing in! */
1907         return i;
1908 }
1909
1910
1911 LyXParagraph * LyXParagraph::DepthHook(int deth)
1912 {
1913         LyXParagraph * newpar = this;
1914         if (deth < 0)
1915                 return 0;
1916    
1917         do {
1918                 newpar = newpar->FirstPhysicalPar()->Previous();
1919         } while (newpar && newpar->GetDepth() > deth
1920                  && newpar->footnoteflag == footnoteflag);
1921    
1922         if (!newpar) {
1923                 if (Previous() || GetDepth())
1924                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
1925                                 "no hook." << endl;
1926                 newpar = this;
1927         }
1928         return newpar->FirstPhysicalPar();
1929 }
1930
1931
1932 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
1933 {
1934         LyXParagraph const * newpar = this;
1935         if (deth < 0)
1936                 return 0;
1937    
1938         do {
1939                 newpar = newpar->FirstPhysicalPar()->Previous();
1940         } while (newpar && newpar->GetDepth() > deth
1941                  && newpar->footnoteflag == footnoteflag);
1942    
1943         if (!newpar) {
1944                 if (Previous() || GetDepth())
1945                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
1946                                 "no hook." << endl;
1947                 newpar = this;
1948         }
1949         return newpar->FirstPhysicalPar();
1950 }
1951
1952
1953 int LyXParagraph::AutoDeleteInsets()
1954 {
1955         int count = 0;
1956         InsetList::size_type index = 0;
1957         while (index < insetlist.size()) {
1958                 if (insetlist[index].inset && insetlist[index].inset->AutoDelete()) {
1959                         Erase(insetlist[index].pos); 
1960                         // Erase() calls to insetlist.erase(&insetlist[index])
1961                         // so index shouldn't be increased.
1962                         ++count;
1963                 } else
1964                         ++index;
1965         }
1966         return count;
1967 }
1968
1969
1970 LyXParagraph::inset_iterator LyXParagraph::InsetIterator(LyXParagraph::size_type pos)
1971 {
1972         InsetList::iterator it = lower_bound(insetlist.begin(),
1973                                              insetlist.end(),
1974                                              pos, matchIT());
1975         return inset_iterator(it);
1976 }
1977
1978
1979 // returns -1 if inset not found
1980 int LyXParagraph::GetPositionOfInset(Inset * inset) const
1981 {
1982         // Find the entry.
1983         // We could use lower_bound here too, we just need to add
1984         // the approp. operator() to matchIT (and change the name
1985         // of that struct). Code would then be:
1986         // InsetList::const_iterator cit = lower_bound(insetlist.begin(),
1987         //                                             insetlist.end(),
1988         //                                             inset, matchIT());
1989         // if ((*cit).inset == inset) {
1990         //         return (*cit).pos;
1991         // }
1992         for (InsetList::const_iterator cit = insetlist.begin();
1993              cit != insetlist.end(); ++cit) {
1994                 if ((*cit).inset == inset) {
1995                         return (*cit).pos;
1996                 }
1997         }
1998         // Think about footnotes.
1999         if (footnoteflag == LyXParagraph::NO_FOOTNOTE 
2000             && next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2001                 int further = 
2002                         NextAfterFootnote()->GetPositionOfInset(inset);
2003                 if (further != -1)
2004                         return text.size() + 1 + further;
2005         }
2006         return -1;
2007 }
2008
2009
2010 LyXParagraph * LyXParagraph::TeXOnePar(BufferParams const & bparams,
2011                                        ostream & os, TexRow & texrow,
2012                                        bool moving_arg, 
2013                                        ostream & foot,
2014                                        TexRow & foot_texrow,
2015                                        int & foot_count)
2016 {
2017         lyxerr[Debug::LATEX] << "TeXOnePar...     " << this << endl;
2018         LyXLayout const & style =
2019                 textclasslist.Style(bparams.textclass,
2020                                     layout);
2021
2022         bool further_blank_line = false;
2023         if (IsDummy())
2024                 lyxerr << "ERROR (LyXParagraph::TeXOnePar) is dummy." << endl;
2025
2026         if (start_of_appendix) {
2027                 os << "\\appendix\n";
2028                 texrow.newline();
2029         }
2030
2031         if (!spacing.isDefault()
2032             && (!Previous() || !Previous()->HasSameLayout(this))) {
2033                 os << spacing.writeEnvirBegin() << "\n";
2034                 texrow.newline();
2035         }
2036         
2037         if (tex_code_break_column && style.isCommand()){
2038                 os << '\n';
2039                 texrow.newline();
2040         }
2041
2042         if (pagebreak_top) {
2043                 os << "\\newpage";
2044                 further_blank_line = true;
2045         }
2046         if (added_space_top.kind() != VSpace::NONE) {
2047                 os << added_space_top.asLatexCommand(bparams);
2048                 further_blank_line = true;
2049         }
2050       
2051         if (line_top) {
2052                 os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
2053                    << "\\vspace{-1\\parskip}";
2054                 further_blank_line = true;
2055         }
2056
2057         if (further_blank_line){
2058                 os << '\n';
2059                 texrow.newline();
2060         }
2061
2062         Language const * language = getParLanguage(bparams);
2063         Language const * doc_language = bparams.language_info;
2064         if (language != doc_language &&
2065             (!previous || previous->getParLanguage(bparams) != language)) {
2066                 os << subst(lyxrc.language_command_begin, "$$lang",
2067                             language->lang())
2068                    << endl;
2069                 texrow.newline();
2070         }
2071         
2072         switch (style.latextype) {
2073         case LATEX_COMMAND:
2074                 os << '\\'
2075                    << style.latexname()
2076                    << style.latexparam();
2077                 break;
2078         case LATEX_ITEM_ENVIRONMENT:
2079                 if (bibkey) {
2080                         bibkey->Latex(os, false, false);
2081                 } else
2082                         os << "\\item ";
2083                 break;
2084         case LATEX_LIST_ENVIRONMENT:
2085                 os << "\\item ";
2086                 break;
2087         default:
2088                 break;
2089         }
2090
2091         bool need_par = SimpleTeXOnePar(bparams, os, texrow, moving_arg);
2092  
2093         // Spit out footnotes
2094         LyXParagraph * par = next;
2095         if (lyxrc.rtl_support) {
2096                 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2097                     && next->footnoteflag != footnoteflag) {
2098                         LyXParagraph * p = 0;
2099                         bool is_rtl = (size() > 0) 
2100                                 ? GetFontSettings(bparams,
2101                                                   size()-1).isRightToLeft()
2102                                 : language->RightToLeft();
2103                         if ( (p = NextAfterFootnote()) != 0 &&
2104                              p->size() > 0 &&
2105                              p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2106                                 is_rtl = getParLanguage(bparams)->RightToLeft();
2107                         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2108                                && par->footnoteflag != footnoteflag) {
2109                                 par = par->TeXFootnote(bparams,
2110                                                        os, texrow, foot,
2111                                                        foot_texrow, foot_count,
2112                                                        is_rtl);
2113                                 par->SimpleTeXOnePar(bparams,
2114                                                      os, texrow, moving_arg);
2115                                 is_rtl = (par->size() > 0)
2116                                         ? par->GetFontSettings(bparams,
2117                                                                par->size()-1).isRightToLeft()
2118                                         : language->RightToLeft();
2119                                 if (par->next &&
2120                                     par->next->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2121                                     (p = par->NextAfterFootnote()) != 0 &&
2122                                     p->size() > 0 &&
2123                                     p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2124                                         is_rtl = language->RightToLeft();
2125                                 par = par->next;
2126                         }
2127                 }
2128         } else {
2129                 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2130                        && par->footnoteflag != footnoteflag) {
2131                         par = par->TeXFootnote(bparams,
2132                                                os, texrow,
2133                                                foot, foot_texrow, foot_count,
2134                                                false);
2135                         par->SimpleTeXOnePar(bparams, os, texrow, moving_arg);
2136                         par = par->next;
2137                 }
2138         }
2139
2140         // Make sure that \\par is done with the font of the last
2141         // character if this has another size as the default.
2142         // This is necessary because LaTeX (and LyX on the screen)
2143         // calculates the space between the baselines according
2144         // to this font. (Matthias)
2145         LyXFont font = getFont(bparams, Last() - 1);
2146         if (need_par) {
2147                 if (style.resfont.size() != font.size()) {
2148                         os << '\\'
2149                            << font.latexSize()
2150                            << ' ';
2151                 }
2152                 os << "\\par}";
2153         } else if (textclasslist.Style(bparams.textclass,
2154                                        GetLayout()).isCommand()) {
2155                 if (style.resfont.size() != font.size()) {
2156                         os << '\\'
2157                            << font.latexSize()
2158                            << ' ';
2159                 }
2160                 os << '}';
2161         } else if (style.resfont.size() != font.size()){
2162                 os << "{\\" << font.latexSize() << " \\par}";
2163         }
2164
2165         if (language != doc_language &&
2166             (!par
2167              || (footnoteflag != NO_FOOTNOTE && par->footnoteflag != footnoteflag)
2168              || par->getParLanguage(bparams) != language)) {
2169                 os << endl 
2170                    << subst(lyxrc.language_command_end, "$$lang",
2171                             doc_language->lang());
2172         }
2173         
2174         switch (style.latextype) {
2175         case LATEX_ITEM_ENVIRONMENT:
2176         case LATEX_LIST_ENVIRONMENT:
2177                 if (par && (depth < par->depth)) {
2178                         os << '\n';
2179                         texrow.newline();
2180                 }
2181                 break;
2182         case LATEX_ENVIRONMENT:
2183                 // if its the last paragraph of the current environment
2184                 // skip it otherwise fall through
2185                 if (par
2186                     && (par->layout != layout
2187                         || par->depth != depth
2188                         || par->pextra_type != pextra_type))
2189                         break;
2190         default:
2191                 // we don't need it for the last paragraph!!!
2192                 if (next && !(footnoteflag != LyXParagraph::NO_FOOTNOTE
2193                       && footnotekind != LyXParagraph::FOOTNOTE
2194                       && footnotekind != LyXParagraph::MARGIN
2195                       && (table
2196                           || (par
2197                               && par->table)))) {
2198                         // don't insert this if we would be adding it
2199                         // before or after a table in a float.  This 
2200                         // little trick is needed in order to allow
2201                         // use of tables in \subfigures or \subtables.
2202                         os << '\n';
2203                         texrow.newline();
2204                 }
2205         }
2206         
2207         further_blank_line = false;
2208         if (line_bottom) {
2209                 os << "\\lyxline{\\" << getFont(bparams, Last() - 1).latexSize() << '}';
2210                 further_blank_line = true;
2211         }
2212
2213         if (added_space_bottom.kind() != VSpace::NONE) {
2214                 os << added_space_bottom.asLatexCommand(bparams);
2215                 further_blank_line = true;
2216         }
2217       
2218         if (pagebreak_bottom) {
2219                 os << "\\newpage";
2220                 further_blank_line = true;
2221         }
2222
2223         if (further_blank_line){
2224                 os << '\n';
2225                 texrow.newline();
2226         }
2227
2228         if (!spacing.isDefault()
2229             && (!par || !par->HasSameLayout(this))) {
2230                 os << spacing.writeEnvirEnd() << "\n";
2231                 texrow.newline();
2232         }
2233         
2234         // we don't need it for the last paragraph!!!
2235         if (next && !(footnoteflag != LyXParagraph::NO_FOOTNOTE && par &&
2236               par->footnoteflag == LyXParagraph::NO_FOOTNOTE)) {
2237                 os << '\n';
2238                 texrow.newline();
2239         }
2240
2241         lyxerr[Debug::LATEX] << "TeXOnePar...done " << par << endl;
2242         return par;
2243 }
2244
2245
2246 // This one spits out the text of the paragraph
2247 bool LyXParagraph::SimpleTeXOnePar(BufferParams const & bparams,
2248                                    ostream & os, TexRow & texrow,
2249                                    bool moving_arg)
2250 {
2251         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...     " << this << endl;
2252
2253 #ifndef NEW_TABULAR
2254         if (table)
2255                 return SimpleTeXOneTablePar(bparams, os, texrow);
2256 #endif
2257
2258         bool return_value = false;
2259
2260         LyXLayout const & style =
2261                 textclasslist.Style(bparams.textclass,
2262                                     GetLayout());
2263         LyXFont basefont, last_font;
2264
2265         // Maybe we have to create a optional argument.
2266         size_type main_body;
2267         if (style.labeltype != LABEL_MANUAL)
2268                 main_body = 0;
2269         else
2270                 main_body = BeginningOfMainBody();
2271
2272         if (main_body > 0) {
2273                 os << '[';
2274                 basefont = getFont(bparams, -2); // Get label font
2275         } else {
2276                 basefont = getFont(bparams, -1); // Get layout font
2277         }
2278
2279         int column = 0;
2280
2281         if (main_body >= 0
2282             && !text.size()
2283             && !IsDummy()) {
2284                 if (style.isCommand()) {
2285                         os << '{';
2286                         ++column;
2287                 } else if (align != LYX_ALIGN_LAYOUT) {
2288                         os << '{';
2289                         ++column;
2290                         return_value = true;
2291                 }
2292         }
2293
2294         moving_arg |= style.needprotect;
2295  
2296         // Which font is currently active?
2297         LyXFont running_font(basefont);
2298         // Do we have an open font change?
2299         bool open_font = false;
2300
2301         texrow.start(this, 0);
2302
2303         for (size_type i = 0; i < size(); ++i) {
2304                 ++column;
2305                 // First char in paragraph or after label?
2306                 if (i == main_body && !IsDummy()) {
2307                         if (main_body > 0) {
2308                                 if (open_font) {
2309                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
2310                                         open_font = false;
2311                                 }
2312                                 basefont = getFont(bparams, -1); // Now use the layout font
2313                                 running_font = basefont;
2314                                 os << ']';
2315                                 ++column;
2316                         }
2317                         if (style.isCommand()) {
2318                                 os << '{';
2319                                 ++column;
2320                         } else if (align != LYX_ALIGN_LAYOUT) {
2321                                 os << "{\\par";
2322                                 column += 4;
2323                                 return_value = true;
2324                         }
2325
2326                         if (noindent) {
2327                                 os << "\\noindent ";
2328                                 column += 10;
2329                         }
2330                         switch (align) {
2331                         case LYX_ALIGN_NONE:
2332                         case LYX_ALIGN_BLOCK:
2333                         case LYX_ALIGN_LAYOUT:
2334                         case LYX_ALIGN_SPECIAL:
2335                                 break;
2336                         case LYX_ALIGN_LEFT:
2337                                 if (getParLanguage(bparams)->lang() != "hebrew") {
2338                                         os << "\\raggedright ";
2339                                         column+= 13;
2340                                 } else {
2341                                         os << "\\raggedleft ";
2342                                         column+= 12;
2343                                 }
2344                                 break;
2345                         case LYX_ALIGN_RIGHT:
2346                                 if (getParLanguage(bparams)->lang() != "hebrew") {
2347                                         os << "\\raggedleft ";
2348                                         column+= 12;
2349                                 } else {
2350                                         os << "\\raggedright ";
2351                                         column+= 13;
2352                                 }
2353                                 break;
2354                         case LYX_ALIGN_CENTER:
2355                                 os << "\\centering ";
2356                                 column+= 11;
2357                                 break;
2358                         }        
2359                 }
2360
2361                 int c = GetChar(i);
2362
2363                 // Fully instantiated font
2364                 LyXFont font = getFont(bparams, i);
2365                 LyXParagraph * p = 0;
2366                 if (i == 0 && previous && 
2367                     previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2368                     (p = PreviousBeforeFootnote()) != 0)
2369                         last_font = p->getFont(bparams, p->size()-1);
2370                 else
2371                         last_font = running_font;
2372
2373                 // Spaces at end of font change are simulated to be
2374                 // outside font change, i.e. we write "\textXX{text} "
2375                 // rather than "\textXX{text }". (Asger)
2376                 if (open_font && c == ' ' && i <= size() - 2 
2377                     && !getFont(bparams, i + 1).equalExceptLatex(running_font) 
2378                     && !getFont(bparams, i + 1).equalExceptLatex(font)) {
2379                         font = getFont(bparams, i + 1);
2380                 }
2381                 // We end font definition before blanks
2382                 if (!font.equalExceptLatex(running_font) && open_font) {
2383                         column += running_font.latexWriteEndChanges(os,
2384                                                                     basefont,
2385                                                                     (i == main_body-1) ? basefont : font);
2386                         running_font = basefont;
2387                         open_font = false;
2388                 }
2389
2390                 // Blanks are printed before start of fontswitch
2391                 if (c == ' ') {
2392                         // Do not print the separation of the optional argument
2393                         if (i != main_body - 1) {
2394                                 SimpleTeXBlanks(os, texrow, i,
2395                                                 column, font, style);
2396                         }
2397                 }
2398
2399                 // Do we need to change font?
2400                 if (!font.equalExceptLatex(running_font)
2401                     && i != main_body-1) {
2402                         column += font.latexWriteStartChanges(os, basefont,
2403                                                               last_font);
2404                         running_font = font;
2405                         open_font = true;
2406                 }
2407
2408                 if (c == LyXParagraph::META_NEWLINE) {
2409                         // newlines are handled differently here than
2410                         // the default in SimpleTeXSpecialChars().
2411                         if (!style.newline_allowed
2412                             || font.latex() == LyXFont::ON) {
2413                                 os << '\n';
2414                         } else {
2415                                 if (open_font) {
2416                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
2417                                         open_font = false;
2418                                 }
2419                                 basefont = getFont(bparams, -1);
2420                                 running_font = basefont;
2421                                 if (font.family() == 
2422                                     LyXFont::TYPEWRITER_FAMILY) {
2423                                         os << "~";
2424                                 }
2425                                 if (moving_arg)
2426                                         os << "\\protect ";
2427                                 os << "\\\\\n";
2428                         }
2429                         texrow.newline();
2430                         texrow.start(this, i + 1);
2431                         column = 0;
2432                 } else {
2433                         SimpleTeXSpecialChars(bparams,
2434                                               os, texrow, moving_arg,
2435                                               font, running_font, basefont,
2436                                               open_font, style, i, column, c);
2437                 }
2438         }
2439
2440         // If we have an open font definition, we have to close it
2441         if (open_font) {
2442                 LyXParagraph * p = 0;
2443                 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2444                     && (p =  NextAfterFootnote()) != 0)
2445                         running_font.latexWriteEndChanges(os, basefont,
2446                                                           p->getFont(bparams, 0));
2447                 else
2448                         running_font.latexWriteEndChanges(os, basefont, basefont);
2449         }
2450
2451         // Needed if there is an optional argument but no contents.
2452         if (main_body > 0 && main_body == size()) {
2453                 os << "]~";
2454                 return_value = false;
2455         }
2456
2457         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
2458         return return_value;
2459 }
2460
2461
2462 // This one spits out the text of a table paragraph
2463 bool LyXParagraph::SimpleTeXOneTablePar(BufferParams const & bparams,
2464                                         ostream & os, TexRow & texrow)
2465 {
2466         lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar...     " << this << endl;
2467    
2468         bool return_value = false;
2469
2470         LyXLayout const & style = 
2471                 textclasslist.Style(bparams.textclass, GetLayout());
2472  
2473         int column = 0;
2474         if (!IsDummy()) { // it is dummy if it is in a float!!!
2475                 if (style.isCommand()) {
2476                         os << '{';
2477                         ++column;
2478                 } else if (align != LYX_ALIGN_LAYOUT) {
2479                         os << '{';
2480                         ++column;
2481                         return_value = true;
2482                 }
2483                 if (noindent) {
2484                         os << "\\noindent ";
2485                         column += 10;
2486                 }
2487                 switch (align) {
2488                 case LYX_ALIGN_NONE:
2489                 case LYX_ALIGN_BLOCK:
2490                 case LYX_ALIGN_LAYOUT:
2491                 case LYX_ALIGN_SPECIAL: break;
2492                 case LYX_ALIGN_LEFT:
2493                         os << "\\raggedright ";
2494                         column+= 13;
2495                         break;
2496                 case LYX_ALIGN_RIGHT:
2497                         os << "\\raggedleft ";
2498                         column+= 12;
2499                         break;
2500                 case LYX_ALIGN_CENTER:
2501                         os << "\\centering ";
2502                         column+= 11;
2503                         break;
2504                 }
2505         }
2506
2507         LyXFont basefont = getFont(bparams, -1); // Get layout font
2508         // Which font is currently active?
2509         LyXFont running_font = basefont;
2510         LyXFont last_font;
2511         // Do we have an open font change?
2512         bool open_font = false;
2513         int current_cell_number = -1;
2514         int tmp = table->TexEndOfCell(os, current_cell_number);
2515         for (; tmp > 0 ; --tmp)
2516                 texrow.newline();
2517         
2518         texrow.start(this, 0);
2519
2520         bool is_rtl = getParLanguage(bparams)->RightToLeft();
2521         bool first_in_cell = true;
2522                 
2523         for (size_type i = 0; i < size(); ++i) {
2524                 char c = GetChar(i);
2525                 if (table->IsContRow(current_cell_number + 1)) {
2526                         if (c == LyXParagraph::META_NEWLINE)
2527                                 ++current_cell_number;
2528                         continue;
2529                 }
2530                 ++column;
2531
2532                 if (first_in_cell && is_rtl) {
2533                         os << "\\R{";
2534                         column += 3;
2535                         first_in_cell = false;
2536                 }
2537
2538                 // Fully instantiated font
2539                 LyXFont font = getFont(bparams, i);
2540                 last_font = running_font;
2541
2542                 // Spaces at end of font change are simulated to be
2543                 // outside font change.
2544                 // i.e. we write "\textXX{text} " rather than
2545                 // "\textXX{text }". (Asger)
2546                 if (open_font && c == ' ' && i <= size() - 2
2547                     && getFont(bparams, i + 1) != running_font
2548                     && getFont(bparams, i + 1) != font) {
2549                         font = getFont(bparams, i + 1);
2550                 }
2551
2552                 // We end font definition before blanks
2553                 if (font != running_font && open_font) {
2554                         column += running_font.latexWriteEndChanges(os,
2555                                                                     basefont,
2556                                                                     font);
2557                         running_font = basefont;
2558                         open_font = false;
2559                 }
2560                 // Blanks are printed before start of fontswitch
2561                 if (c == ' '){
2562                         SimpleTeXBlanks(os, texrow, i, column, font, style);
2563                 }
2564                 // Do we need to change font?
2565                 if (font != running_font) {
2566                         column += font.latexWriteStartChanges(os, basefont,
2567                                                               last_font);
2568                         running_font = font;
2569                         open_font = true;
2570                 }
2571                 // Do we need to turn on LaTeX mode?
2572                 if (font.latex() != running_font.latex()) {
2573                         if (font.latex() == LyXFont::ON
2574                             && style.needprotect) {
2575                                 os << "\\protect ";
2576                                 column += 9;
2577                         }
2578                 }
2579                 if (c == LyXParagraph::META_NEWLINE) {
2580                         // special case for inside a table
2581                         // different from default case in
2582                         // SimpleTeXSpecialChars()
2583                         if (open_font) {
2584                                 column += running_font
2585                                         .latexWriteEndChanges(os, basefont,
2586                                                               basefont);
2587                                 open_font = false;
2588                         }
2589                         basefont = getFont(bparams, -1);
2590                         running_font = basefont;
2591                         ++current_cell_number;
2592                         if (table->CellHasContRow(current_cell_number) >= 0) {
2593                                 TeXContTableRows(bparams, os, i + 1,
2594                                                  current_cell_number,
2595                                                  column, texrow);
2596                         }
2597                         if (is_rtl && !first_in_cell) {
2598                                 os << "}";
2599                                 first_in_cell = true;
2600                         }
2601
2602                         // if this cell follow only ContRows till end don't
2603                         // put the EndOfCell because it is put after the
2604                         // for(...)
2605                         if (table->ShouldBeVeryLastCell(current_cell_number)) {
2606                                 --current_cell_number;
2607                                 break;
2608                         }
2609                         int tmp = table->TexEndOfCell(os,
2610                                                       current_cell_number);
2611                         if (tmp > 0) {
2612                                 column = 0;
2613                         } else if (tmp < 0) {
2614                                 tmp = -tmp;
2615                         }
2616                         for (; tmp--;) {
2617                                 texrow.newline();
2618                         }
2619                         texrow.start(this, i + 1);
2620                 } else {
2621                         SimpleTeXSpecialChars(bparams,
2622                                               os, texrow, false,
2623                                               font, running_font, basefont,
2624                                               open_font, style, i, column, c);
2625                 }
2626         }
2627
2628         // If we have an open font definition, we have to close it
2629         if (open_font) {
2630                 running_font.latexWriteEndChanges(os, basefont, basefont);
2631         }
2632         ++current_cell_number;
2633         if (is_rtl && !first_in_cell)
2634                 os << "}";
2635         tmp = table->TexEndOfCell(os, current_cell_number);
2636         for (; tmp > 0; --tmp)
2637                 texrow.newline();
2638         lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar...done " << this << endl;
2639         return return_value;
2640 }
2641
2642
2643 // This one spits out the text off ContRows in tables
2644 bool LyXParagraph::TeXContTableRows(BufferParams const & bparams,
2645                                     ostream & os,
2646                                     LyXParagraph::size_type i,
2647                                     int current_cell_number,
2648                                     int & column, TexRow & texrow)
2649 {
2650         lyxerr[Debug::LATEX] << "TeXContTableRows...     " << this << endl;
2651         if (!table)
2652                 return false;
2653     
2654         bool return_value = false;
2655         LyXLayout const & style =
2656                 textclasslist.Style(bparams.textclass,
2657                                     GetLayout());
2658         LyXFont basefont = getFont(bparams, -1); // Get layout font
2659         LyXFont last_font;
2660         // Which font is currently active?
2661         LyXFont running_font = basefont;
2662         // Do we have an open font change?
2663         bool open_font = false;
2664
2665         size_type lastpos = i;
2666         int cell = table->CellHasContRow(current_cell_number);
2667         ++current_cell_number;
2668         char c;
2669         while(cell >= 0) {
2670                 // first find the right position
2671                 i = lastpos;
2672                 for (; (i < size()) && (current_cell_number<cell); ++i) {
2673                         c = GetChar(i);
2674                         if (c == LyXParagraph::META_NEWLINE)
2675                                 ++current_cell_number;
2676                 }
2677                 lastpos = i;
2678                 c = GetChar(i);
2679                 if (table->Linebreaks(table->FirstVirtualCell(cell))) {
2680                         os << " \\\\\n";
2681                         texrow.newline();
2682                         column = 0;
2683                 } else if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
2684                         os << ' ';
2685                 }
2686
2687                 for (; i < size()
2688                              && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
2689                      ++i) {
2690                         ++column;
2691
2692                         // Fully instantiated font
2693                         LyXFont font = getFont(bparams, i);
2694                         last_font = running_font;
2695
2696                         // Spaces at end of font change are simulated to
2697                         // be outside font change. i.e. we write
2698                         // "\textXX{text} " rather than "\textXX{text }".
2699                         // (Asger)
2700                         if (open_font && c == ' ' && i <= size() - 2 
2701                             && getFont(bparams, i + 1) != running_font
2702                             && getFont(bparams, i + 1) != font) {
2703                                 font = getFont(bparams, i + 1);
2704                         }
2705
2706                         // We end font definition before blanks
2707                         if (font != running_font && open_font) {
2708                                 column += running_font.latexWriteEndChanges(os, basefont, font);
2709                                 running_font = basefont;
2710                                 open_font = false;
2711                         }
2712                         // Blanks are printed before start of fontswitch
2713                         if (c == ' '){
2714                                 SimpleTeXBlanks(os, texrow, i,
2715                                                 column, font, style);
2716                         }
2717                         // Do we need to change font?
2718                         if (font != running_font) {
2719                                 column +=
2720                                         font.latexWriteStartChanges(os,
2721                                                                     basefont,
2722                                                                     last_font);
2723                                 running_font = font;
2724                                 open_font = true;
2725                         }
2726                         // Do we need to turn on LaTeX mode?
2727                         if (font.latex() != running_font.latex()) {
2728                                 if (font.latex() == LyXFont::ON
2729                                     && style.needprotect) {
2730                                         os << "\\protect ";
2731                                         column += 9;
2732                                 }
2733                         }
2734                         SimpleTeXSpecialChars(bparams,
2735                                               os, texrow, false, font,
2736                                               running_font, basefont,
2737                                               open_font, style, i, column, c);
2738                 }
2739                 // If we have an open font definition, we have to close it
2740                 if (open_font) {
2741                         running_font.latexWriteEndChanges(os, basefont,
2742                                                           basefont);
2743                         open_font = false;
2744                 }
2745                 basefont = getFont(bparams, -1);
2746                 running_font = basefont;
2747                 cell = table->CellHasContRow(current_cell_number);
2748         }
2749         lyxerr[Debug::LATEX] << "TeXContTableRows...done " << this << endl;
2750         return return_value;
2751 }
2752
2753
2754 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
2755 {
2756         bool retval = false;
2757         switch (c) {
2758         case LyXParagraph::META_HFILL:
2759                 sgml_string.erase();
2760                 break;
2761         case LyXParagraph::META_NEWLINE:
2762                 sgml_string = '\n';
2763                 break;
2764         case '&': 
2765                 sgml_string = "&amp;";
2766                 break;
2767         case '<': 
2768                 sgml_string = "&lt;"; 
2769                 break;
2770         case '>':
2771                 sgml_string = "&gt;"; 
2772                 break;
2773         case '$': 
2774                 sgml_string = "&dollar;"; 
2775                 break;
2776         case '#': 
2777                 sgml_string = "&num;";
2778                 break;
2779         case '%': 
2780                 sgml_string = "&percnt;";
2781                 break;
2782         case '[': 
2783                 sgml_string = "&lsqb;";
2784                 break;
2785         case ']': 
2786                 sgml_string = "&rsqb;";
2787                 break;
2788         case '{': 
2789                 sgml_string = "&lcub;";
2790                 break;
2791         case '}': 
2792                 sgml_string = "&rcub;";
2793                 break;
2794         case '~': 
2795                 sgml_string = "&tilde;";
2796                 break;
2797         case '"': 
2798                 sgml_string = "&quot;";
2799                 break;
2800         case '\\': 
2801                 sgml_string = "&bsol;";
2802                 break;
2803         case ' ':
2804                 retval = true;
2805                 sgml_string = ' ';
2806                 break;
2807         case '\0': // Ignore :-)
2808                 sgml_string.erase();
2809                 break;
2810         default:
2811                 sgml_string = c;
2812                 break;
2813         }
2814         return retval;
2815 }
2816
2817
2818 void LyXParagraph::SimpleDocBookOneTablePar(BufferParams const & bparams,
2819                                             ostream & os, string & extra,
2820                                             int & desc_on, int depth) 
2821 {
2822         if (!table) return;
2823         lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar... " << this << endl;
2824         int column = 0;
2825         LyXFont font1, font2;
2826         char c;
2827         Inset * inset;
2828         size_type main_body;
2829         bool emph_flag = false;
2830         
2831         LyXLayout const & style =
2832                 textclasslist.Style(bparams.textclass,
2833                                     GetLayout());
2834         
2835         if (style.labeltype != LABEL_MANUAL)
2836                 main_body = 0;
2837         else
2838                 main_body = BeginningOfMainBody();
2839         
2840         // Gets paragraph main font.
2841         if (main_body > 0)
2842                 font1 = style.labelfont;
2843         else
2844                 font1 = style.font;
2845         
2846         int char_line_count = depth;
2847         os << newlineAndDepth(depth);
2848         if (footnoteflag == LyXParagraph::NO_FOOTNOTE) {
2849                 os << "<INFORMALTABLE>"
2850                    << newlineAndDepth(++depth);
2851         }
2852         int current_cell_number = -1;
2853         int tmp = table->DocBookEndOfCell(os, current_cell_number, depth);
2854         
2855         // Parsing main loop.
2856         for (size_type i = 0; i < size(); ++i) {
2857                 c = GetChar(i);
2858                 if (table->IsContRow(current_cell_number+1)) {
2859                         if (c == LyXParagraph::META_NEWLINE)
2860                                 ++current_cell_number;
2861                         continue;
2862                 }
2863                 ++column;
2864                 
2865                 // Fully instantiated font
2866                 font2 = getFont(bparams, i);
2867                 
2868                 // Handle <emphasis> tag.
2869                 if (font1.emph() != font2.emph() && i) {
2870                         if (font2.emph() == LyXFont::ON) {
2871                                 os << "<emphasis>";
2872                                 emph_flag= true;
2873                         } else if (emph_flag) {
2874                                 os << "</emphasis>";
2875                                 emph_flag= false;
2876                         }
2877                 }
2878                 if (c == LyXParagraph::META_NEWLINE) {
2879                         // We have only to control for emphasis open here!
2880                         if (emph_flag) {
2881                                 os << "</emphasis>";
2882                                 emph_flag= false;
2883                         }
2884                         font1 = font2 = getFont(bparams, -1);
2885                         ++current_cell_number;
2886                         if (table->CellHasContRow(current_cell_number) >= 0) {
2887                                 DocBookContTableRows(bparams,
2888                                                      os, extra, desc_on, i + 1,
2889                                                      current_cell_number,
2890                                                      column);
2891                         }
2892                         // if this cell follow only ContRows till end don't
2893                         // put the EndOfCell because it is put after the
2894                         // for(...)
2895                         if (table->ShouldBeVeryLastCell(current_cell_number)) {
2896                                 --current_cell_number;
2897                                 break;
2898                         }
2899                         tmp = table->DocBookEndOfCell(os,
2900                                                       current_cell_number,
2901                                                       depth);
2902                         
2903                         if (tmp > 0)
2904                                 column = 0;
2905                 } else if (c == LyXParagraph::META_INSET) {
2906                         inset = GetInset(i);
2907 #ifdef HAVE_SSTREAM
2908                         std::ostringstream ost;
2909                         inset->DocBook(ost);
2910                         string tmp_out = ost.str().c_str();
2911 #else
2912                         ostrstream ost;
2913                         inset->DocBook(ost);
2914                         ost << '\0';
2915                         char * ctmp = ost.str();
2916                         string tmp_out(ctmp);
2917                         delete [] ctmp;
2918 #endif
2919                         //
2920                         // This code needs some explanation:
2921                         // Two insets are treated specially
2922                         //   label if it is the first element in a
2923                         //   command paragraph
2924                         //         desc_on == 3
2925                         //   graphics inside tables or figure floats
2926                         //   can't go on
2927                         //   title (the equivalente in latex for this
2928                         //   case is caption
2929                         //   and title should come first
2930                         //         desc_on == 4
2931                         //
2932                         if(desc_on != 3 || i != 0) {
2933                                 if(tmp_out[0] == '@') {
2934                                         if(desc_on == 4)
2935                                                 extra += frontStrip(tmp_out,
2936                                                                     '@');
2937                                         else
2938                                                 os << frontStrip(tmp_out,
2939                                                                  '@');
2940                                 } else
2941                                         os << tmp_out;
2942                         }
2943                 } else if (font2.latex() == LyXFont::ON) {
2944                         // "TeX"-Mode on == > SGML-Mode on.
2945                         if (c != '\0')
2946                                 os << c;
2947                         ++char_line_count;
2948                 } else {
2949                         string sgml_string;
2950                         if (linuxDocConvertChar(c, sgml_string) 
2951                             && !style.free_spacing) {
2952                                 // in freespacing mode, spaces are
2953                                 // non-breaking characters
2954                                 // char is ' '
2955                                 if (desc_on == 1) {
2956                                         ++char_line_count;
2957                                         os << '\n'
2958                                            << "</term><listitem><para>";
2959                                         desc_on = 2;
2960                                 } else  {
2961                                         os << c;
2962                                 }
2963                         } else {
2964                                 os << sgml_string;
2965                         }
2966                 }
2967                 font1 = font2;
2968         }
2969         
2970         // Needed if there is an optional argument but no contents.
2971         if (main_body > 0 && main_body == size()) {
2972                 font1 = style.font;
2973         }
2974
2975         if (emph_flag) {
2976                 os << "</emphasis>";
2977         }
2978         
2979         ++current_cell_number;
2980         tmp = table->DocBookEndOfCell(os, current_cell_number, depth);
2981         // Resets description flag correctly.
2982         switch(desc_on){
2983         case 1:
2984                 // <term> not closed...
2985                 os << "</term>";
2986                 break;
2987         }
2988         if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
2989                 os << "</INFORMALTABLE>";
2990         os << '\n';
2991         lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar...done "
2992                              << this << endl;
2993 }
2994
2995
2996 void LyXParagraph::DocBookContTableRows(BufferParams const & bparams,
2997                                         ostream & os, string & extra,
2998                                         int & desc_on,
2999                                         LyXParagraph::size_type i,
3000                                         int current_cell_number, int &column) 
3001
3002 {
3003         if (!table) return;
3004         
3005         lyxerr[Debug::LATEX] << "DocBookContTableRows... " << this << endl;
3006
3007         LyXFont font2;
3008         char c;
3009         Inset * inset;
3010         //string emph = "emphasis";
3011         bool emph_flag = false;
3012         int char_line_count = 0;
3013         
3014         LyXLayout const & style =
3015                 textclasslist.Style(bparams.textclass,
3016                                     GetLayout());
3017         
3018         size_type main_body;
3019         if (style.labeltype != LABEL_MANUAL)
3020                 main_body = 0;
3021         else
3022                 main_body = BeginningOfMainBody();
3023         
3024         // Gets paragraph main font.
3025         LyXFont font1;
3026         if (main_body > 0)
3027                 font1 = style.labelfont;
3028         else
3029                 font1 = style.font;
3030         
3031         size_type lastpos = i;
3032         int cell = table->CellHasContRow(current_cell_number);
3033         ++current_cell_number;
3034         while(cell >= 0) {
3035                 // first find the right position
3036                 i = lastpos;
3037                 for (; i < size() && current_cell_number < cell; ++i) {
3038                         c = GetChar(i);
3039                         if (c == LyXParagraph::META_NEWLINE)
3040                                 ++current_cell_number;
3041                 }
3042                 lastpos = i;
3043                 c = GetChar(i);
3044                 // I don't know how to handle this so I comment it
3045                 // for the moment (Jug)
3046 //             if (table->Linebreaks(table->FirstVirtualCell(cell))) {
3047 //                     file += " \\\\\n";
3048 //                     column = 0;
3049 //             } else
3050                 if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
3051                         os << ' ';
3052                 }
3053
3054                 for (; i < size()
3055                              && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
3056                      ++i) {
3057                         ++column;
3058                         
3059                         // Fully instantiated font
3060                         font2 = getFont(bparams, i);
3061                         
3062                         // Handle <emphasis> tag.
3063                         if (font1.emph() != font2.emph() && i) {
3064                                 if (font2.emph() == LyXFont::ON) {
3065                                         os << "<emphasis>";
3066                                         emph_flag= true;
3067                                 } else if (emph_flag) {
3068                                         os << "</emphasis>";
3069                                         emph_flag= false;
3070                                 }
3071                         }
3072                         if (c == LyXParagraph::META_INSET) {
3073                                 inset = GetInset(i);
3074 #ifdef HAVE_SSTREAM
3075                                 std::ostringstream ost;
3076                                 inset->DocBook(ost);
3077                                 string tmp_out = ost.str().c_str();
3078 #else
3079                                 ostrstream ost;
3080                                 inset->DocBook(ost);
3081                                 ost << '\0';
3082                                 char * ctmp = ost.str();
3083                                 string tmp_out(ctmp);
3084                                 delete [] ctmp;
3085 #endif
3086                                 //
3087                                 // This code needs some explanation:
3088                                 // Two insets are treated specially
3089                                 //   label if it is the first element in a
3090                                 //   command paragraph
3091                                 //       desc_on == 3
3092                                 //   graphics inside tables or figure floats
3093                                 //   can't go on title (the equivalente in
3094                                 //   latex for this case is caption and title
3095                                 //   should come first
3096                                 //       desc_on == 4
3097                                 //
3098                                 if(desc_on != 3 || i != 0) {
3099                                         if(tmp_out[0] == '@') {
3100                                                 if(desc_on == 4)
3101                                                         extra += frontStrip(tmp_out, '@');
3102                                                 else
3103                                                         os << frontStrip(tmp_out, '@');
3104                                         } else
3105                                                 os << tmp_out;
3106                                 }
3107                         } else if (font2.latex() == LyXFont::ON) {
3108                                 // "TeX"-Mode on == > SGML-Mode on.
3109                                 if (c!= '\0')
3110                                         os << c;
3111                                 ++char_line_count;
3112                         } else {
3113                                 string sgml_string;
3114                                 if (linuxDocConvertChar(c, sgml_string) 
3115                                     && !style.free_spacing) {
3116                                         // in freespacing mode, spaces are
3117                                         // non-breaking characters
3118                                         // char is ' '
3119                                         if (desc_on == 1) {
3120                                                 ++char_line_count;
3121                                                 os << '\n'
3122                                                    << "</term><listitem><para>";
3123                                                 desc_on = 2;
3124                                         } else  {
3125                                                 os << c;
3126                                         }
3127                                 } else {
3128                                         os << sgml_string;
3129                                 }
3130                         }
3131                 }
3132                 // we have only to control for emphasis open here!
3133                 if (emph_flag) {
3134                         os << "</emphasis>";
3135                         emph_flag= false;
3136                 }
3137                 font1 = font2 = getFont(bparams, -1);
3138                 cell = table->CellHasContRow(current_cell_number);
3139         }
3140         lyxerr[Debug::LATEX] << "DocBookContTableRows...done " << this << endl;
3141 }
3142
3143
3144 void LyXParagraph::SimpleTeXBlanks(ostream & os, TexRow & texrow,
3145                                    LyXParagraph::size_type const i,
3146                                    int & column, LyXFont const & font,
3147                                    LyXLayout const & style)
3148 {
3149         if (column > tex_code_break_column
3150             && i 
3151             && GetChar(i - 1) != ' '
3152             && (i < size() - 1)
3153             // In LaTeX mode, we don't want to
3154             // break lines since some commands
3155             // do not like this
3156             && ! (font.latex() == LyXFont::ON)
3157             // same in FreeSpacing mode
3158             && !style.free_spacing
3159             // In typewriter mode, we want to avoid 
3160             // ! . ? : at the end of a line
3161             && !(font.family() == LyXFont::TYPEWRITER_FAMILY
3162                  && (GetChar(i-1) == '.'
3163                      || GetChar(i-1) == '?' 
3164                      || GetChar(i-1) == ':'
3165                      || GetChar(i-1) == '!'))) {
3166                 if (tex_code_break_column == 0) {
3167                         // in batchmode we need LaTeX to still
3168                         // see it as a space not as an extra '\n'
3169                         os << " %\n";
3170                 } else {
3171                         os << '\n';
3172                 }
3173                 texrow.newline();
3174                 texrow.start(this, i + 1);
3175                 column = 0;
3176         } else if (font.latex() == LyXFont::OFF) {
3177                 if (style.free_spacing) {
3178                         os << '~';
3179                 } else {
3180                         os << ' ';
3181                 }
3182         }
3183 }
3184
3185
3186 void LyXParagraph::SimpleTeXSpecialChars(BufferParams const & bparams,
3187                                          ostream & os, TexRow & texrow,
3188                                          bool moving_arg,
3189                                          LyXFont & font,
3190                                          LyXFont & running_font,
3191                                          LyXFont & basefont,
3192                                          bool & open_font,
3193                                          LyXLayout const & style,
3194                                          LyXParagraph::size_type & i,
3195                                          int & column, char const c)
3196 {
3197         // Two major modes:  LaTeX or plain
3198         // Handle here those cases common to both modes
3199         // and then split to handle the two modes separately.
3200         switch (c) {
3201         case LyXParagraph::META_INSET: {
3202                 Inset * inset = GetInset(i);
3203                 if (inset) {
3204                         bool close = false;
3205                         int len = os.tellp();
3206                         if ((inset->LyxCode() == Inset::GRAPHICS_CODE
3207                              || inset->LyxCode() == Inset::MATH_CODE
3208                              || inset->LyxCode() == Inset::URL_CODE)
3209                             && running_font.isRightToLeft()) {
3210                                 os << "\\L{";
3211                                 close = true;
3212                         }
3213
3214                         int tmp = inset->Latex(os, moving_arg,
3215                                                style.free_spacing);
3216
3217                         if (close)
3218                                 os << "}";
3219
3220                         if (tmp) {
3221                                 column = 0;
3222                         } else {
3223                                 column += os.tellp() - len;
3224                         }
3225                         for (; tmp--;) {
3226                                 texrow.newline();
3227                         }
3228                 }
3229         }
3230         break;
3231
3232         case LyXParagraph::META_NEWLINE:
3233                 if (open_font) {
3234                         column += running_font.latexWriteEndChanges(os,
3235                                                                     basefont,
3236                                                                     basefont);
3237                         open_font = false;
3238                 }
3239                 basefont = getFont(bparams, -1);
3240                 running_font = basefont;
3241                 break;
3242
3243         case LyXParagraph::META_HFILL: 
3244                 os << "\\hfill{}";
3245                 column += 7;
3246                 break;
3247
3248         default:
3249                 // And now for the special cases within each mode
3250                 // Are we in LaTeX mode?
3251                 if (font.latex() == LyXFont::ON) {
3252                         // at present we only have one option
3253                         // but I'll leave it as a switch statement
3254                         // so its simpler to extend. (ARRae)
3255                         switch (c) {
3256                         default:
3257                                 // make sure that we will not print
3258                                 // error generating chars to the tex
3259                                 // file. This test would not be needed
3260                                 // if it were done in the buffer
3261                                 // itself.
3262                                 if (c != '\0') {
3263                                         os << c;
3264                                 }
3265                                 break;
3266                         }
3267                 } else {
3268                         // Plain mode (i.e. not LaTeX)
3269                         switch (c) {
3270                         case '\\': 
3271                                 os << "\\textbackslash{}";
3272                                 column += 15;
3273                                 break;
3274                 
3275                         case '°': case '±': case '²': case '³':  
3276                         case '×': case '÷': case '¹': case 'ª':
3277                         case 'º': case '¬': case 'µ':
3278                                 if (bparams.inputenc == "latin1") {
3279                                         os << "\\ensuremath{"
3280                                            << c
3281                                            << '}';
3282                                         column += 13;
3283                                 } else {
3284                                         os << c;
3285                                 }
3286                                 break;
3287
3288                         case '|': case '<': case '>':
3289                                 // In T1 encoding, these characters exist
3290                                 if (lyxrc.fontenc == "T1") {
3291                                         os << c;
3292                                         //... but we should avoid ligatures
3293                                         if ((c == '>' || c == '<')
3294                                             && i <= size() - 2
3295                                             && GetChar(i + 1) == c){
3296                                                 os << "\\textcompwordmark{}";
3297                                                 column += 19;
3298                                         }
3299                                         break;
3300                                 }
3301                                 // Typewriter font also has them
3302                                 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
3303                                         os << c;
3304                                         break;
3305                                 } 
3306                                 // Otherwise, we use what LaTeX
3307                                 // provides us.
3308                                 switch(c) {
3309                                 case '<':
3310                                         os << "\\textless{}";
3311                                         column += 10;
3312                                         break;
3313                                 case '>':
3314                                         os << "\\textgreater{}";
3315                                         column += 13;
3316                                         break;
3317                                 case '|':
3318                                         os << "\\textbar{}";
3319                                         column += 9;
3320                                         break;
3321                                 }
3322                                 break;
3323
3324                         case '-': // "--" in Typewriter mode -> "-{}-"
3325                                 if (i <= size() - 2
3326                                     && GetChar(i + 1) == '-'
3327                                     && font.family() == LyXFont::TYPEWRITER_FAMILY) {
3328                                         os << "-{}";
3329                                         column += 2;
3330                                 } else {
3331                                         os << '-';
3332                                 }
3333                                 break;
3334
3335                         case '\"': 
3336                                 os << "\\char`\\\"{}";
3337                                 column += 9;
3338                                 break;
3339
3340                         case '£':
3341                                 if (bparams.inputenc == "default") {
3342                                         os << "\\pounds{}";
3343                                         column += 8;
3344                                 } else {
3345                                         os << c;
3346                                 }
3347                                 break;
3348
3349                         case '$': case '&':
3350                         case '%': case '#': case '{':
3351                         case '}': case '_':
3352                                 os << '\\' << c;
3353                                 column += 1;
3354                                 break;
3355
3356                         case '~':
3357                                 os << "\\textasciitilde{}";
3358                                 column += 16;
3359                                 break;
3360
3361                         case '^':
3362                                 os << "\\textasciicircum{}";
3363                                 column += 17;
3364                                 break;
3365
3366                         case '*': case '[': case ']':
3367                                 // avoid being mistaken for optional arguments
3368                                 os << '{' << c << '}';
3369                                 column += 2;
3370                                 break;
3371
3372                         case ' ':
3373                                 // Blanks are printed before font switching.
3374                                 // Sure? I am not! (try nice-latex)
3375                                 // I am sure it's correct. LyX might be smarter
3376                                 // in the future, but for now, nothing wrong is
3377                                 // written. (Asger)
3378                                 break;
3379
3380                         default:
3381                                 /* idea for labels --- begin*/
3382                                 // Check for "LyX"
3383                                 if (c ==  'L'
3384                                     && i <= size() - 3
3385                                     && font.family() != LyXFont::TYPEWRITER_FAMILY
3386                                     && GetChar(i + 1) == 'y'
3387                                     && GetChar(i + 2) == 'X') {
3388                                         os << "\\LyX{}";
3389                                         i += 2;
3390                                         column += 5;
3391                                 }
3392                                 // Check for "TeX"
3393                                 else if (c == 'T'
3394                                          && i <= size() - 3
3395                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3396                                          && GetChar(i + 1) == 'e'
3397                                          && GetChar(i + 2) == 'X') {
3398                                         os << "\\TeX{}";
3399                                         i += 2;
3400                                         column += 5;
3401                                 }
3402                                 // Check for "LaTeX2e"
3403                                 else if (c == 'L'
3404                                          && i <= size() - 7
3405                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3406                                          && GetChar(i + 1) == 'a'
3407                                          && GetChar(i + 2) == 'T'
3408                                          && GetChar(i + 3) == 'e'
3409                                          && GetChar(i + 4) == 'X'
3410                                          && GetChar(i + 5) == '2'
3411                                          && GetChar(i + 6) == 'e') {
3412                                         os << "\\LaTeXe{}";
3413                                         i += 6;
3414                                         column += 8;
3415                                 }
3416                                 // Check for "LaTeX"
3417                                 else if (c == 'L'
3418                                          && i <= size() - 5
3419                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3420                                          && GetChar(i + 1) == 'a'
3421                                          && GetChar(i + 2) == 'T'
3422                                          && GetChar(i + 3) == 'e'
3423                                          && GetChar(i + 4) == 'X') {
3424                                         os << "\\LaTeX{}";
3425                                         i += 4;
3426                                         column += 7;
3427                                         /* idea for labels --- end*/ 
3428                                 } else if (c != '\0') {
3429                                         os << c;
3430                                 }
3431                                 break;
3432                         }
3433                 }
3434         }
3435 }
3436
3437
3438 #if 0
3439 bool LyXParagraph::RoffContTableRows(ostream & os,
3440                                      LyXParagraph::size_type i,
3441                                      int actcell)
3442 {
3443         if (!table)
3444                 return false;
3445
3446         LyXFont font1(LyXFont::ALL_INHERIT);
3447         LyXFont font2;
3448         Inset * inset;
3449         char c;
3450
3451         string fname2 = TmpFileName(string(), "RAT2");
3452         int lastpos = i;
3453         int cell = table->CellHasContRow(actcell);
3454         ++actcell;
3455         while(cell >= 0) {
3456                 // first find the right position
3457                 i = lastpos;
3458                 for (; i < size() && actcell < cell; ++i) {
3459                         c = GetChar(i);
3460                         if (c == LyXParagraph::META_NEWLINE)
3461                                 ++actcell;
3462                 }
3463                 lastpos = i;
3464                 c = GetChar(i);
3465                 if ((c != ' ') && (c != LyXParagraph::META_NEWLINE))
3466                         os << " ";
3467                 for (; i < size()
3468                              && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
3469                      ++i) {
3470                         font2 = GetFontSettings(i);
3471                         if (font1.latex() != font2.latex()) {
3472                                 if (font2.latex() != LyXFont::OFF)
3473                                         continue;
3474                         }
3475                         c = GetChar(i);
3476                         switch (c) {
3477                         case LyXParagraph::META_INSET:
3478                                 if ((inset = GetInset(i))) {
3479 #ifdef HAVE_SSTREAM
3480                                         stringstream ss(ios::in | ios::out);
3481                                         inset->Ascii(ss);
3482                                         ss.seekp(0);
3483                                         ss.get(c);
3484                                         while (!ss) {
3485                                                 if (c == '\\')
3486                                                         os << "\\\\";
3487                                                 else
3488                                                         os << c;
3489                                                 ss.get(c);
3490                                         }
3491 #else
3492                                         strstream ss;
3493                                         inset->Ascii(ss);
3494                                         ss.seekp(0);
3495                                         ss.get(c);
3496                                         while (!ss) {
3497                                                 if (c == '\\')
3498                                                         os << "\\\\";
3499                                                 else
3500                                                         os << c;
3501                                                 ss.get(c);
3502                                         }
3503                                         delete [] ss.str();
3504 #endif
3505                                 }
3506                                 break;
3507                         case LyXParagraph::META_NEWLINE:
3508                                 break;
3509                         case LyXParagraph::META_HFILL: 
3510                                 break;
3511                         case '\\': 
3512                                 os << "\\\\";
3513                                 break;
3514                         default:
3515                                 if (c != '\0')
3516                                         os << c;
3517                                 else
3518                                         lyxerr.debug() << "RoffAsciiTable: "
3519                                                 "NULL char in structure."
3520                                                        << endl;
3521                                 break;
3522                         }
3523                 }
3524                 cell = table->CellHasContRow(actcell);
3525         }
3526         return true;
3527 }
3528 #endif
3529
3530
3531 LyXParagraph * LyXParagraph::TeXDeeper(BufferParams const & bparams,
3532                                        ostream & os, TexRow & texrow,
3533                                        ostream & foot,
3534                                        TexRow & foot_texrow,
3535                                        int & foot_count)
3536 {
3537         lyxerr[Debug::LATEX] << "TeXDeeper...     " << this << endl;
3538         LyXParagraph * par = this;
3539
3540         while (par &&
3541                (par->depth == depth) &&
3542                (par->footnoteflag == footnoteflag)) {
3543                 if (par->IsDummy())
3544                         lyxerr << "ERROR (LyXParagraph::TeXDeeper)" << endl;
3545                 if (textclasslist.Style(bparams.textclass, 
3546                                         par->layout).isEnvironment()
3547                     || par->pextra_type != PEXTRA_NONE) {
3548                         par = par->TeXEnvironment(bparams,
3549                                                   os, texrow,
3550                                                   foot, foot_texrow,
3551                                                   foot_count);
3552                 } else {
3553                         par = par->TeXOnePar(bparams,
3554                                              os, texrow, false,
3555                                              foot, foot_texrow,
3556                                              foot_count);
3557                 }
3558         }
3559         lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
3560
3561         return par;
3562 }
3563
3564
3565 LyXParagraph * LyXParagraph::TeXEnvironment(BufferParams const & bparams,
3566                                             ostream & os, TexRow & texrow,
3567                                             ostream & foot,
3568                                             TexRow & foot_texrow,
3569                                             int & foot_count)
3570 {
3571         bool eindent_open = false;
3572         bool foot_this_level = false;
3573         // flags when footnotetext should be appended to file.
3574         static bool minipage_open = false;
3575         static int minipage_open_depth = 0;
3576         char par_sep = bparams.paragraph_separation;
3577     
3578         lyxerr[Debug::LATEX] << "TeXEnvironment...     " << this << endl;
3579         if (IsDummy())
3580                 lyxerr << "ERROR (LyXParagraph::TeXEnvironment)" << endl;
3581
3582         LyXLayout const & style =
3583                 textclasslist.Style(bparams.textclass,
3584                                     layout);
3585        
3586         if (pextra_type == PEXTRA_INDENT) {
3587                 if (!pextra_width.empty()) {
3588                         os << "\\begin{LyXParagraphIndent}{"
3589                            << pextra_width << "}\n";
3590                 } else {
3591                         //float ib = atof(pextra_widthp.c_str())/100;
3592                         // string can't handle floats at present (971109)
3593                         // so I'll do a conversion by hand knowing that
3594                         // the limits are 0.0 to 1.0. ARRae.
3595                         os << "\\begin{LyXParagraphIndent}{";
3596                         switch (pextra_widthp.length()) {
3597                         case 3:
3598                                 os << "1.00";
3599                                 break;
3600                         case 2:
3601                                 os << "0."
3602                                    << pextra_widthp;
3603                                 break;
3604                         case 1:
3605                                 os << "0.0"
3606                                    << pextra_widthp;
3607                         }
3608                         os << "\\columnwidth}\n";
3609                 }
3610                 texrow.newline();
3611                 eindent_open = true;
3612         }
3613         if ((pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3614                 if (pextra_hfill && Previous() &&
3615                     (Previous()->pextra_type == PEXTRA_MINIPAGE)) {
3616                         os << "\\hfill{}\n";
3617                         texrow.newline();
3618                 }
3619                 if (par_sep == BufferParams::PARSEP_INDENT) {
3620                         os << "{\\setlength\\parindent{0pt}\n";
3621                         texrow.newline();
3622                 }
3623                 os << "\\begin{minipage}";
3624                 switch(pextra_alignment) {
3625                 case MINIPAGE_ALIGN_TOP:
3626                         os << "[t]";
3627                         break;
3628                 case MINIPAGE_ALIGN_MIDDLE:
3629                         os << "[m]";
3630                         break;
3631                 case MINIPAGE_ALIGN_BOTTOM:
3632                         os << "[b]";
3633                         break;
3634                 }
3635                 if (!pextra_width.empty()) {
3636                         os << '{' << pextra_width << "}\n";
3637                 } else {
3638                         //float ib = atof(par->pextra_width.c_str())/100;
3639                         // string can't handle floats at present
3640                         // so I'll do a conversion by hand knowing that
3641                         // the limits are 0.0 to 1.0. ARRae.
3642                         os << '{';
3643                         switch (pextra_widthp.length()) {
3644                         case 3:
3645                                 os << "1.00";
3646                                 break;
3647                         case 2:
3648                                 os << "0."
3649                                    << pextra_widthp;
3650                                 break;
3651                         case 1:
3652                                 os << "0.0"
3653                                    << pextra_widthp;
3654                         }
3655                         os << "\\columnwidth}\n";
3656                 }
3657                 texrow.newline();
3658                 if (par_sep == BufferParams::PARSEP_INDENT) {
3659                         os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3660                         texrow.newline();
3661                 }
3662                 minipage_open = true;
3663                 minipage_open_depth = depth;
3664         }
3665
3666 #ifdef WITH_WARNINGS
3667 #warning Define FANCY_FOOTNOTE_CODE to re-enable Allan footnote code
3668         //I disabled it because it breaks when lists span on several
3669         //pages (JMarc)
3670 #endif
3671         if (style.isEnvironment()){
3672                 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
3673 #ifdef FANCY_FOOTNOTE_CODE
3674                         if (foot_count < 0) {
3675                                 // flag that footnote[mark][text] should be
3676                                 // used for any footnotes from now on
3677                                 foot_count = 0;
3678                                 foot_this_level = true;
3679                         }
3680 #endif
3681                         os << "\\begin{" << style.latexname() << "}{"
3682                            << labelwidthstring << "}\n";
3683                 } else if (style.labeltype == LABEL_BIBLIO) {
3684                         // ale970405
3685                         os << "\\begin{" << style.latexname() << "}{"
3686                            <<  bibitemWidest(current_view->painter())
3687                            << "}\n";
3688                 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
3689 #ifdef FANCY_FOOTNOTE_CODE
3690                         if (foot_count < 0) {
3691                                 // flag that footnote[mark][text] should be
3692                                 // used for any footnotes from now on
3693                                 foot_count = 0;
3694                                 foot_this_level = true;
3695                         }
3696 #endif
3697                         os << "\\begin{" << style.latexname() << '}'
3698                            << style.latexparam() << '\n';
3699                 } else 
3700                         os << "\\begin{" << style.latexname() << '}'
3701                            << style.latexparam() << '\n';
3702                 texrow.newline();
3703         }
3704         LyXParagraph * par = this;
3705         do {
3706                 par = par->TeXOnePar(bparams,
3707                                      os, texrow, false,
3708                                      foot, foot_texrow, foot_count);
3709
3710                 if (minipage_open && par && !style.isEnvironment() &&
3711                     (par->pextra_type == PEXTRA_MINIPAGE) &&
3712                     par->pextra_start_minipage) {
3713                         os << "\\end{minipage}\n";
3714                         texrow.newline();
3715                         if (par_sep == BufferParams::PARSEP_INDENT) {
3716                                 os << "}\n";
3717                                 texrow.newline();
3718                         }
3719                         minipage_open = false;
3720                 }
3721                 if (par && par->depth > depth) {
3722                         if (textclasslist.Style(bparams.textclass,
3723                                                 par->layout).isParagraph()
3724                             && !par->table
3725                             // Thinko!
3726                             // How to handle this? (Lgb)
3727                             //&& !suffixIs(os, "\n\n")
3728                                 ) {
3729                                 // There should be at least one '\n' already
3730                                 // but we need there to be two for Standard 
3731                                 // paragraphs that are depth-increment'ed to be
3732                                 // output correctly.  However, tables can
3733                                 // also be paragraphs so don't adjust them.
3734                                 // ARRae
3735                                 // Thinkee:
3736                                 // Will it ever harm to have one '\n' too
3737                                 // many? i.e. that we sometimes will have
3738                                 // three in a row. (Lgb)
3739                                 os << '\n';
3740                                 texrow.newline();
3741                         }
3742                         par = par->TeXDeeper(bparams, os, texrow,
3743                                              foot, foot_texrow, foot_count);
3744                 }
3745                 if (par && par->layout == layout && par->depth == depth &&
3746                     (par->pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3747                         if (par->pextra_hfill && par->Previous() &&
3748                             (par->Previous()->pextra_type == PEXTRA_MINIPAGE)){
3749                                 os << "\\hfill{}\n";
3750                                 texrow.newline();
3751                         }
3752                         if (par_sep == BufferParams::PARSEP_INDENT) {
3753                                 os << "{\\setlength\\parindent{0pt}\n";
3754                                 texrow.newline();
3755                         }
3756                         os << "\\begin{minipage}";
3757                         switch(par->pextra_alignment) {
3758                         case MINIPAGE_ALIGN_TOP:
3759                                 os << "[t]";
3760                                 break;
3761                         case MINIPAGE_ALIGN_MIDDLE:
3762                                 os << "[m]";
3763                                 break;
3764                         case MINIPAGE_ALIGN_BOTTOM:
3765                                 os << "[b]";
3766                                 break;
3767                         }
3768                         if (!par->pextra_width.empty()) {
3769                                 os << '{' << par->pextra_width << "}\n";
3770                         } else {
3771                                 //float ib = atof(par->pextra_widthp.c_str())/100;
3772                                 // string can't handle floats at present
3773                                 // so I'll do a conversion by hand knowing that
3774                                 // the limits are 0.0 to 1.0. ARRae.
3775                                 os << '{';
3776                                 switch (par->pextra_widthp.length()) {
3777                                 case 3:
3778                                         os << "1.00";
3779                                         break;
3780                                 case 2:
3781                                         os << "0." << par->pextra_widthp;
3782                                         break;
3783                                 case 1:
3784                                         os << "0.0" << par->pextra_widthp;
3785                                 }
3786                                 os << "\\columnwidth}\n";
3787                         }
3788                         texrow.newline();
3789                         if (par_sep == BufferParams::PARSEP_INDENT) {
3790                                 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3791                                 texrow.newline();
3792                         }
3793                         minipage_open = true;
3794                         minipage_open_depth = par->depth;
3795                 }
3796         } while (par
3797                  && par->layout == layout
3798                  && par->depth == depth
3799                  && par->pextra_type == pextra_type
3800                  && par->footnoteflag == footnoteflag);
3801  
3802         if (style.isEnvironment()) {
3803                 os << "\\end{" << style.latexname() << '}';
3804                 // maybe this should go after the minipage closes?
3805                 if (foot_this_level) {
3806                         if (foot_count >= 1) {
3807                                 if (foot_count > 1) {
3808                                         os << "\\addtocounter{footnote}{-"
3809                                            << foot_count - 1
3810                                            << '}';
3811                                 }
3812                                 os << foot;
3813                                 texrow += foot_texrow;
3814                                 foot.clear();
3815                                 foot_texrow.reset();
3816                                 foot_count = 0;
3817                         }
3818                 }
3819         }
3820         if (minipage_open && (minipage_open_depth == depth) &&
3821             (!par || par->pextra_start_minipage ||
3822              par->pextra_type != PEXTRA_MINIPAGE)) {
3823                 os << "\\end{minipage}\n";
3824                 texrow.newline();
3825                 if (par_sep == BufferParams::PARSEP_INDENT) {
3826                         os << "}\n";
3827                         texrow.newline();
3828                 }
3829                 if (par && par->pextra_type != PEXTRA_MINIPAGE) {
3830                         os << "\\medskip\n\n";
3831                         texrow.newline();
3832                         texrow.newline();
3833                 }
3834                 minipage_open = false;
3835         }
3836         if (eindent_open) {
3837                 os << "\\end{LyXParagraphIndent}\n";
3838                 texrow.newline();
3839         }
3840         if (!(par && (par->pextra_type == PEXTRA_MINIPAGE) 
3841               && par->pextra_hfill)) {
3842                 os << '\n';
3843                 texrow.newline();
3844         }
3845         lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
3846         return par;  // ale970302
3847 }
3848
3849
3850 LyXParagraph * LyXParagraph::TeXFootnote(BufferParams const & bparams,
3851                                          ostream & os, TexRow & texrow,
3852                                          ostream & foot, TexRow & foot_texrow,
3853                                          int & foot_count,
3854                                          bool parent_is_rtl)
3855 {
3856         lyxerr[Debug::LATEX] << "TeXFootnote...  " << this << endl;
3857         if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
3858                 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3859                         "No footnote!" << endl;
3860
3861         LyXParagraph * par = this;
3862         LyXLayout const & style =
3863                 textclasslist.Style(bparams.textclass, 
3864                                     previous->GetLayout());
3865         
3866         if (style.needprotect && footnotekind != LyXParagraph::FOOTNOTE){
3867                 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3868                         "Float other than footnote in command"
3869                         " with moving argument is illegal" << endl;
3870         }
3871
3872         if (footnotekind != LyXParagraph::FOOTNOTE
3873             && footnotekind != LyXParagraph::MARGIN
3874             && os.tellp()
3875             // Thinko
3876             // How to solve this?
3877             //&& !suffixIs(file, '\n')
3878                 ) {
3879                 // we need to ensure that real floats like tables and figures
3880                 // have their \begin{} on a new line otherwise we can get
3881                 // incorrect results when using the endfloat.sty package
3882                 // especially if two floats follow one another.  ARRae 981022
3883                 // NOTE: if the file is length 0 it must have just been
3884                 //       written out so we assume it ended with a '\n'
3885                 // Thinkee:
3886                 // As far as I can see there is never any harm in writing
3887                 // a '\n' too much. Please tell me if I am wrong. (Lgb)
3888                 os << '\n';
3889                 texrow.newline();
3890         }
3891
3892         bool moving_arg = false;
3893         bool need_closing = false;
3894         bool is_rtl = isRightToLeftPar(bparams);
3895
3896         if (is_rtl != parent_is_rtl) {
3897                 if (is_rtl)
3898                         os << "\\R{";
3899                 else
3900                         os << "\\L{";
3901                 need_closing = true;
3902         }
3903         
3904         //BufferParams * params = &current_view->buffer()->params;
3905         bool footer_in_body = true;
3906         switch (footnotekind) {
3907         case LyXParagraph::FOOTNOTE:
3908                 if (style.intitle) {
3909                         os << "\\thanks{\n";
3910                         footer_in_body = false;
3911                         moving_arg = true;
3912                 } else {
3913                         if (foot_count == -1) {
3914                                 // we're at depth 0 so we can use:
3915                                 os << "\\footnote{%\n";
3916                                 footer_in_body = false;
3917                         } else {
3918                                 os << "\\footnotemark{}%\n";
3919                                 if (foot_count) {
3920                                         // we only need this when there are
3921                                         // multiple footnotes
3922                                         os << "\\stepcounter{footnote}";
3923                                 }
3924                                 os << "\\footnotetext{%\n";
3925                                 foot_texrow.start(this, 0);
3926                                 foot_texrow.newline();
3927                                 ++foot_count;
3928                         }
3929                 }
3930                 break;
3931         case LyXParagraph::MARGIN:
3932                 os << "\\marginpar{\n";
3933                 break;
3934         case LyXParagraph::FIG:
3935                 if (pextra_type == PEXTRA_FLOATFLT
3936                     && (!pextra_width.empty()
3937                         || !pextra_widthp.empty())) {
3938                         if (!pextra_width.empty())
3939                                 os << "\\begin{floatingfigure}{"
3940                                    << pextra_width << "}\n";
3941                         else
3942                                 os << "\\begin{floatingfigure}{"
3943                                    << atoi(pextra_widthp.c_str())/100.0
3944                                    << "\\textwidth}\n";
3945                 } else {
3946                         os << "\\begin{figure}";
3947                         if (!bparams.float_placement.empty()) { 
3948                                 os << '[' << bparams.float_placement << "]\n";
3949                         } else {
3950                                 os << '\n';
3951                         }
3952                 }
3953                 break;
3954         case LyXParagraph::TAB:
3955                 os << "\\begin{table}";
3956                 if (!bparams.float_placement.empty()) { 
3957                         os << '[' << bparams.float_placement << "]\n";
3958                 } else {
3959                         os << '\n';
3960                 }
3961                 break;
3962         case LyXParagraph::WIDE_FIG:
3963                 os << "\\begin{figure*}";
3964                 if (!bparams.float_placement.empty()) { 
3965                         os << '[' << bparams.float_placement << "]\n";
3966                 } else {
3967                         os << '\n';
3968                 }
3969                 break;
3970         case LyXParagraph::WIDE_TAB:
3971                 os << "\\begin{table*}";
3972                 if (!bparams.float_placement.empty()) { 
3973                         os << '[' << bparams.float_placement << "]\n";
3974                 } else {
3975                         os << '\n';
3976                 }
3977                 break;
3978         case LyXParagraph::ALGORITHM:
3979                 os << "\\begin{algorithm}\n";
3980                 break;
3981         }
3982         texrow.newline();
3983    
3984         if (footnotekind != LyXParagraph::FOOTNOTE
3985             || !footer_in_body) {
3986                 // Process text for all floats except footnotes in body
3987                 do {
3988                         LyXLayout const & style =
3989                                 textclasslist
3990                                 .Style(bparams.textclass, par->layout);
3991                         if (par->IsDummy())
3992                                 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3993                                        << endl;
3994                         if (style.isEnvironment()
3995                             || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3996                                 // Allows the use of minipages within float
3997                                 // environments. Shouldn't be circular because
3998                                 // we don't support footnotes inside
3999                                 // floats (yet). ARRae
4000                                 par = par->TeXEnvironment(bparams, os, texrow,
4001                                                           foot, foot_texrow,
4002                                                           foot_count);
4003                         } else {
4004                                 par = par->TeXOnePar(bparams,
4005                                                      os, texrow, moving_arg,
4006                                                      foot, foot_texrow,
4007                                                      foot_count);
4008                         }
4009                         
4010                         if (par && !par->IsDummy() && par->depth > depth) {
4011                                 par = par->TeXDeeper(bparams, os, texrow,
4012                                                      foot, foot_texrow,
4013                                                      foot_count);
4014                         }
4015                 } while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4016         } else {
4017                 // process footnotes > depth 0 or in environments separately
4018                 // NOTE: Currently don't support footnotes within footnotes
4019                 //       even though that is possible using the \footnotemark
4020 #ifdef HAVE_SSTREAM
4021                 std::ostringstream dummy;
4022 #else
4023                 ostrstream dummy;
4024 #endif
4025                 TexRow dummy_texrow;
4026                 int dummy_count = 0;
4027                 do {
4028                         LyXLayout const & style =
4029                                 textclasslist
4030                                 .Style(bparams.textclass, par->layout);
4031                         if (par->IsDummy())
4032                                 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
4033                                        << endl;
4034                         if (style.isEnvironment()
4035                             || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
4036                                 // Allows the use of minipages within float
4037                                 // environments. Shouldn't be circular because
4038                                 // we don't support footnotes inside
4039                                 // floats (yet). ARRae
4040                                 par = par->TeXEnvironment(bparams,
4041                                                           foot, foot_texrow,
4042                                                           dummy, dummy_texrow,
4043                                                           dummy_count);
4044                         } else {
4045                                 par = par->TeXOnePar(bparams,
4046                                                      foot, foot_texrow,
4047                                                      moving_arg,
4048                                                      dummy, dummy_texrow,
4049                                                      dummy_count);
4050                         }
4051
4052                         if (par && !par->IsDummy() && par->depth > depth) {
4053                                 par = par->TeXDeeper(bparams,
4054                                                      foot, foot_texrow,
4055                                                      dummy, dummy_texrow,
4056                                                      dummy_count);
4057                         }
4058                 } while (par
4059                          && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4060                 if (dummy_count) {
4061                         lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
4062                                 "Footnote in a Footnote -- not supported"
4063                                << endl;
4064                 }
4065 #ifndef HAVE_OSTREAM
4066                 delete [] dummy.str();
4067 #endif
4068         }
4069
4070         switch (footnotekind) {
4071         case LyXParagraph::FOOTNOTE:
4072                 if (footer_in_body) {
4073                         // This helps tell which of the multiple
4074                         // footnotetexts an error was in.
4075                         foot << "}%\n";
4076                         foot_texrow.newline();
4077                 } else {
4078                         os << '}';
4079                 }
4080                 break;
4081         case LyXParagraph::MARGIN:
4082                 os << '}';
4083                 break;
4084         case LyXParagraph::FIG:
4085                 if (pextra_type == PEXTRA_FLOATFLT
4086                     && (!pextra_width.empty()
4087                         || !pextra_widthp.empty()))
4088                         os << "\\end{floatingfigure}";
4089                 else
4090                         os << "\\end{figure}";
4091                 break;
4092         case LyXParagraph::TAB:
4093                 os << "\\end{table}";
4094                 break;
4095         case LyXParagraph::WIDE_FIG:
4096                 os << "\\end{figure*}";
4097                 break;
4098         case LyXParagraph::WIDE_TAB:
4099                 os << "\\end{table*}";
4100                 break;
4101         case LyXParagraph::ALGORITHM:
4102                 os << "\\end{algorithm}";
4103                 break;
4104         }
4105
4106         if (need_closing)
4107                 os << "}";
4108
4109         if (footnotekind != LyXParagraph::FOOTNOTE
4110             && footnotekind != LyXParagraph::MARGIN) {
4111                 // we need to ensure that real floats like tables and figures
4112                 // have their \end{} on a line of their own otherwise we can
4113                 // get incorrect results when using the endfloat.sty package.
4114                 os << "\n";
4115                 texrow.newline();
4116         }
4117
4118         lyxerr[Debug::LATEX] << "TeXFootnote...done " << par->next << endl;
4119         return par;
4120 }
4121
4122
4123 bool LyXParagraph::IsDummy() const
4124 {
4125         return (footnoteflag == LyXParagraph::NO_FOOTNOTE && previous
4126                 && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4127 }
4128
4129
4130 void LyXParagraph::SetPExtraType(BufferParams const & bparams,
4131                                  int type, char const * width,
4132                                  char const * widthp)
4133 {
4134         pextra_type = type;
4135         pextra_width = width;
4136         pextra_widthp = widthp;
4137
4138         if (textclasslist.Style(bparams.textclass, 
4139                                 layout).isEnvironment()) {
4140                 LyXParagraph
4141                         * par = this,
4142                         * ppar = par;
4143
4144                 while (par && (par->layout == layout)
4145                        && (par->depth == depth)) {
4146                         ppar = par;
4147                         par = par->Previous();
4148                         if (par)
4149                                 par = par->FirstPhysicalPar();
4150                         while (par && par->depth > depth) {
4151                                 par = par->Previous();
4152                                 if (par)
4153                                         par = par->FirstPhysicalPar();
4154                         }
4155                 }
4156                 par = ppar;
4157                 while (par && (par->layout == layout)
4158                        && (par->depth == depth)) {
4159                         par->pextra_type = type;
4160                         par->pextra_width = width;
4161                         par->pextra_widthp = widthp;
4162                         par = par->NextAfterFootnote();
4163                         if (par && (par->depth > depth))
4164                                 par->SetPExtraType(bparams,
4165                                                    type, width, widthp);
4166                         while (par && ((par->depth > depth) || par->IsDummy()))
4167                                 par = par->NextAfterFootnote();
4168                 }
4169         }
4170 }
4171
4172
4173 void LyXParagraph::UnsetPExtraType(BufferParams const & bparams)
4174 {
4175         if (pextra_type == PEXTRA_NONE)
4176                 return;
4177     
4178         pextra_type = PEXTRA_NONE;
4179         pextra_width.erase();
4180         pextra_widthp.erase();
4181
4182         if (textclasslist.Style(bparams.textclass, 
4183                                 layout).isEnvironment()) {
4184                 LyXParagraph
4185                         * par = this,
4186                         * ppar = par;
4187
4188                 while (par && (par->layout == layout)
4189                        && (par->depth == depth)) {
4190                         ppar = par;
4191                         par = par->Previous();
4192                         if (par)
4193                                 par = par->FirstPhysicalPar();
4194                         while (par && par->depth > depth) {
4195                                 par = par->Previous();
4196                                 if (par)
4197                                         par = par->FirstPhysicalPar();
4198                         }
4199                 }
4200                 par = ppar;
4201                 while (par && (par->layout == layout)
4202                        && (par->depth == depth)) {
4203                         par->pextra_type = PEXTRA_NONE;
4204                         par->pextra_width.erase();
4205                         par->pextra_widthp.erase();
4206                         par = par->NextAfterFootnote();
4207                         if (par && (par->depth > depth))
4208                                 par->UnsetPExtraType(bparams);
4209                         while (par && ((par->depth > depth) || par->IsDummy()))
4210                                 par = par->NextAfterFootnote();
4211                 }
4212         }
4213 }
4214
4215
4216 bool LyXParagraph::IsHfill(size_type pos) const
4217 {
4218         return IsHfillChar(GetChar(pos));
4219 }
4220
4221
4222 bool LyXParagraph::IsInset(size_type pos) const
4223 {
4224         return IsInsetChar(GetChar(pos));
4225 }
4226
4227
4228 bool LyXParagraph::IsFloat(size_type pos) const
4229 {
4230         return IsFloatChar(GetChar(pos));
4231 }
4232
4233
4234 bool LyXParagraph::IsNewline(size_type pos) const
4235 {
4236         return pos >= 0 && IsNewlineChar(GetChar(pos));
4237 }
4238
4239
4240 bool LyXParagraph::IsSeparator(size_type pos) const
4241 {
4242         return IsSeparatorChar(GetChar(pos));
4243 }
4244
4245
4246 bool LyXParagraph::IsLineSeparator(size_type pos) const
4247 {
4248         return IsLineSeparatorChar(GetChar(pos));
4249 }
4250
4251
4252 bool LyXParagraph::IsKomma(size_type pos) const
4253 {
4254         return IsKommaChar(GetChar(pos));
4255 }
4256
4257
4258 /// Used by the spellchecker
4259 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
4260 {
4261         unsigned char c = GetChar(pos);
4262         if (IsLetterChar(c))
4263                 return true;
4264         // '\0' is not a letter, allthough every string contains "" (below)
4265         if( c == '\0')
4266                 return false;
4267         // We want to pass the ' and escape chars to ispell
4268         string extra = lyxrc.isp_esc_chars + '\'';
4269         char ch[2];
4270         ch[0] = c;
4271         ch[1] = 0;
4272         return contains(extra, ch);
4273 }
4274  
4275  
4276 bool LyXParagraph::IsWord(size_type pos ) const
4277 {
4278         return IsWordChar(GetChar(pos)) ;
4279 }
4280
4281
4282 Language const *
4283 LyXParagraph::getParLanguage(BufferParams const & bparams) const 
4284 {
4285         if (IsDummy())
4286                 return FirstPhysicalPar()->getParLanguage(bparams);
4287         else if (size() > 0)
4288 #ifndef NEW_TABULAR
4289                 if (!table)
4290 #endif
4291                         return GetFirstFontSettings().language();
4292 #ifndef NEW_TABULAR
4293                 else {
4294                         for (size_type pos = 0; pos < size(); ++pos)
4295                                 if (IsNewline(pos))
4296                                         return GetFontSettings(bparams, pos).language();
4297                         return GetFirstFontSettings().language();
4298                 }
4299 #endif
4300         else if (previous)
4301                 return previous->getParLanguage(bparams);
4302         else
4303                 return bparams.language_info;
4304 }
4305
4306
4307 bool LyXParagraph::isRightToLeftPar(BufferParams const & bparams) const
4308 {
4309         return lyxrc.rtl_support && !table
4310                 && getParLanguage(bparams)->RightToLeft();
4311 }
4312
4313
4314 void LyXParagraph::ChangeLanguage(BufferParams const & bparams,
4315                                   Language const * from, Language const * to)
4316 {
4317         for(size_type i = 0; i < size(); ++i) {
4318                 LyXFont font = GetFontSettings(bparams, i);
4319                 if (font.language() == from) {
4320                         font.setLanguage(to);
4321                         SetFont(i, font);
4322                 }
4323         }
4324 }
4325
4326
4327 bool LyXParagraph::isMultiLingual(BufferParams const & bparams)
4328 {
4329         Language const * doc_language =
4330                 bparams.language_info;
4331         for(size_type i = 0; i < size(); ++i) {
4332                 LyXFont font = GetFontSettings(bparams, i);
4333                 if (font.language() != doc_language)
4334                         return true;
4335         }
4336         return false;
4337 }
4338
4339
4340 // Convert the paragraph to a string.
4341 // Used for building the table of contents
4342 string LyXParagraph::String(BufferParams const & bparams, bool label)
4343 {
4344         string s;
4345         if (label && !IsDummy() && !labelstring.empty())
4346                 s += labelstring + ' ';
4347         string::size_type len = s.size();
4348
4349         for (LyXParagraph::size_type i = 0; i < size(); ++i) {
4350                 unsigned char c = GetChar(i);
4351                 if (IsPrintable(c))
4352                         s += c;
4353                 else if (c == META_INSET &&
4354                          GetInset(i)->LyxCode() == Inset::MATH_CODE) {
4355 #ifdef HAVE_SSTREAM
4356                         std::ostringstream ost;
4357                         GetInset(i)->Ascii(ost);
4358 #else
4359                         ostrstream ost;
4360                         GetInset(i)->Ascii(ost);
4361                         ost << '\0';
4362 #endif
4363                         s += subst(ost.str(),'\n',' ');
4364                 }
4365         }
4366
4367         if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE 
4368             && footnoteflag == LyXParagraph::NO_FOOTNOTE)
4369                 s += NextAfterFootnote()->String(bparams, false);
4370
4371         if (!IsDummy()) {
4372                 if (isRightToLeftPar(bparams))
4373                         reverse(s.begin() + len,s.end());
4374         }
4375         return s;
4376 }
4377
4378
4379 string LyXParagraph::String(LyXParagraph::size_type beg,
4380                             LyXParagraph::size_type end)
4381 {
4382         string s;
4383         int actcell = 0;
4384         int cell = 1;
4385 #ifndef NEW_TABULAR
4386         if (table)
4387                 for (LyXParagraph::size_type i = 0; i < beg; ++i)
4388                         if (IsNewline(i)) {
4389                                 if (cell >= table->NumberOfCellsInRow(actcell))
4390                                         cell = 1;
4391                                 else
4392                                         ++cell;
4393                                 ++actcell;
4394                         }
4395 #endif
4396         
4397         if (beg == 0 && !IsDummy() && !labelstring.empty())
4398                 s += labelstring + ' ';
4399
4400         for (LyXParagraph::size_type i = beg; i < end; ++i) {
4401                 unsigned char c = GetChar(i);
4402                 if (IsPrintable(c))
4403                         s += c;
4404                 else if (c == META_INSET) {
4405 #ifdef HAVE_SSTREAM
4406                         std::ostringstream ost;
4407                         GetInset(i)->Ascii(ost);
4408 #else
4409                         ostrstream ost;
4410                         GetInset(i)->Ascii(ost);
4411                         ost << '\0';
4412 #endif
4413                         s += ost.str();
4414                 } else if (table && IsNewlineChar(c)) {
4415                         if (cell >= table->NumberOfCellsInRow(actcell)) {
4416                                 s += '\n';
4417                                 cell = 1;
4418                         } else {
4419                                 s += ' ';
4420                                 ++cell;
4421                         }
4422                         ++actcell;
4423                 }
4424         }
4425
4426         //if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
4427         //      s += NextAfterFootnote()->String(false);
4428
4429         return s;
4430 }