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