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