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