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