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