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