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