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