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