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