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