]> git.lyx.org Git - lyx.git/blob - src/paragraph.C
NEW_INSETS changes, + some small things in insettabular.C
[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         if (
134 #ifndef NEW_INSETS
135                 footnoteflag != LyXParagraph::NO_FOOTNOTE ||
136 #endif
137             !previous
138 #ifndef NEW_INSETS
139             || previous->footnoteflag == LyXParagraph::NO_FOOTNOTE
140 #endif
141                 ) {
142
143 #ifndef NEW_INSETS
144                 // The beginning or the end of a footnote environment?
145                 if (footflag != footnoteflag) {
146                         footflag = footnoteflag;
147                         if (footflag) {
148                                 os << "\n\\begin_float "
149                                    << string_footnotekinds[footnotekind]
150                                    << " ";
151                         } else {
152                                 os << "\n\\end_float ";
153                         }
154                 }
155 #endif
156                 // The beginning or end of a deeper (i.e. nested) area?
157                 if (dth != depth) {
158                         if (depth > dth) {
159                                 while (depth > dth) {
160                                         os << "\n\\begin_deeper ";
161                                         ++dth;
162                                 }
163                         } else {
164                                 while (depth < dth) {
165                                         os << "\n\\end_deeper ";
166                                         --dth;
167                                 }
168                         }
169                 }
170
171                 // First write the layout
172                 os << "\n\\layout "
173                    << textclasslist.NameOfLayout(params.textclass, layout)
174                    << "\n";
175
176                 // Maybe some vertical spaces.
177                 if (added_space_top.kind() != VSpace::NONE)
178                         os << "\\added_space_top "
179                            << added_space_top.asLyXCommand() << " ";
180                 if (added_space_bottom.kind() != VSpace::NONE)
181                         os << "\\added_space_bottom "
182                            << added_space_bottom.asLyXCommand() << " ";
183
184                 // Maybe the paragraph has special spacing
185                 spacing.writeFile(os, true);
186                 
187                 // The labelwidth string used in lists.
188                 if (!labelwidthstring.empty())
189                         os << "\\labelwidthstring "
190                            << labelwidthstring << '\n';
191
192                 // Lines above or below?
193                 if (line_top)
194                         os << "\\line_top ";
195                 if (line_bottom)
196                         os << "\\line_bottom ";
197
198                 // Pagebreaks above or below?
199                 if (pagebreak_top)
200                         os << "\\pagebreak_top ";
201                 if (pagebreak_bottom)
202                         os << "\\pagebreak_bottom ";
203                         
204                 // Start of appendix?
205                 if (start_of_appendix)
206                         os << "\\start_of_appendix ";
207
208                 // Noindent?
209                 if (noindent)
210                         os << "\\noindent ";
211                         
212                 // Alignment?
213                 if (align != LYX_ALIGN_LAYOUT) {
214                         int h = 0;
215                         switch (align) {
216                         case LYX_ALIGN_LEFT: h = 1; break;
217                         case LYX_ALIGN_RIGHT: h = 2; break;
218                         case LYX_ALIGN_CENTER: h = 3; break;
219                         default: h = 0; break;
220                         }
221                         os << "\\align " << string_align[h] << " ";
222                 }
223                 if (pextra_type != PEXTRA_NONE) {
224                         os << "\\pextra_type " << pextra_type;
225                         if (pextra_type == PEXTRA_MINIPAGE) {
226                                 os << " \\pextra_alignment "
227                                    << pextra_alignment;
228                                 if (pextra_hfill)
229                                         os << " \\pextra_hfill "
230                                            << pextra_hfill;
231                                 if (pextra_start_minipage)
232                                         os << " \\pextra_start_minipage "
233                                            << pextra_start_minipage;
234                         }
235                         if (!pextra_width.empty()) {
236                                 os << " \\pextra_width "
237                                    << VSpace(pextra_width).asLyXCommand();
238                         } else if (!pextra_widthp.empty()) {
239                                 os << " \\pextra_widthp "
240                                    << pextra_widthp;
241                         }
242                         os << '\n';
243                 }
244         } else {
245 #ifndef NEW_INSETS
246                 // Dummy layout. This means that a footnote ended.
247                 os << "\n\\end_float ";
248                 footflag = LyXParagraph::NO_FOOTNOTE;
249 #else
250                 lyxerr << "Why don't we have a previous?" << endl;
251 #endif
252         }
253 #ifndef NEW_TABULAR     
254         // It might be a table.
255         if (table){
256                 os << "\\LyXTable\n";
257                 table->Write(os);
258         }
259 #endif
260         // bibitem  ale970302
261         if (bibkey)
262                 bibkey->Write(buf, os);
263
264         LyXFont font1(LyXFont::ALL_INHERIT, params.language_info);
265
266         int column = 0;
267         for (size_type i = 0; i < size(); ++i) {
268                 if (!i) {
269                         os << "\n";
270                         column = 0;
271                 }
272                 
273                 // Write font changes
274                 LyXFont font2 = GetFontSettings(params, i);
275                 if (font2 != font1) {
276                         font2.lyxWriteChanges(font1, os);
277                         column = 0;
278                         font1 = font2;
279                 }
280
281                 value_type c = GetChar(i);
282                 switch (c) {
283                 case META_INSET:
284                 {
285                         Inset const * inset = GetInset(i);
286                         if (inset)
287                                 if (inset->DirectWrite()) {
288                                         // international char, let it write
289                                         // code directly so it's shorter in
290                                         // the file
291                                         inset->Write(buf, os);
292                                 } else {
293                                         os << "\n\\begin_inset ";
294                                         inset->Write(buf, os);
295                                         os << "\n\\end_inset \n\n";
296                                         column = 0;
297                                 }
298                 }
299                 break;
300                 case META_NEWLINE: 
301                         os << "\n\\newline \n";
302                         column = 0;
303                         break;
304                 case META_HFILL: 
305                         os << "\n\\hfill \n";
306                         column = 0;
307                         break;
308                 case '\\':
309                         os << "\n\\backslash \n";
310                         column = 0;
311                         break;
312                 case '.':
313                         if (i + 1 < size() && GetChar(i + 1) == ' ') {
314                                 os << ".\n";
315                                 column = 0;
316                         } else
317                                 os << ".";
318                         break;
319                 default:
320                         if ((column > 70 && c == ' ')
321                             || column > 79) {
322                                 os << "\n";
323                                 column = 0;
324                         }
325                         // this check is to amend a bug. LyX sometimes
326                         // inserts '\0' this could cause problems.
327                         if (c != '\0')
328                                 os << c;
329                         else
330                                 lyxerr << "ERROR (LyXParagraph::writeFile):"
331                                         " NULL char in structure." << endl;
332                         ++column;
333                         break;
334                 }
335         }
336
337         // now write the next paragraph
338         if (next)
339                 next->writeFile(buf, os, params, footflag, dth);
340 }
341
342
343 void LyXParagraph::validate(LaTeXFeatures & features) const
344 {
345         BufferParams const & params = features.bufferParams();
346
347 #ifndef NEW_INSETS
348         // this will be useful later
349         LyXLayout const & layout =
350                 textclasslist.Style(params.textclass, 
351                                     GetLayout());
352 #endif
353         
354         // check the params.
355         if (line_top || line_bottom)
356                 features.lyxline = true;
357         if (!spacing.isDefault())
358                 features.setspace = true;
359         
360         // then the layouts
361         features.layout[GetLayout()] = true;
362
363         // then the fonts
364         Language const * doc_language = params.language_info;
365         
366         for (FontList::const_iterator cit = fontlist.begin();
367              cit != fontlist.end(); ++cit) {
368                 if ((*cit).font.noun() == LyXFont::ON) {
369                         lyxerr[Debug::LATEX] << "font.noun: "
370                                              << (*cit).font.noun()
371                                              << endl;
372                         features.noun = true;
373                         lyxerr[Debug::LATEX] << "Noun enabled. Font: "
374                                              << (*cit).font.stateText(0)
375                                              << endl;
376                 }
377                 switch ((*cit).font.color()) {
378                 case LColor::none:
379                 case LColor::inherit:
380                 case LColor::ignore:
381                         break;
382                 default:
383                         features.color = true;
384                         lyxerr[Debug::LATEX] << "Color enabled. Font: "
385                                              << (*cit).font.stateText(0)
386                                              << endl;
387                 }
388
389                 Language const * language = (*cit).font.language();
390                 if (language != doc_language) {
391                         features.UsedLanguages.insert(language);
392                         lyxerr[Debug::LATEX] << "Found language "
393                                              << language->lang() << endl;
394                 }
395         }
396
397         // then the insets
398         for (InsetList::const_iterator cit = insetlist.begin();
399              cit != insetlist.end(); ++cit) {
400                 if ((*cit).inset)
401                         (*cit).inset->Validate(features);
402         }
403
404         if (table && table->IsLongTable())
405                 features.longtable = true;
406         if (pextra_type == PEXTRA_INDENT)
407                 features.LyXParagraphIndent = true;
408         if (pextra_type == PEXTRA_FLOATFLT)
409                 features.floatflt = true;
410 #ifndef NEW_INSETS
411         if (layout.needprotect 
412             && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
413                 features.NeedLyXFootnoteCode = true;
414 #endif
415         if (params.paragraph_separation == BufferParams::PARSEP_INDENT
416             && pextra_type == LyXParagraph::PEXTRA_MINIPAGE)
417                 features.NeedLyXMinipageIndent = true;
418         if (table && table->NeedRotating())
419                 features.rotating = true;
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                 !table){
1580                 while (Last()
1581                        && (IsNewline(0) || IsLineSeparator(0))){
1582                         Erase(0);
1583                         ++i;
1584                 }
1585         }
1586         return i;
1587 }
1588
1589
1590 LyXParagraph * LyXParagraph::Clone() const
1591 {
1592         // create a new paragraph
1593         LyXParagraph * result = new LyXParagraph;
1594    
1595         result->MakeSameLayout(this);
1596
1597         // this is because of the dummy layout of the paragraphs that
1598         // follow footnotes
1599         result->layout = layout;
1600
1601 #ifndef NEW_TABULAR
1602         /* table stuff -- begin*/ 
1603         if (table)
1604                 result->table = table->Clone();
1605         else
1606                 result->table = 0;
1607         /* table stuff -- end*/ 
1608 #endif
1609         result->inset_owner = inset_owner;
1610    
1611         // ale970302
1612         result->bibkey = (bibkey) ? new InsetBibKey(bibkey): 0;
1613                
1614     
1615         // copy everything behind the break-position to the new paragraph
1616
1617         result->text = text;
1618         result->fontlist = fontlist;
1619         result->insetlist = insetlist;
1620         for (InsetList::iterator it = result->insetlist.begin();
1621              it != result->insetlist.end(); ++it)
1622                 (*it).inset = (*it).inset->Clone();
1623         return result;
1624 }
1625
1626
1627 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1628 {
1629 #ifndef NEW_INSETS
1630         par = par->FirstPhysicalPar();
1631 #endif
1632
1633         return (
1634 #ifndef NEW_INSETS
1635                 par->footnoteflag == footnoteflag &&
1636                 par->footnotekind == footnotekind &&
1637 #endif
1638                 par->layout == layout &&
1639
1640                 par->align == align &&
1641
1642                 par->line_bottom == line_bottom &&
1643                 par->pagebreak_bottom == pagebreak_bottom &&
1644                 par->added_space_bottom == added_space_bottom &&
1645
1646                 par->line_top == line_top &&
1647                 par->pagebreak_top == pagebreak_top &&
1648                 par->added_space_top == added_space_top &&
1649
1650                 par->spacing == spacing &&
1651                 
1652                 par->pextra_type == pextra_type &&
1653                 par->pextra_width == pextra_width && 
1654                 par->pextra_widthp == pextra_widthp && 
1655                 par->pextra_alignment == pextra_alignment && 
1656                 par->pextra_hfill == pextra_hfill && 
1657                 par->pextra_start_minipage == pextra_start_minipage && 
1658 #ifndef NEW_TABULAR
1659                 par->table == table && // what means: NO TABLE AT ALL
1660 #endif
1661
1662                 par->noindent == noindent &&
1663                 par->depth == depth);
1664 }
1665
1666
1667 void LyXParagraph::BreakParagraphConservative(BufferParams const & bparams,
1668                                               LyXParagraph::size_type pos)
1669 {
1670         // create a new paragraph
1671         LyXParagraph * par = ParFromPos(pos);
1672
1673         LyXParagraph * tmp = new LyXParagraph(par);
1674    
1675         tmp->MakeSameLayout(par);
1676
1677         // When can pos < Last()?
1678         // I guess pos == Last() is possible.
1679         if (Last() > pos) {
1680                 // copy everything behind the break-position to the new
1681                 // paragraph
1682                 size_type pos_first = 0;
1683                 while (ParFromPos(pos_first) != par)
1684                         ++pos_first;
1685                 size_type pos_end = pos_first + par->text.size() - 1;
1686
1687                 size_type i, j;
1688                 for (i = j = pos; i <= pos_end; ++i) {
1689                         par->CutIntoMinibuffer(bparams, i - pos_first);
1690                         if (tmp->InsertFromMinibuffer(j - pos))
1691                                 ++j;
1692                 }
1693                 tmp->text.resize(tmp->text.size());
1694                 for (size_type i = pos_end; i >= pos; --i)
1695                         par->Erase(i - pos_first);
1696
1697                 par->text.resize(par->text.size());
1698         }
1699 }
1700    
1701
1702 // Be carefull, this does not make any check at all.
1703 void LyXParagraph::PasteParagraph(BufferParams const & bparams)
1704 {
1705         // copy the next paragraph to this one
1706         LyXParagraph * the_next = Next();
1707 #ifndef NEW_INSETS   
1708         LyXParagraph * firstpar = FirstPhysicalPar();
1709 #else
1710         LyXParagraph * firstpar = this;
1711 #endif
1712    
1713         // first the DTP-stuff
1714         firstpar->line_bottom = the_next->line_bottom;
1715         firstpar->added_space_bottom = the_next->added_space_bottom;
1716         firstpar->pagebreak_bottom = the_next->pagebreak_bottom;
1717
1718         size_type pos_end = the_next->text.size() - 1;
1719         size_type pos_insert = Last();
1720
1721         // ok, now copy the paragraph
1722         size_type i, j;
1723         for (i = j = 0; i <= pos_end; ++i) {
1724                 the_next->CutIntoMinibuffer(bparams, i);
1725                 if (InsertFromMinibuffer(pos_insert + j))
1726                         ++j;
1727         }
1728    
1729         // delete the next paragraph
1730         LyXParagraph * ppar = the_next->previous;
1731         LyXParagraph * npar = the_next->next;
1732         delete the_next;
1733         ppar->next = npar;
1734 }
1735
1736
1737 #ifndef NEW_INSETS
1738 void LyXParagraph::OpenFootnote(LyXParagraph::size_type pos)
1739 {
1740         LyXParagraph * par = ParFromPos(pos);
1741         par = par->next;
1742         while (par && par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1743                 par->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
1744                 par = par->next;
1745         }
1746 }
1747
1748
1749 void LyXParagraph::CloseFootnote(LyXParagraph::size_type pos)
1750 {
1751         LyXParagraph * par = ParFromPos(pos);
1752         par = par->next;
1753         while (par && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1754                 par->footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
1755                 par = par->next;
1756         }
1757 }
1758 #endif
1759
1760
1761 int LyXParagraph::GetEndLabel(BufferParams const & bparams) const
1762 {
1763         LyXParagraph const * par = this;
1764         int par_depth = GetDepth();
1765         while (par) {
1766                 LyXTextClass::LayoutList::size_type layout = par->GetLayout();
1767                 int endlabeltype =
1768                         textclasslist.Style(bparams.textclass,
1769                                             layout).endlabeltype;
1770                 if (endlabeltype != END_LABEL_NO_LABEL) {
1771                         LyXParagraph const * last = this;
1772 #ifndef NEW_INSETS
1773                         if( footnoteflag == NO_FOOTNOTE)
1774                                 last = LastPhysicalPar();
1775                         else if (next->footnoteflag == NO_FOOTNOTE)
1776                                 return endlabeltype;
1777 #else
1778                         last = this;
1779 #endif
1780
1781                         if (!last || !last->next)
1782                                 return endlabeltype;
1783
1784                         int next_depth = last->next->GetDepth();
1785                         if (par_depth > next_depth ||
1786                             (par_depth == next_depth && layout != last->next->GetLayout() ))
1787                                 return endlabeltype;
1788                         break;
1789                 }
1790                 if (par_depth == 0)
1791                         break;
1792                 par = par->DepthHook(par_depth - 1);
1793                 if (par)
1794                         par_depth = par->GetDepth();
1795         }
1796         return END_LABEL_NO_LABEL;
1797 }
1798
1799
1800 LyXTextClass::size_type LyXParagraph::GetLayout() const
1801 {
1802 #ifndef NEW_INSETS
1803         return FirstPhysicalPar()->layout;
1804 #else
1805         return layout;
1806 #endif
1807 }
1808
1809
1810 char LyXParagraph::GetDepth() const
1811 {
1812 #ifndef NEW_INSETS
1813         return FirstPhysicalPar()->depth;
1814 #else
1815         return depth;
1816 #endif
1817 }
1818
1819
1820 char LyXParagraph::GetAlign() const
1821 {
1822 #ifndef NEW_INSETS
1823         return FirstPhysicalPar()->align;
1824 #else
1825         return align;
1826 #endif
1827 }
1828
1829
1830 string const & LyXParagraph::GetLabelstring() const
1831 {
1832 #ifndef NEW_INSETS
1833         return FirstPhysicalPar()->labelstring;
1834 #else
1835         return labelstring;
1836 #endif
1837 }
1838
1839
1840 int LyXParagraph::GetFirstCounter(int i) const
1841 {
1842 #ifndef NEW_INSETS
1843         return FirstPhysicalPar()->counter_[i];
1844 #else
1845         return counter_[i];
1846 #endif
1847 }
1848
1849
1850 // the next two functions are for the manual labels
1851 string LyXParagraph::GetLabelWidthString() const
1852 {
1853 #ifndef NEW_INSETS
1854         if (!FirstPhysicalPar()->labelwidthstring.empty())
1855                 return FirstPhysicalPar()->labelwidthstring;
1856 #else
1857         if (!labelwidthstring.empty())
1858                 return labelwidthstring;
1859 #endif
1860         else
1861                 return _("Senseless with this layout!");
1862 }
1863
1864
1865 void LyXParagraph::SetLabelWidthString(string const & s)
1866 {
1867 #ifndef NEW_INSETS
1868         LyXParagraph * par = FirstPhysicalPar();
1869
1870         par->labelwidthstring = s;
1871 #else
1872         labelwidthstring = s;
1873 #endif
1874 }
1875
1876
1877 void LyXParagraph::SetOnlyLayout(BufferParams const & bparams,
1878                                  LyXTextClass::size_type new_layout)
1879 {
1880 #ifndef NEW_INSETS
1881         LyXParagraph * par = FirstPhysicalPar();
1882 #else
1883         LyXParagraph * par = this;
1884 #endif
1885         LyXParagraph * ppar = 0;
1886         LyXParagraph * npar = 0;
1887
1888         par->layout = new_layout;
1889 #ifndef NEW_TABULAR
1890         /* table stuff -- begin*/ 
1891         if (table) 
1892                 par->layout = 0;
1893         /* table stuff -- end*/
1894 #endif
1895         if (par->pextra_type == PEXTRA_NONE) {
1896                 if (par->Previous()) {
1897 #ifndef NEW_INSETS
1898                         ppar = par->Previous()->FirstPhysicalPar();
1899 #else
1900                         ppar = par->Previous();
1901 #endif
1902                         while(ppar
1903                               && ppar->Previous()
1904                               && (ppar->depth > par->depth))
1905 #ifndef NEW_INSETS
1906                                 ppar = ppar->Previous()->FirstPhysicalPar();
1907 #else
1908                         ppar = ppar->Previous();
1909 #endif
1910                 }
1911                 if (par->Next()) {
1912 #ifndef NEW_INSETS
1913                         npar = par->Next()->NextAfterFootnote();
1914 #else
1915                         npar = par->Next();
1916 #endif
1917                         while(npar
1918                               && npar->Next()
1919                               && (npar->depth > par->depth))
1920 #ifndef NEW_INSETS
1921                                 npar = npar->Next()->NextAfterFootnote();
1922 #else
1923                         npar = npar->Next();
1924 #endif
1925                 }
1926                 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
1927                         string
1928                                 p1 = ppar->pextra_width,
1929                                 p2 = ppar->pextra_widthp;
1930                         ppar->SetPExtraType(bparams, ppar->pextra_type,
1931                                             p1.c_str(), p2.c_str());
1932                 }
1933                 if ((par->pextra_type == PEXTRA_NONE) &&
1934                     npar && (npar->pextra_type != PEXTRA_NONE)) {
1935                         string
1936                                 p1 = npar->pextra_width,
1937                                 p2 = npar->pextra_widthp;
1938                         npar->SetPExtraType(bparams, npar->pextra_type,
1939                                             p1.c_str(), p2.c_str());
1940                 }
1941         }
1942 }
1943
1944
1945 void LyXParagraph::SetLayout(BufferParams const & bparams,
1946                              LyXTextClass::size_type new_layout)
1947 {
1948         LyXParagraph
1949 #ifndef NEW_INSETS
1950                 * par = FirstPhysicalPar(),
1951 #else
1952                 * par = this,
1953 #endif
1954                 * ppar = 0,
1955                 * npar = 0;
1956
1957         par->layout = new_layout;
1958         par->labelwidthstring.erase();
1959         par->align = LYX_ALIGN_LAYOUT;
1960         par->added_space_top = VSpace(VSpace::NONE);
1961         par->added_space_bottom = VSpace(VSpace::NONE);
1962         par->spacing.set(Spacing::Default);
1963
1964 #ifndef NEW_TABULAR
1965         /* table stuff -- begin*/ 
1966         if (table) 
1967                 par->layout = 0;
1968         /* table stuff -- end*/
1969 #endif
1970         if (par->pextra_type == PEXTRA_NONE) {
1971                 if (par->Previous()) {
1972 #ifndef NEW_INSETS
1973                         ppar = par->Previous()->FirstPhysicalPar();
1974 #else
1975                         ppar = par->Previous();
1976 #endif
1977                         while(ppar
1978                               && ppar->Previous()
1979                               && (ppar->depth > par->depth))
1980 #ifndef NEW_INSETS
1981                                 ppar = ppar->Previous()->FirstPhysicalPar();
1982 #else
1983                         ppar = ppar->Previous();
1984 #endif
1985                 }
1986                 if (par->Next()) {
1987 #ifndef NEW_INSETS
1988                         npar = par->Next()->NextAfterFootnote();
1989 #else
1990                         npar = par->Next();
1991 #endif
1992                         while(npar
1993                               && npar->Next()
1994                               && (npar->depth > par->depth))
1995 #ifndef NEW_INSETS
1996                                 npar = npar->Next()->NextAfterFootnote();
1997 #else
1998                         npar = npar->Next();
1999 #endif
2000                 }
2001                 if (ppar && (ppar->pextra_type != PEXTRA_NONE)) {
2002                         string
2003                                 p1 = ppar->pextra_width,
2004                                 p2 = ppar->pextra_widthp;
2005                         ppar->SetPExtraType(bparams, ppar->pextra_type,
2006                                             p1.c_str(), p2.c_str());
2007                 }
2008                 if ((par->pextra_type == PEXTRA_NONE) &&
2009                     npar && (npar->pextra_type != PEXTRA_NONE)) {
2010                         string
2011                                 p1 = npar->pextra_width,
2012                                 p2 = npar->pextra_widthp;
2013                         npar->SetPExtraType(bparams, npar->pextra_type,
2014                                             p1.c_str(), p2.c_str());
2015                 }
2016         }
2017 }
2018
2019
2020 // if the layout of a paragraph contains a manual label, the beginning of the 
2021 // main body is the beginning of the second word. This is what the par-
2022 // function returns. If the layout does not contain a label, the main
2023 // body always starts with position 0. This differentiation is necessary,
2024 // because there cannot be a newline or a blank <= the beginning of the 
2025 // main body in TeX.
2026
2027 int LyXParagraph::BeginningOfMainBody() const
2028 {
2029 #ifndef NEW_INSETS
2030         if (FirstPhysicalPar() != this)
2031                 return -1;
2032 #endif
2033         // Unroll the first two cycles of the loop
2034         // and remember the previous character to
2035         // remove unnecessary GetChar() calls
2036         size_type i = 0;
2037         if (i < size()
2038             && GetChar(i) != LyXParagraph::META_NEWLINE
2039                 ) {
2040                 ++i;
2041                 char previous_char = 0, temp = 0; 
2042                 if (i < size()
2043                     && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2044                         // Yes, this  ^ is supposed to be "= " not "=="
2045                         ++i;
2046                         while (i < size()
2047                                && previous_char != ' '
2048                                && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2049                                 ++i;
2050                                 previous_char = temp;
2051                         }
2052                 }
2053         }
2054
2055 #ifndef NEW_INSETS
2056         if (i == 0 && i == size() &&
2057             !(footnoteflag == LyXParagraph::NO_FOOTNOTE
2058               && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE))
2059                 ++i;                           /* the cursor should not jump  
2060                                                 * to the main body if there
2061                                                 * is nothing in! */
2062 #endif
2063         return i;
2064 }
2065
2066
2067 LyXParagraph * LyXParagraph::DepthHook(int deth)
2068 {
2069         LyXParagraph * newpar = this;
2070         if (deth < 0)
2071                 return 0;
2072    
2073         do {
2074 #ifndef NEW_INSETS
2075                 newpar = newpar->FirstPhysicalPar()->Previous();
2076 #else
2077                 newpar = newpar->Previous();
2078 #endif
2079         } while (newpar && newpar->GetDepth() > deth
2080 #ifndef NEW_INSETS
2081                  && newpar->footnoteflag == footnoteflag
2082 #endif
2083                 );
2084    
2085         if (!newpar) {
2086                 if (Previous() || GetDepth())
2087                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
2088                                 "no hook." << endl;
2089                 newpar = this;
2090         }
2091 #ifndef NEW_INSETS
2092         return newpar->FirstPhysicalPar();
2093 #else
2094         return newpar;
2095 #endif
2096 }
2097
2098
2099 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
2100 {
2101         LyXParagraph const * newpar = this;
2102         if (deth < 0)
2103                 return 0;
2104    
2105         do {
2106 #ifndef NEW_INSETS
2107                 newpar = newpar->FirstPhysicalPar()->Previous();
2108 #else
2109                 newpar = newpar->Previous();
2110 #endif
2111         } while (newpar && newpar->GetDepth() > deth
2112 #ifndef NEW_INSETS
2113                  && newpar->footnoteflag == footnoteflag
2114 #endif
2115                 );
2116    
2117         if (!newpar) {
2118                 if (Previous() || GetDepth())
2119                         lyxerr << "ERROR (LyXParagraph::DepthHook): "
2120                                 "no hook." << endl;
2121                 newpar = this;
2122         }
2123 #ifndef NEW_INSETS
2124         return newpar->FirstPhysicalPar();
2125 #else
2126         return newpar;
2127 #endif
2128 }
2129
2130
2131 int LyXParagraph::AutoDeleteInsets()
2132 {
2133         int count = 0;
2134         InsetList::size_type index = 0;
2135         while (index < insetlist.size()) {
2136                 if (insetlist[index].inset && insetlist[index].inset->AutoDelete()) {
2137                         Erase(insetlist[index].pos); 
2138                         // Erase() calls to insetlist.erase(&insetlist[index])
2139                         // so index shouldn't be increased.
2140                         ++count;
2141                 } else
2142                         ++index;
2143         }
2144         return count;
2145 }
2146
2147
2148 LyXParagraph::inset_iterator
2149 LyXParagraph::InsetIterator(LyXParagraph::size_type pos)
2150 {
2151         InsetTable search_inset(pos, 0);
2152         InsetList::iterator it = lower_bound(insetlist.begin(),
2153                                              insetlist.end(),
2154                                              search_inset, matchIT());
2155         return inset_iterator(it);
2156 }
2157
2158
2159 // returns -1 if inset not found
2160 int LyXParagraph::GetPositionOfInset(Inset * inset) const
2161 {
2162         // Find the entry.
2163         // We could use lower_bound here too, we just need to add
2164         // the approp. operator() to matchIT (and change the name
2165         // of that struct). Code would then be:
2166         // InsetList::const_iterator cit = lower_bound(insetlist.begin(),
2167         //                                             insetlist.end(),
2168         //                                             inset, matchIT());
2169         // if ((*cit).inset == inset) {
2170         //         return (*cit).pos;
2171         // }
2172         for (InsetList::const_iterator cit = insetlist.begin();
2173              cit != insetlist.end(); ++cit) {
2174                 if ((*cit).inset == inset) {
2175                         return (*cit).pos;
2176                 }
2177         }
2178 #ifndef NEW_INSETS
2179         // Think about footnotes.
2180         if (footnoteflag == LyXParagraph::NO_FOOTNOTE 
2181             && next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2182                 int further = 
2183                         NextAfterFootnote()->GetPositionOfInset(inset);
2184                 if (further != -1)
2185                         return text.size() + 1 + further;
2186         }
2187 #endif
2188         return -1;
2189 }
2190
2191
2192 LyXParagraph * LyXParagraph::TeXOnePar(Buffer const * buf,
2193                                        BufferParams const & bparams,
2194                                        ostream & os, TexRow & texrow,
2195                                        bool moving_arg
2196 #ifndef NEW_INSETS
2197                                        , 
2198                                        ostream & foot,
2199                                        TexRow & foot_texrow,
2200                                        int & foot_count
2201 #endif
2202         )
2203 {
2204         lyxerr[Debug::LATEX] << "TeXOnePar...     " << this << endl;
2205         LyXLayout const & style =
2206                 textclasslist.Style(bparams.textclass,
2207                                     layout);
2208
2209         bool further_blank_line = false;
2210 #ifndef NEW_INSETS
2211         if (IsDummy())
2212                 lyxerr << "ERROR (LyXParagraph::TeXOnePar) is dummy." << endl;
2213 #endif
2214
2215         if (start_of_appendix) {
2216                 os << "\\appendix\n";
2217                 texrow.newline();
2218         }
2219
2220         if (!spacing.isDefault()
2221             && (!Previous() || !Previous()->HasSameLayout(this))) {
2222                 os << spacing.writeEnvirBegin() << "\n";
2223                 texrow.newline();
2224         }
2225         
2226         if (tex_code_break_column && style.isCommand()){
2227                 os << '\n';
2228                 texrow.newline();
2229         }
2230
2231         if (pagebreak_top) {
2232                 os << "\\newpage";
2233                 further_blank_line = true;
2234         }
2235         if (added_space_top.kind() != VSpace::NONE) {
2236                 os << added_space_top.asLatexCommand(bparams);
2237                 further_blank_line = true;
2238         }
2239       
2240         if (line_top) {
2241                 os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
2242                    << "\\vspace{-1\\parskip}";
2243                 further_blank_line = true;
2244         }
2245
2246         if (further_blank_line){
2247                 os << '\n';
2248                 texrow.newline();
2249         }
2250
2251         Language const * language = getParLanguage(bparams);
2252         Language const * doc_language = bparams.language_info;
2253         Language const * previous_language = previous
2254                 ? previous->getParLanguage(bparams) : doc_language;
2255         if (language != doc_language && language != previous_language) {
2256                 os << subst(lyxrc.language_command_begin, "$$lang",
2257                             language->lang())
2258                    << endl;
2259                 texrow.newline();
2260         }
2261
2262         if (bparams.inputenc == "auto" &&
2263             language->encoding() != previous_language->encoding()) {
2264                 os << "\\inputencoding{"
2265                    << language->encoding()->LatexName()
2266                    << "}" << endl;
2267                 texrow.newline();
2268         }
2269         
2270         switch (style.latextype) {
2271         case LATEX_COMMAND:
2272                 os << '\\'
2273                    << style.latexname()
2274                    << style.latexparam();
2275                 break;
2276         case LATEX_ITEM_ENVIRONMENT:
2277                 if (bibkey) {
2278                         bibkey->Latex(buf, os, false, false);
2279                 } else
2280                         os << "\\item ";
2281                 break;
2282         case LATEX_LIST_ENVIRONMENT:
2283                 os << "\\item ";
2284                 break;
2285         default:
2286                 break;
2287         }
2288
2289         bool need_par = SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2290  
2291         LyXParagraph * par = next;
2292 #ifndef NEW_INSETS
2293         // Spit out footnotes
2294         if (lyxrc.rtl_support) {
2295                 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2296                     && next->footnoteflag != footnoteflag) {
2297                         LyXParagraph * p = 0;
2298                         bool is_rtl = (size() > 0) 
2299                                 ? GetFontSettings(bparams,
2300                                                   size()-1).isRightToLeft()
2301                                 : language->RightToLeft();
2302                         if ( (p = NextAfterFootnote()) != 0 &&
2303                              p->size() > 0 &&
2304                              p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2305                                 is_rtl = getParLanguage(bparams)->RightToLeft();
2306                         while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2307                                && par->footnoteflag != footnoteflag) {
2308                                 par = par->TeXFootnote(buf, bparams,
2309                                                        os, texrow, foot,
2310                                                        foot_texrow, foot_count,
2311                                                        is_rtl);
2312                                 par->SimpleTeXOnePar(buf, bparams,
2313                                                      os, texrow, moving_arg);
2314                                 is_rtl = (par->size() > 0)
2315                                         ? par->GetFontSettings(bparams,
2316                                                                par->size()-1).isRightToLeft()
2317                                         : language->RightToLeft();
2318                                 if (par->next &&
2319                                     par->next->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2320                                     (p = par->NextAfterFootnote()) != 0 &&
2321                                     p->size() > 0 &&
2322                                     p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2323                                         is_rtl = language->RightToLeft();
2324                                 par = par->next;
2325                         }
2326                 }
2327         } else {
2328                 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2329                        && par->footnoteflag != footnoteflag) {
2330                         par = par->TeXFootnote(buf, bparams,
2331                                                os, texrow,
2332                                                foot, foot_texrow, foot_count,
2333                                                false);
2334                         par->SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2335                         par = par->next;
2336                 }
2337         }
2338 #endif
2339
2340         // Make sure that \\par is done with the font of the last
2341         // character if this has another size as the default.
2342         // This is necessary because LaTeX (and LyX on the screen)
2343         // calculates the space between the baselines according
2344         // to this font. (Matthias)
2345         LyXFont font = getFont(bparams, Last() - 1);
2346         if (need_par) {
2347                 if (style.resfont.size() != font.size()) {
2348                         os << '\\'
2349                            << font.latexSize()
2350                            << ' ';
2351                 }
2352                 os << "\\par}";
2353         } else if (textclasslist.Style(bparams.textclass,
2354                                        GetLayout()).isCommand()) {
2355                 if (style.resfont.size() != font.size()) {
2356                         os << '\\'
2357                            << font.latexSize()
2358                            << ' ';
2359                 }
2360                 os << '}';
2361         } else if (style.resfont.size() != font.size()){
2362                 os << "{\\" << font.latexSize() << " \\par}";
2363         }
2364
2365         if (language != doc_language &&
2366             (!par
2367 #ifndef NEW_INSETS
2368              || (footnoteflag != NO_FOOTNOTE && par->footnoteflag != footnoteflag)
2369 #endif
2370              || par->getParLanguage(bparams) != language)) {
2371                 os << endl 
2372                    << subst(lyxrc.language_command_end, "$$lang",
2373                             doc_language->lang());
2374         }
2375         
2376         switch (style.latextype) {
2377         case LATEX_ITEM_ENVIRONMENT:
2378         case LATEX_LIST_ENVIRONMENT:
2379                 if (par && (depth < par->depth)) {
2380                         os << '\n';
2381                         texrow.newline();
2382                 }
2383                 break;
2384         case LATEX_ENVIRONMENT:
2385                 // if its the last paragraph of the current environment
2386                 // skip it otherwise fall through
2387                 if (par
2388                     && (par->layout != layout
2389                         || par->depth != depth
2390                         || par->pextra_type != pextra_type))
2391                         break;
2392         default:
2393                 // we don't need it for the last paragraph!!!
2394                 if (next
2395                     && !(
2396 #ifndef NEW_INSETS
2397                             footnoteflag != LyXParagraph::NO_FOOTNOTE
2398                       && footnotekind != LyXParagraph::FOOTNOTE
2399                       && footnotekind != LyXParagraph::MARGIN &&
2400 #endif
2401                       (table
2402                           || (par
2403                               && par->table)))) {
2404                         // don't insert this if we would be adding it
2405                         // before or after a table in a float.  This 
2406                         // little trick is needed in order to allow
2407                         // use of tables in \subfigures or \subtables.
2408                         os << '\n';
2409                         texrow.newline();
2410                 }
2411         }
2412         
2413         further_blank_line = false;
2414         if (line_bottom) {
2415                 os << "\\lyxline{\\" << getFont(bparams, Last() - 1).latexSize() << '}';
2416                 further_blank_line = true;
2417         }
2418
2419         if (added_space_bottom.kind() != VSpace::NONE) {
2420                 os << added_space_bottom.asLatexCommand(bparams);
2421                 further_blank_line = true;
2422         }
2423       
2424         if (pagebreak_bottom) {
2425                 os << "\\newpage";
2426                 further_blank_line = true;
2427         }
2428
2429         if (further_blank_line){
2430                 os << '\n';
2431                 texrow.newline();
2432         }
2433
2434         if (!spacing.isDefault()
2435             && (!par || !par->HasSameLayout(this))) {
2436                 os << spacing.writeEnvirEnd() << "\n";
2437                 texrow.newline();
2438         }
2439         
2440         // we don't need it for the last paragraph!!!
2441         if (next
2442 #ifndef NEW_INSETS
2443             && !(footnoteflag != LyXParagraph::NO_FOOTNOTE && par &&
2444               par->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2445 #endif
2446                 ) {
2447                 os << '\n';
2448                 texrow.newline();
2449         }
2450
2451         lyxerr[Debug::LATEX] << "TeXOnePar...done " << par << endl;
2452         return par;
2453 }
2454
2455
2456 // This one spits out the text of the paragraph
2457 bool LyXParagraph::SimpleTeXOnePar(Buffer const * buf,
2458                                    BufferParams const & bparams,
2459                                    ostream & os, TexRow & texrow,
2460                                    bool moving_arg)
2461 {
2462         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...     " << this << endl;
2463
2464 #ifndef NEW_TABULAR
2465         if (table)
2466                 return SimpleTeXOneTablePar(buf, bparams, os, texrow);
2467 #endif
2468
2469         bool return_value = false;
2470
2471         LyXLayout const & style =
2472                 textclasslist.Style(bparams.textclass,
2473                                     GetLayout());
2474         LyXFont basefont, last_font;
2475
2476         // Maybe we have to create a optional argument.
2477         size_type main_body;
2478         if (style.labeltype != LABEL_MANUAL)
2479                 main_body = 0;
2480         else
2481                 main_body = BeginningOfMainBody();
2482
2483         if (main_body > 0) {
2484                 os << '[';
2485                 basefont = getFont(bparams, -2); // Get label font
2486         } else {
2487                 basefont = getFont(bparams, -1); // Get layout font
2488         }
2489
2490         int column = 0;
2491
2492         if (main_body >= 0
2493             && !text.size()
2494 #ifndef NEW_INSETS
2495             && !IsDummy()
2496 #endif
2497                 ) {
2498                 if (style.isCommand()) {
2499                         os << '{';
2500                         ++column;
2501                 } else if (align != LYX_ALIGN_LAYOUT) {
2502                         os << '{';
2503                         ++column;
2504                         return_value = true;
2505                 }
2506         }
2507
2508         moving_arg |= style.needprotect;
2509  
2510         // Which font is currently active?
2511         LyXFont running_font(basefont);
2512         // Do we have an open font change?
2513         bool open_font = false;
2514
2515         texrow.start(this, 0);
2516
2517         for (size_type i = 0; i < size(); ++i) {
2518                 ++column;
2519                 // First char in paragraph or after label?
2520                 if (i == main_body
2521 #ifndef NEW_INSETS
2522                     && !IsDummy()
2523 #endif
2524                         ) {
2525                         if (main_body > 0) {
2526                                 if (open_font) {
2527                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
2528                                         open_font = false;
2529                                 }
2530                                 basefont = getFont(bparams, -1); // Now use the layout font
2531                                 running_font = basefont;
2532                                 os << ']';
2533                                 ++column;
2534                         }
2535                         if (style.isCommand()) {
2536                                 os << '{';
2537                                 ++column;
2538                         } else if (align != LYX_ALIGN_LAYOUT) {
2539                                 os << "{\\par";
2540                                 column += 4;
2541                                 return_value = true;
2542                         }
2543
2544                         if (noindent) {
2545                                 os << "\\noindent ";
2546                                 column += 10;
2547                         }
2548                         switch (align) {
2549                         case LYX_ALIGN_NONE:
2550                         case LYX_ALIGN_BLOCK:
2551                         case LYX_ALIGN_LAYOUT:
2552                         case LYX_ALIGN_SPECIAL:
2553                                 break;
2554                         case LYX_ALIGN_LEFT:
2555                                 if (getParLanguage(bparams)->lang() != "hebrew") {
2556                                         os << "\\raggedright ";
2557                                         column+= 13;
2558                                 } else {
2559                                         os << "\\raggedleft ";
2560                                         column+= 12;
2561                                 }
2562                                 break;
2563                         case LYX_ALIGN_RIGHT:
2564                                 if (getParLanguage(bparams)->lang() != "hebrew") {
2565                                         os << "\\raggedleft ";
2566                                         column+= 12;
2567                                 } else {
2568                                         os << "\\raggedright ";
2569                                         column+= 13;
2570                                 }
2571                                 break;
2572                         case LYX_ALIGN_CENTER:
2573                                 os << "\\centering ";
2574                                 column+= 11;
2575                                 break;
2576                         }        
2577                 }
2578
2579                 value_type c = GetChar(i);
2580
2581                 // Fully instantiated font
2582                 LyXFont font = getFont(bparams, i);
2583                 LyXParagraph * p = 0;
2584                 if (i == 0
2585 #ifndef NEW_INSETS
2586                     && previous && 
2587                     previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2588                     (p = PreviousBeforeFootnote()) != 0)
2589 #else
2590                         && (p = previous))
2591 #endif
2592                         last_font = p->getFont(bparams, p->size() - 1);
2593                 else
2594                         last_font = running_font;
2595
2596                 // Spaces at end of font change are simulated to be
2597                 // outside font change, i.e. we write "\textXX{text} "
2598                 // rather than "\textXX{text }". (Asger)
2599                 if (open_font && c == ' ' && i <= size() - 2 
2600                     && !getFont(bparams, i + 1).equalExceptLatex(running_font) 
2601                     && !getFont(bparams, i + 1).equalExceptLatex(font)) {
2602                         font = getFont(bparams, i + 1);
2603                 }
2604                 // We end font definition before blanks
2605                 if (!font.equalExceptLatex(running_font) && open_font) {
2606                         column += running_font.latexWriteEndChanges(os,
2607                                                                     basefont,
2608                                                                     (i == main_body-1) ? basefont : font);
2609                         running_font = basefont;
2610                         open_font = false;
2611                 }
2612
2613                 // Blanks are printed before start of fontswitch
2614                 if (c == ' ') {
2615                         // Do not print the separation of the optional argument
2616                         if (i != main_body - 1) {
2617                                 SimpleTeXBlanks(os, texrow, i,
2618                                                 column, font, style);
2619                         }
2620                 }
2621
2622                 // Do we need to change font?
2623                 if (!font.equalExceptLatex(running_font)
2624                     && i != main_body-1) {
2625                         column += font.latexWriteStartChanges(os, basefont,
2626                                                               last_font);
2627                         running_font = font;
2628                         open_font = true;
2629                 }
2630
2631                 if (c == LyXParagraph::META_NEWLINE) {
2632                         // newlines are handled differently here than
2633                         // the default in SimpleTeXSpecialChars().
2634                         if (!style.newline_allowed
2635                             || font.latex() == LyXFont::ON) {
2636                                 os << '\n';
2637                         } else {
2638                                 if (open_font) {
2639                                         column += running_font.latexWriteEndChanges(os, basefont, basefont);
2640                                         open_font = false;
2641                                 }
2642                                 basefont = getFont(bparams, -1);
2643                                 running_font = basefont;
2644                                 if (font.family() == 
2645                                     LyXFont::TYPEWRITER_FAMILY) {
2646                                         os << "~";
2647                                 }
2648                                 if (moving_arg)
2649                                         os << "\\protect ";
2650                                 os << "\\\\\n";
2651                         }
2652                         texrow.newline();
2653                         texrow.start(this, i + 1);
2654                         column = 0;
2655                 } else {
2656                         SimpleTeXSpecialChars(buf, bparams,
2657                                               os, texrow, moving_arg,
2658                                               font, running_font, basefont,
2659                                               open_font, style, i, column, c);
2660                 }
2661         }
2662
2663         // If we have an open font definition, we have to close it
2664         if (open_font) {
2665                 LyXParagraph * p = 0;
2666                 if (next
2667 #ifndef NEW_INSETS
2668                     && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2669                     && (p =  NextAfterFootnote()) != 0
2670 #else
2671                         && (p = next)
2672 #endif
2673                 )
2674                         running_font.latexWriteEndChanges(os, basefont,
2675                                                           p->getFont(bparams, 0));
2676                 else
2677                         running_font.latexWriteEndChanges(os, basefont, basefont);
2678         }
2679
2680         // Needed if there is an optional argument but no contents.
2681         if (main_body > 0 && main_body == size()) {
2682                 os << "]~";
2683                 return_value = false;
2684         }
2685
2686         lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
2687         return return_value;
2688 }
2689
2690
2691 // This one spits out the text of a table paragraph
2692 bool LyXParagraph::SimpleTeXOneTablePar(Buffer const * buf,
2693                                         BufferParams const & bparams,
2694                                         ostream & os, TexRow & texrow)
2695 {
2696         lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar...     " << this << endl;
2697    
2698         bool return_value = false;
2699
2700         LyXLayout const & style = 
2701                 textclasslist.Style(bparams.textclass, GetLayout());
2702  
2703         int column = 0;
2704 #ifndef NEW_INSETS
2705         if (!IsDummy()) { // it is dummy if it is in a float!!!
2706 #endif
2707                 if (style.isCommand()) {
2708                         os << '{';
2709                         ++column;
2710                 } else if (align != LYX_ALIGN_LAYOUT) {
2711                         os << '{';
2712                         ++column;
2713                         return_value = true;
2714                 }
2715                 if (noindent) {
2716                         os << "\\noindent ";
2717                         column += 10;
2718                 }
2719                 switch (align) {
2720                 case LYX_ALIGN_NONE:
2721                 case LYX_ALIGN_BLOCK:
2722                 case LYX_ALIGN_LAYOUT:
2723                 case LYX_ALIGN_SPECIAL: break;
2724                 case LYX_ALIGN_LEFT:
2725                         os << "\\raggedright ";
2726                         column+= 13;
2727                         break;
2728                 case LYX_ALIGN_RIGHT:
2729                         os << "\\raggedleft ";
2730                         column+= 12;
2731                         break;
2732                 case LYX_ALIGN_CENTER:
2733                         os << "\\centering ";
2734                         column+= 11;
2735                         break;
2736                 }
2737 #ifndef NEW_INSETS
2738         }
2739 #endif
2740
2741         LyXFont basefont = getFont(bparams, -1); // Get layout font
2742         // Which font is currently active?
2743         LyXFont running_font = basefont;
2744         LyXFont last_font;
2745         // Do we have an open font change?
2746         bool open_font = false;
2747         int current_cell_number = -1;
2748         int tmp = table->TexEndOfCell(os, current_cell_number);
2749         for (; tmp > 0 ; --tmp)
2750                 texrow.newline();
2751         
2752         texrow.start(this, 0);
2753
2754         bool is_rtl = getParLanguage(bparams)->RightToLeft();
2755         bool first_in_cell = true;
2756                 
2757         for (size_type i = 0; i < size(); ++i) {
2758                 value_type c = GetChar(i);
2759                 if (table->IsContRow(current_cell_number + 1)) {
2760                         if (c == LyXParagraph::META_NEWLINE)
2761                                 ++current_cell_number;
2762                         continue;
2763                 }
2764                 ++column;
2765
2766                 if (first_in_cell && is_rtl) {
2767                         os << "\\R{";
2768                         column += 3;
2769                         first_in_cell = false;
2770                 }
2771
2772                 // Fully instantiated font
2773                 LyXFont font = getFont(bparams, i);
2774                 last_font = running_font;
2775
2776                 // Spaces at end of font change are simulated to be
2777                 // outside font change.
2778                 // i.e. we write "\textXX{text} " rather than
2779                 // "\textXX{text }". (Asger)
2780                 if (open_font && c == ' ' && i <= size() - 2
2781                     && getFont(bparams, i + 1) != running_font
2782                     && getFont(bparams, i + 1) != font) {
2783                         font = getFont(bparams, i + 1);
2784                 }
2785
2786                 // We end font definition before blanks
2787                 if (font != running_font && open_font) {
2788                         column += running_font.latexWriteEndChanges(os,
2789                                                                     basefont,
2790                                                                     font);
2791                         running_font = basefont;
2792                         open_font = false;
2793                 }
2794                 // Blanks are printed before start of fontswitch
2795                 if (c == ' ') {
2796                         SimpleTeXBlanks(os, texrow, i, column, font, style);
2797                 }
2798                 // Do we need to change font?
2799                 if (font != running_font) {
2800                         column += font.latexWriteStartChanges(os, basefont,
2801                                                               last_font);
2802                         running_font = font;
2803                         open_font = true;
2804                 }
2805                 // Do we need to turn on LaTeX mode?
2806                 if (font.latex() != running_font.latex()) {
2807                         if (font.latex() == LyXFont::ON
2808                             && style.needprotect) {
2809                                 os << "\\protect ";
2810                                 column += 9;
2811                         }
2812                 }
2813                 if (c == LyXParagraph::META_NEWLINE) {
2814                         // special case for inside a table
2815                         // different from default case in
2816                         // SimpleTeXSpecialChars()
2817                         if (open_font) {
2818                                 column += running_font
2819                                         .latexWriteEndChanges(os, basefont,
2820                                                               basefont);
2821                                 open_font = false;
2822                         }
2823                         basefont = getFont(bparams, -1);
2824                         running_font = basefont;
2825                         ++current_cell_number;
2826                         if (table->CellHasContRow(current_cell_number) >= 0) {
2827                                 TeXContTableRows(buf, bparams, os, i + 1,
2828                                                  current_cell_number,
2829                                                  column, texrow);
2830                         }
2831                         if (is_rtl && !first_in_cell) {
2832                                 os << "}";
2833                                 first_in_cell = true;
2834                         }
2835
2836                         // if this cell follow only ContRows till end don't
2837                         // put the EndOfCell because it is put after the
2838                         // for(...)
2839                         if (table->ShouldBeVeryLastCell(current_cell_number)) {
2840                                 --current_cell_number;
2841                                 break;
2842                         }
2843                         int tmp = table->TexEndOfCell(os,
2844                                                       current_cell_number);
2845                         if (tmp > 0) {
2846                                 column = 0;
2847                         } else if (tmp < 0) {
2848                                 tmp = -tmp;
2849                         }
2850                         for (; tmp--;) {
2851                                 texrow.newline();
2852                         }
2853                         texrow.start(this, i + 1);
2854                 } else {
2855                         SimpleTeXSpecialChars(buf, bparams,
2856                                               os, texrow, false,
2857                                               font, running_font, basefont,
2858                                               open_font, style, i, column, c);
2859                 }
2860         }
2861
2862         // If we have an open font definition, we have to close it
2863         if (open_font) {
2864                 running_font.latexWriteEndChanges(os, basefont, basefont);
2865         }
2866         ++current_cell_number;
2867         if (is_rtl && !first_in_cell)
2868                 os << "}";
2869         tmp = table->TexEndOfCell(os, current_cell_number);
2870         for (; tmp > 0; --tmp)
2871                 texrow.newline();
2872         lyxerr[Debug::LATEX] << "SimpleTeXOneTablePar...done " << this << endl;
2873         return return_value;
2874 }
2875
2876
2877 // This one spits out the text off ContRows in tables
2878 bool LyXParagraph::TeXContTableRows(Buffer const * buf,
2879                                     BufferParams const & bparams,
2880                                     ostream & os,
2881                                     LyXParagraph::size_type i,
2882                                     int current_cell_number,
2883                                     int & column, TexRow & texrow)
2884 {
2885         lyxerr[Debug::LATEX] << "TeXContTableRows...     " << this << endl;
2886         if (!table)
2887                 return false;
2888     
2889         bool return_value = false;
2890         LyXLayout const & style =
2891                 textclasslist.Style(bparams.textclass,
2892                                     GetLayout());
2893         LyXFont basefont = getFont(bparams, -1); // Get layout font
2894         LyXFont last_font;
2895         // Which font is currently active?
2896         LyXFont running_font = basefont;
2897         // Do we have an open font change?
2898         bool open_font = false;
2899
2900         size_type lastpos = i;
2901         int cell = table->CellHasContRow(current_cell_number);
2902         ++current_cell_number;
2903         value_type c;
2904         while(cell >= 0) {
2905                 // first find the right position
2906                 i = lastpos;
2907                 for (; (i < size()) && (current_cell_number < cell); ++i) {
2908                         c = GetChar(i);
2909                         if (c == LyXParagraph::META_NEWLINE)
2910                                 ++current_cell_number;
2911                 }
2912                 lastpos = i;
2913                 c = GetChar(i);
2914                 if (table->Linebreaks(table->FirstVirtualCell(cell))) {
2915                         os << " \\\\\n";
2916                         texrow.newline();
2917                         column = 0;
2918                 } else if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
2919                         os << ' ';
2920                 }
2921
2922                 for (; i < size()
2923                              && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
2924                      ++i) {
2925                         ++column;
2926
2927                         // Fully instantiated font
2928                         LyXFont font = getFont(bparams, i);
2929                         last_font = running_font;
2930
2931                         // Spaces at end of font change are simulated to
2932                         // be outside font change. i.e. we write
2933                         // "\textXX{text} " rather than "\textXX{text }".
2934                         // (Asger)
2935                         if (open_font && c == ' ' && i <= size() - 2 
2936                             && getFont(bparams, i + 1) != running_font
2937                             && getFont(bparams, i + 1) != font) {
2938                                 font = getFont(bparams, i + 1);
2939                         }
2940
2941                         // We end font definition before blanks
2942                         if (font != running_font && open_font) {
2943                                 column += running_font.latexWriteEndChanges(os, basefont, font);
2944                                 running_font = basefont;
2945                                 open_font = false;
2946                         }
2947                         // Blanks are printed before start of fontswitch
2948                         if (c == ' '){
2949                                 SimpleTeXBlanks(os, texrow, i,
2950                                                 column, font, style);
2951                         }
2952                         // Do we need to change font?
2953                         if (font != running_font) {
2954                                 column +=
2955                                         font.latexWriteStartChanges(os,
2956                                                                     basefont,
2957                                                                     last_font);
2958                                 running_font = font;
2959                                 open_font = true;
2960                         }
2961                         // Do we need to turn on LaTeX mode?
2962                         if (font.latex() != running_font.latex()) {
2963                                 if (font.latex() == LyXFont::ON
2964                                     && style.needprotect) {
2965                                         os << "\\protect ";
2966                                         column += 9;
2967                                 }
2968                         }
2969                         SimpleTeXSpecialChars(buf, bparams,
2970                                               os, texrow, false, font,
2971                                               running_font, basefont,
2972                                               open_font, style, i, column, c);
2973                 }
2974                 // If we have an open font definition, we have to close it
2975                 if (open_font) {
2976                         running_font.latexWriteEndChanges(os, basefont,
2977                                                           basefont);
2978                         open_font = false;
2979                 }
2980                 basefont = getFont(bparams, -1);
2981                 running_font = basefont;
2982                 cell = table->CellHasContRow(current_cell_number);
2983         }
2984         lyxerr[Debug::LATEX] << "TeXContTableRows...done " << this << endl;
2985         return return_value;
2986 }
2987
2988
2989 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
2990 {
2991         bool retval = false;
2992         switch (c) {
2993         case LyXParagraph::META_HFILL:
2994                 sgml_string.erase();
2995                 break;
2996         case LyXParagraph::META_NEWLINE:
2997                 sgml_string = '\n';
2998                 break;
2999         case '&': 
3000                 sgml_string = "&amp;";
3001                 break;
3002         case '<': 
3003                 sgml_string = "&lt;"; 
3004                 break;
3005         case '>':
3006                 sgml_string = "&gt;"; 
3007                 break;
3008         case '$': 
3009                 sgml_string = "&dollar;"; 
3010                 break;
3011         case '#': 
3012                 sgml_string = "&num;";
3013                 break;
3014         case '%': 
3015                 sgml_string = "&percnt;";
3016                 break;
3017         case '[': 
3018                 sgml_string = "&lsqb;";
3019                 break;
3020         case ']': 
3021                 sgml_string = "&rsqb;";
3022                 break;
3023         case '{': 
3024                 sgml_string = "&lcub;";
3025                 break;
3026         case '}': 
3027                 sgml_string = "&rcub;";
3028                 break;
3029         case '~': 
3030                 sgml_string = "&tilde;";
3031                 break;
3032         case '"': 
3033                 sgml_string = "&quot;";
3034                 break;
3035         case '\\': 
3036                 sgml_string = "&bsol;";
3037                 break;
3038         case ' ':
3039                 retval = true;
3040                 sgml_string = ' ';
3041                 break;
3042         case '\0': // Ignore :-)
3043                 sgml_string.erase();
3044                 break;
3045         default:
3046                 sgml_string = c;
3047                 break;
3048         }
3049         return retval;
3050 }
3051
3052
3053 void LyXParagraph::SimpleDocBookOneTablePar(Buffer const * buffer, 
3054                                             ostream & os, string & extra,
3055                                             int & desc_on, int depth) 
3056 {
3057         BufferParams const & bparams = buffer->params;
3058         if (!table) return;
3059         lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar... " << this << endl;
3060         int column = 0;
3061         LyXFont font1, font2;
3062         char c;
3063         Inset * inset;
3064         size_type main_body;
3065         bool emph_flag = false;
3066         
3067         LyXLayout const & style =
3068                 textclasslist.Style(bparams.textclass,
3069                                     GetLayout());
3070         
3071         if (style.labeltype != LABEL_MANUAL)
3072                 main_body = 0;
3073         else
3074                 main_body = BeginningOfMainBody();
3075         
3076         // Gets paragraph main font.
3077         if (main_body > 0)
3078                 font1 = style.labelfont;
3079         else
3080                 font1 = style.font;
3081         
3082         int char_line_count = depth;
3083         os << newlineAndDepth(depth);
3084 #ifndef NEW_INSETS
3085         if (footnoteflag == LyXParagraph::NO_FOOTNOTE) {
3086                 os << "<INFORMALTABLE>"
3087                    << newlineAndDepth(++depth);
3088         }
3089 #else
3090         os << "<INFORMALTABLE>"
3091            << newlineAndDepth(++depth);
3092 #endif
3093         int current_cell_number = -1;
3094         int tmp = table->DocBookEndOfCell(os, current_cell_number, depth);
3095         
3096         // Parsing main loop.
3097         for (size_type i = 0; i < size(); ++i) {
3098                 c = GetChar(i);
3099                 if (table->IsContRow(current_cell_number+1)) {
3100                         if (c == LyXParagraph::META_NEWLINE)
3101                                 ++current_cell_number;
3102                         continue;
3103                 }
3104                 ++column;
3105                 
3106                 // Fully instantiated font
3107                 font2 = getFont(bparams, i);
3108                 
3109                 // Handle <emphasis> tag.
3110                 if (font1.emph() != font2.emph() && i) {
3111                         if (font2.emph() == LyXFont::ON) {
3112                                 os << "<emphasis>";
3113                                 emph_flag= true;
3114                         } else if (emph_flag) {
3115                                 os << "</emphasis>";
3116                                 emph_flag= false;
3117                         }
3118                 }
3119                 if (c == LyXParagraph::META_NEWLINE) {
3120                         // We have only to control for emphasis open here!
3121                         if (emph_flag) {
3122                                 os << "</emphasis>";
3123                                 emph_flag= false;
3124                         }
3125                         font1 = font2 = getFont(bparams, -1);
3126                         ++current_cell_number;
3127                         if (table->CellHasContRow(current_cell_number) >= 0) {
3128                                 DocBookContTableRows(buffer,
3129                                                      os, extra, desc_on, i + 1,
3130                                                      current_cell_number,
3131                                                      column);
3132                         }
3133                         // if this cell follow only ContRows till end don't
3134                         // put the EndOfCell because it is put after the
3135                         // for(...)
3136                         if (table->ShouldBeVeryLastCell(current_cell_number)) {
3137                                 --current_cell_number;
3138                                 break;
3139                         }
3140                         tmp = table->DocBookEndOfCell(os,
3141                                                       current_cell_number,
3142                                                       depth);
3143                         
3144                         if (tmp > 0)
3145                                 column = 0;
3146                 } else if (c == LyXParagraph::META_INSET) {
3147                         inset = GetInset(i);
3148 #ifdef HAVE_SSTREAM
3149                         std::ostringstream ost;
3150                         inset->DocBook(buffer, ost);
3151                         string tmp_out = ost.str().c_str();
3152 #else
3153                         ostrstream ost;
3154                         inset->DocBook(buffer, ost);
3155                         ost << '\0';
3156                         char * ctmp = ost.str();
3157                         string tmp_out(ctmp);
3158                         delete [] ctmp;
3159 #endif
3160                         //
3161                         // This code needs some explanation:
3162                         // Two insets are treated specially
3163                         //   label if it is the first element in a
3164                         //   command paragraph
3165                         //         desc_on == 3
3166                         //   graphics inside tables or figure floats
3167                         //   can't go on
3168                         //   title (the equivalente in latex for this
3169                         //   case is caption
3170                         //   and title should come first
3171                         //         desc_on == 4
3172                         //
3173                         if(desc_on != 3 || i != 0) {
3174                                 if(tmp_out[0] == '@') {
3175                                         if(desc_on == 4)
3176                                                 extra += frontStrip(tmp_out,
3177                                                                     '@');
3178                                         else
3179                                                 os << frontStrip(tmp_out,
3180                                                                  '@');
3181                                 } else
3182                                         os << tmp_out;
3183                         }
3184                 } else if (font2.latex() == LyXFont::ON) {
3185                         // "TeX"-Mode on == > SGML-Mode on.
3186                         if (c != '\0')
3187                                 os << c;
3188                         ++char_line_count;
3189                 } else {
3190                         string sgml_string;
3191                         if (linuxDocConvertChar(c, sgml_string) 
3192                             && !style.free_spacing) {
3193                                 // in freespacing mode, spaces are
3194                                 // non-breaking characters
3195                                 // char is ' '
3196                                 if (desc_on == 1) {
3197                                         ++char_line_count;
3198                                         os << '\n'
3199                                            << "</term><listitem><para>";
3200                                         desc_on = 2;
3201                                 } else  {
3202                                         os << c;
3203                                 }
3204                         } else {
3205                                 os << sgml_string;
3206                         }
3207                 }
3208                 font1 = font2;
3209         }
3210         
3211         // Needed if there is an optional argument but no contents.
3212         if (main_body > 0 && main_body == size()) {
3213                 font1 = style.font;
3214         }
3215
3216         if (emph_flag) {
3217                 os << "</emphasis>";
3218         }
3219         
3220         ++current_cell_number;
3221         tmp = table->DocBookEndOfCell(os, current_cell_number, depth);
3222         // Resets description flag correctly.
3223         switch(desc_on){
3224         case 1:
3225                 // <term> not closed...
3226                 os << "</term>";
3227                 break;
3228         }
3229 #ifndef NEW_INSETS
3230         if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
3231 #endif
3232                 os << "</INFORMALTABLE>";
3233         os << '\n';
3234         lyxerr[Debug::LATEX] << "SimpleDocbookOneTablePar...done "
3235                              << this << endl;
3236 }
3237
3238
3239 void LyXParagraph::DocBookContTableRows(Buffer const * buffer,
3240                                         ostream & os, string & extra,
3241                                         int & desc_on,
3242                                         LyXParagraph::size_type i,
3243                                         int current_cell_number, int &column) 
3244
3245 {
3246         if (!table) return;
3247
3248         BufferParams const & bparams = buffer->params;
3249         
3250         lyxerr[Debug::LATEX] << "DocBookContTableRows... " << this << endl;
3251
3252         LyXFont font2;
3253         char c;
3254         Inset * inset;
3255         //string emph = "emphasis";
3256         bool emph_flag = false;
3257         int char_line_count = 0;
3258         
3259         LyXLayout const & style =
3260                 textclasslist.Style(bparams.textclass,
3261                                     GetLayout());
3262         
3263         size_type main_body;
3264         if (style.labeltype != LABEL_MANUAL)
3265                 main_body = 0;
3266         else
3267                 main_body = BeginningOfMainBody();
3268         
3269         // Gets paragraph main font.
3270         LyXFont font1;
3271         if (main_body > 0)
3272                 font1 = style.labelfont;
3273         else
3274                 font1 = style.font;
3275         
3276         size_type lastpos = i;
3277         int cell = table->CellHasContRow(current_cell_number);
3278         ++current_cell_number;
3279         while(cell >= 0) {
3280                 // first find the right position
3281                 i = lastpos;
3282                 for (; i < size() && current_cell_number < cell; ++i) {
3283                         c = GetChar(i);
3284                         if (c == LyXParagraph::META_NEWLINE)
3285                                 ++current_cell_number;
3286                 }
3287                 lastpos = i;
3288                 c = GetChar(i);
3289                 // I don't know how to handle this so I comment it
3290                 // for the moment (Jug)
3291 //             if (table->Linebreaks(table->FirstVirtualCell(cell))) {
3292 //                     file += " \\\\\n";
3293 //                     column = 0;
3294 //             } else
3295                 if ((c != ' ') && (c != LyXParagraph::META_NEWLINE)) {
3296                         os << ' ';
3297                 }
3298
3299                 for (; i < size()
3300                              && (c = GetChar(i)) != LyXParagraph::META_NEWLINE;
3301                      ++i) {
3302                         ++column;
3303                         
3304                         // Fully instantiated font
3305                         font2 = getFont(bparams, i);
3306                         
3307                         // Handle <emphasis> tag.
3308                         if (font1.emph() != font2.emph() && i) {
3309                                 if (font2.emph() == LyXFont::ON) {
3310                                         os << "<emphasis>";
3311                                         emph_flag= true;
3312                                 } else if (emph_flag) {
3313                                         os << "</emphasis>";
3314                                         emph_flag= false;
3315                                 }
3316                         }
3317                         if (c == LyXParagraph::META_INSET) {
3318                                 inset = GetInset(i);
3319 #ifdef HAVE_SSTREAM
3320                                 std::ostringstream ost;
3321                                 inset->DocBook(buffer, ost);
3322                                 string tmp_out = ost.str().c_str();
3323 #else
3324                                 ostrstream ost;
3325                                 inset->DocBook(buffer, ost);
3326                                 ost << '\0';
3327                                 char * ctmp = ost.str();
3328                                 string tmp_out(ctmp);
3329                                 delete [] ctmp;
3330 #endif
3331                                 //
3332                                 // This code needs some explanation:
3333                                 // Two insets are treated specially
3334                                 //   label if it is the first element in a
3335                                 //   command paragraph
3336                                 //       desc_on == 3
3337                                 //   graphics inside tables or figure floats
3338                                 //   can't go on title (the equivalente in
3339                                 //   latex for this case is caption and title
3340                                 //   should come first
3341                                 //       desc_on == 4
3342                                 //
3343                                 if(desc_on != 3 || i != 0) {
3344                                         if(tmp_out[0] == '@') {
3345                                                 if(desc_on == 4)
3346                                                         extra += frontStrip(tmp_out, '@');
3347                                                 else
3348                                                         os << frontStrip(tmp_out, '@');
3349                                         } else
3350                                                 os << tmp_out;
3351                                 }
3352                         } else if (font2.latex() == LyXFont::ON) {
3353                                 // "TeX"-Mode on == > SGML-Mode on.
3354                                 if (c!= '\0')
3355                                         os << c;
3356                                 ++char_line_count;
3357                         } else {
3358                                 string sgml_string;
3359                                 if (linuxDocConvertChar(c, sgml_string) 
3360                                     && !style.free_spacing) {
3361                                         // in freespacing mode, spaces are
3362                                         // non-breaking characters
3363                                         // char is ' '
3364                                         if (desc_on == 1) {
3365                                                 ++char_line_count;
3366                                                 os << '\n'
3367                                                    << "</term><listitem><para>";
3368                                                 desc_on = 2;
3369                                         } else  {
3370                                                 os << c;
3371                                         }
3372                                 } else {
3373                                         os << sgml_string;
3374                                 }
3375                         }
3376                 }
3377                 // we have only to control for emphasis open here!
3378                 if (emph_flag) {
3379                         os << "</emphasis>";
3380                         emph_flag= false;
3381                 }
3382                 font1 = font2 = getFont(bparams, -1);
3383                 cell = table->CellHasContRow(current_cell_number);
3384         }
3385         lyxerr[Debug::LATEX] << "DocBookContTableRows...done " << this << endl;
3386 }
3387
3388
3389 void LyXParagraph::SimpleTeXBlanks(ostream & os, TexRow & texrow,
3390                                    LyXParagraph::size_type const i,
3391                                    int & column, LyXFont const & font,
3392                                    LyXLayout const & style)
3393 {
3394         if (column > tex_code_break_column
3395             && i 
3396             && GetChar(i - 1) != ' '
3397             && (i < size() - 1)
3398             // In LaTeX mode, we don't want to
3399             // break lines since some commands
3400             // do not like this
3401             && ! (font.latex() == LyXFont::ON)
3402             // same in FreeSpacing mode
3403             && !style.free_spacing
3404             // In typewriter mode, we want to avoid 
3405             // ! . ? : at the end of a line
3406             && !(font.family() == LyXFont::TYPEWRITER_FAMILY
3407                  && (GetChar(i-1) == '.'
3408                      || GetChar(i-1) == '?' 
3409                      || GetChar(i-1) == ':'
3410                      || GetChar(i-1) == '!'))) {
3411                 if (tex_code_break_column == 0) {
3412                         // in batchmode we need LaTeX to still
3413                         // see it as a space not as an extra '\n'
3414                         os << " %\n";
3415                 } else {
3416                         os << '\n';
3417                 }
3418                 texrow.newline();
3419                 texrow.start(this, i + 1);
3420                 column = 0;
3421         } else if (font.latex() == LyXFont::OFF) {
3422                 if (style.free_spacing) {
3423                         os << '~';
3424                 } else {
3425                         os << ' ';
3426                 }
3427         }
3428 }
3429
3430
3431 void LyXParagraph::SimpleTeXSpecialChars(Buffer const * buf,
3432                                          BufferParams const & bparams,
3433                                          ostream & os, TexRow & texrow,
3434                                          bool moving_arg,
3435                                          LyXFont & font,
3436                                          LyXFont & running_font,
3437                                          LyXFont & basefont,
3438                                          bool & open_font,
3439                                          LyXLayout const & style,
3440                                          LyXParagraph::size_type & i,
3441                                          int & column,
3442                                          LyXParagraph::value_type const c)
3443 {
3444         // Two major modes:  LaTeX or plain
3445         // Handle here those cases common to both modes
3446         // and then split to handle the two modes separately.
3447         switch (c) {
3448         case LyXParagraph::META_INSET: {
3449                 Inset * inset = GetInset(i);
3450                 if (inset) {
3451                         bool close = false;
3452                         int len = os.tellp();
3453                         if ((inset->LyxCode() == Inset::GRAPHICS_CODE
3454                              || inset->LyxCode() == Inset::MATH_CODE
3455                              || inset->LyxCode() == Inset::URL_CODE)
3456                             && running_font.isRightToLeft()) {
3457                                 os << "\\L{";
3458                                 close = true;
3459                         }
3460
3461                         int tmp = inset->Latex(buf, os, moving_arg,
3462                                                style.free_spacing);
3463
3464                         if (close)
3465                                 os << "}";
3466
3467                         if (tmp) {
3468                                 column = 0;
3469                         } else {
3470                                 column += os.tellp() - len;
3471                         }
3472                         for (; tmp--;) {
3473                                 texrow.newline();
3474                         }
3475                 }
3476         }
3477         break;
3478
3479         case LyXParagraph::META_NEWLINE:
3480                 if (open_font) {
3481                         column += running_font.latexWriteEndChanges(os,
3482                                                                     basefont,
3483                                                                     basefont);
3484                         open_font = false;
3485                 }
3486                 basefont = getFont(bparams, -1);
3487                 running_font = basefont;
3488                 break;
3489
3490         case LyXParagraph::META_HFILL: 
3491                 os << "\\hfill{}";
3492                 column += 7;
3493                 break;
3494
3495         default:
3496                 // And now for the special cases within each mode
3497                 // Are we in LaTeX mode?
3498                 if (font.latex() == LyXFont::ON) {
3499                         // at present we only have one option
3500                         // but I'll leave it as a switch statement
3501                         // so its simpler to extend. (ARRae)
3502                         switch (c) {
3503                         default:
3504                                 // make sure that we will not print
3505                                 // error generating chars to the tex
3506                                 // file. This test would not be needed
3507                                 // if it were done in the buffer
3508                                 // itself.
3509                                 if (c != '\0') {
3510                                         os << c;
3511                                 }
3512                                 break;
3513                         }
3514                 } else {
3515                         // Plain mode (i.e. not LaTeX)
3516                         switch (c) {
3517                         case '\\': 
3518                                 os << "\\textbackslash{}";
3519                                 column += 15;
3520                                 break;
3521                 
3522                         case '°': case '±': case '²': case '³':  
3523                         case '×': case '÷': case '¹': case 'ª':
3524                         case 'º': case '¬': case 'µ':
3525                                 if (bparams.inputenc == "latin1" ||
3526                                     (bparams.inputenc == "auto" &&
3527                                      font.language()->encoding()->LatexName()
3528                                      == "latin1")) {
3529                                         os << "\\ensuremath{"
3530                                            << c
3531                                            << '}';
3532                                         column += 13;
3533                                 } else {
3534                                         os << c;
3535                                 }
3536                                 break;
3537
3538                         case '|': case '<': case '>':
3539                                 // In T1 encoding, these characters exist
3540                                 if (lyxrc.fontenc == "T1") {
3541                                         os << c;
3542                                         //... but we should avoid ligatures
3543                                         if ((c == '>' || c == '<')
3544                                             && i <= size() - 2
3545                                             && GetChar(i + 1) == c) {
3546                                                 //os << "\\textcompwordmark{}";
3547                                                 // Jean-Marc, have a look at
3548                                                 // this. I think this works
3549                                                 // equally well:
3550                                                 os << "\\,{}";
3551                                                 // Lgb
3552                                                 column += 19;
3553                                         }
3554                                         break;
3555                                 }
3556                                 // Typewriter font also has them
3557                                 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
3558                                         os << c;
3559                                         break;
3560                                 } 
3561                                 // Otherwise, we use what LaTeX
3562                                 // provides us.
3563                                 switch(c) {
3564                                 case '<':
3565                                         os << "\\textless{}";
3566                                         column += 10;
3567                                         break;
3568                                 case '>':
3569                                         os << "\\textgreater{}";
3570                                         column += 13;
3571                                         break;
3572                                 case '|':
3573                                         os << "\\textbar{}";
3574                                         column += 9;
3575                                         break;
3576                                 }
3577                                 break;
3578
3579                         case '-': // "--" in Typewriter mode -> "-{}-"
3580                                 if (i <= size() - 2
3581                                     && GetChar(i + 1) == '-'
3582                                     && font.family() == LyXFont::TYPEWRITER_FAMILY) {
3583                                         os << "-{}";
3584                                         column += 2;
3585                                 } else {
3586                                         os << '-';
3587                                 }
3588                                 break;
3589
3590                         case '\"': 
3591                                 os << "\\char`\\\"{}";
3592                                 column += 9;
3593                                 break;
3594
3595                         case '£':
3596                                 if (bparams.inputenc == "default") {
3597                                         os << "\\pounds{}";
3598                                         column += 8;
3599                                 } else {
3600                                         os << c;
3601                                 }
3602                                 break;
3603
3604                         case '$': case '&':
3605                         case '%': case '#': case '{':
3606                         case '}': case '_':
3607                                 os << '\\' << c;
3608                                 column += 1;
3609                                 break;
3610
3611                         case '~':
3612                                 os << "\\textasciitilde{}";
3613                                 column += 16;
3614                                 break;
3615
3616                         case '^':
3617                                 os << "\\textasciicircum{}";
3618                                 column += 17;
3619                                 break;
3620
3621                         case '*': case '[': case ']':
3622                                 // avoid being mistaken for optional arguments
3623                                 os << '{' << c << '}';
3624                                 column += 2;
3625                                 break;
3626
3627                         case ' ':
3628                                 // Blanks are printed before font switching.
3629                                 // Sure? I am not! (try nice-latex)
3630                                 // I am sure it's correct. LyX might be smarter
3631                                 // in the future, but for now, nothing wrong is
3632                                 // written. (Asger)
3633                                 break;
3634
3635                         default:
3636                                 /* idea for labels --- begin*/
3637                                 // Check for "LyX"
3638                                 if (c ==  'L'
3639                                     && i <= size() - 3
3640                                     && font.family() != LyXFont::TYPEWRITER_FAMILY
3641                                     && GetChar(i + 1) == 'y'
3642                                     && GetChar(i + 2) == 'X') {
3643                                         os << "\\LyX{}";
3644                                         i += 2;
3645                                         column += 5;
3646                                 }
3647                                 // Check for "TeX"
3648                                 else if (c == 'T'
3649                                          && i <= size() - 3
3650                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3651                                          && GetChar(i + 1) == 'e'
3652                                          && GetChar(i + 2) == 'X') {
3653                                         os << "\\TeX{}";
3654                                         i += 2;
3655                                         column += 5;
3656                                 }
3657                                 // Check for "LaTeX2e"
3658                                 else if (c == 'L'
3659                                          && i <= size() - 7
3660                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3661                                          && GetChar(i + 1) == 'a'
3662                                          && GetChar(i + 2) == 'T'
3663                                          && GetChar(i + 3) == 'e'
3664                                          && GetChar(i + 4) == 'X'
3665                                          && GetChar(i + 5) == '2'
3666                                          && GetChar(i + 6) == 'e') {
3667                                         os << "\\LaTeXe{}";
3668                                         i += 6;
3669                                         column += 8;
3670                                 }
3671                                 // Check for "LaTeX"
3672                                 else if (c == 'L'
3673                                          && i <= size() - 5
3674                                          && font.family() != LyXFont::TYPEWRITER_FAMILY
3675                                          && GetChar(i + 1) == 'a'
3676                                          && GetChar(i + 2) == 'T'
3677                                          && GetChar(i + 3) == 'e'
3678                                          && GetChar(i + 4) == 'X') {
3679                                         os << "\\LaTeX{}";
3680                                         i += 4;
3681                                         column += 7;
3682                                         /* idea for labels --- end*/ 
3683                                 } else if (c != '\0') {
3684                                         os << c;
3685                                 }
3686                                 break;
3687                         }
3688                 }
3689         }
3690 }
3691
3692
3693 LyXParagraph * LyXParagraph::TeXDeeper(Buffer const * buf,
3694                                        BufferParams const & bparams,
3695                                        ostream & os, TexRow & texrow,
3696                                        ostream & foot,
3697                                        TexRow & foot_texrow,
3698                                        int & foot_count)
3699 {
3700         lyxerr[Debug::LATEX] << "TeXDeeper...     " << this << endl;
3701         LyXParagraph * par = this;
3702
3703         while (par &&
3704                (par->depth == depth)
3705 #ifndef NEW_INSETS
3706                && (par->footnoteflag == footnoteflag)
3707 #endif
3708                 ) {
3709 #ifndef NEW_INSETS
3710                 if (par->IsDummy())
3711                         lyxerr << "ERROR (LyXParagraph::TeXDeeper)" << endl;
3712 #endif
3713                 if (textclasslist.Style(bparams.textclass, 
3714                                         par->layout).isEnvironment()
3715                     || par->pextra_type != PEXTRA_NONE) {
3716                         par = par->TeXEnvironment(buf, bparams,
3717                                                   os, texrow,
3718                                                   foot, foot_texrow,
3719                                                   foot_count);
3720                 } else {
3721                         par = par->TeXOnePar(buf, bparams,
3722                                              os, texrow, false
3723 #ifndef NEW_INSETS
3724                                              ,
3725                                              foot, foot_texrow,
3726                                              foot_count
3727 #endif
3728                                 );
3729                 }
3730         }
3731         lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
3732
3733         return par;
3734 }
3735
3736
3737 LyXParagraph * LyXParagraph::TeXEnvironment(Buffer const * buf,
3738                                             BufferParams const & bparams,
3739                                             ostream & os, TexRow & texrow,
3740                                             ostream & foot,
3741                                             TexRow & foot_texrow,
3742                                             int & foot_count)
3743 {
3744         bool eindent_open = false;
3745         bool foot_this_level = false;
3746         // flags when footnotetext should be appended to file.
3747         static bool minipage_open = false;
3748         static int minipage_open_depth = 0;
3749         char par_sep = bparams.paragraph_separation;
3750     
3751         lyxerr[Debug::LATEX] << "TeXEnvironment...     " << this << endl;
3752 #ifndef NEW_INSETS
3753         if (IsDummy())
3754                 lyxerr << "ERROR (LyXParagraph::TeXEnvironment)" << endl;
3755 #endif
3756
3757         LyXLayout const & style =
3758                 textclasslist.Style(bparams.textclass,
3759                                     layout);
3760        
3761         if (pextra_type == PEXTRA_INDENT) {
3762                 if (!pextra_width.empty()) {
3763                         os << "\\begin{LyXParagraphIndent}{"
3764                            << pextra_width << "}\n";
3765                 } else {
3766                         //float ib = atof(pextra_widthp.c_str())/100;
3767                         // string can't handle floats at present (971109)
3768                         // so I'll do a conversion by hand knowing that
3769                         // the limits are 0.0 to 1.0. ARRae.
3770                         os << "\\begin{LyXParagraphIndent}{";
3771                         switch (pextra_widthp.length()) {
3772                         case 3:
3773                                 os << "1.00";
3774                                 break;
3775                         case 2:
3776                                 os << "0."
3777                                    << pextra_widthp;
3778                                 break;
3779                         case 1:
3780                                 os << "0.0"
3781                                    << pextra_widthp;
3782                         }
3783                         os << "\\columnwidth}\n";
3784                 }
3785                 texrow.newline();
3786                 eindent_open = true;
3787         }
3788         if ((pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3789                 if (pextra_hfill && Previous() &&
3790                     (Previous()->pextra_type == PEXTRA_MINIPAGE)) {
3791                         os << "\\hfill{}\n";
3792                         texrow.newline();
3793                 }
3794                 if (par_sep == BufferParams::PARSEP_INDENT) {
3795                         os << "{\\setlength\\parindent{0pt}\n";
3796                         texrow.newline();
3797                 }
3798                 os << "\\begin{minipage}";
3799                 switch(pextra_alignment) {
3800                 case MINIPAGE_ALIGN_TOP:
3801                         os << "[t]";
3802                         break;
3803                 case MINIPAGE_ALIGN_MIDDLE:
3804                         os << "[m]";
3805                         break;
3806                 case MINIPAGE_ALIGN_BOTTOM:
3807                         os << "[b]";
3808                         break;
3809                 }
3810                 if (!pextra_width.empty()) {
3811                         os << '{' << pextra_width << "}\n";
3812                 } else {
3813                         //float ib = atof(par->pextra_width.c_str())/100;
3814                         // string can't handle floats at present
3815                         // so I'll do a conversion by hand knowing that
3816                         // the limits are 0.0 to 1.0. ARRae.
3817                         os << '{';
3818                         switch (pextra_widthp.length()) {
3819                         case 3:
3820                                 os << "1.00";
3821                                 break;
3822                         case 2:
3823                                 os << "0."
3824                                    << pextra_widthp;
3825                                 break;
3826                         case 1:
3827                                 os << "0.0"
3828                                    << pextra_widthp;
3829                         }
3830                         os << "\\columnwidth}\n";
3831                 }
3832                 texrow.newline();
3833                 if (par_sep == BufferParams::PARSEP_INDENT) {
3834                         os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3835                         texrow.newline();
3836                 }
3837                 minipage_open = true;
3838                 minipage_open_depth = depth;
3839         }
3840
3841 #ifdef WITH_WARNINGS
3842 #warning Define FANCY_FOOTNOTE_CODE to re-enable Allan footnote code
3843         //I disabled it because it breaks when lists span on several
3844         //pages (JMarc)
3845 #endif
3846         if (style.isEnvironment()){
3847                 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
3848 #ifdef FANCY_FOOTNOTE_CODE
3849                         if (foot_count < 0) {
3850                                 // flag that footnote[mark][text] should be
3851                                 // used for any footnotes from now on
3852                                 foot_count = 0;
3853                                 foot_this_level = true;
3854                         }
3855 #endif
3856                         os << "\\begin{" << style.latexname() << "}{"
3857                            << labelwidthstring << "}\n";
3858                 } else if (style.labeltype == LABEL_BIBLIO) {
3859                         // ale970405
3860                         os << "\\begin{" << style.latexname() << "}{"
3861                            <<  bibitemWidest(current_view)
3862                            << "}\n";
3863                 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
3864 #ifdef FANCY_FOOTNOTE_CODE
3865                         if (foot_count < 0) {
3866                                 // flag that footnote[mark][text] should be
3867                                 // used for any footnotes from now on
3868                                 foot_count = 0;
3869                                 foot_this_level = true;
3870                         }
3871 #endif
3872                         os << "\\begin{" << style.latexname() << '}'
3873                            << style.latexparam() << '\n';
3874                 } else 
3875                         os << "\\begin{" << style.latexname() << '}'
3876                            << style.latexparam() << '\n';
3877                 texrow.newline();
3878         }
3879         LyXParagraph * par = this;
3880         do {
3881                 par = par->TeXOnePar(buf, bparams,
3882                                      os, texrow, false
3883 #ifndef NEW_INSETS
3884                                      ,
3885                                      foot, foot_texrow, foot_count
3886 #endif
3887                         );
3888
3889                 if (minipage_open && par && !style.isEnvironment() &&
3890                     (par->pextra_type == PEXTRA_MINIPAGE) &&
3891                     par->pextra_start_minipage) {
3892                         os << "\\end{minipage}\n";
3893                         texrow.newline();
3894                         if (par_sep == BufferParams::PARSEP_INDENT) {
3895                                 os << "}\n";
3896                                 texrow.newline();
3897                         }
3898                         minipage_open = false;
3899                 }
3900                 if (par && par->depth > depth) {
3901                         if (textclasslist.Style(bparams.textclass,
3902                                                 par->layout).isParagraph()
3903                             && !par->table
3904                             // Thinko!
3905                             // How to handle this? (Lgb)
3906                             //&& !suffixIs(os, "\n\n")
3907                                 ) {
3908                                 // There should be at least one '\n' already
3909                                 // but we need there to be two for Standard 
3910                                 // paragraphs that are depth-increment'ed to be
3911                                 // output correctly.  However, tables can
3912                                 // also be paragraphs so don't adjust them.
3913                                 // ARRae
3914                                 // Thinkee:
3915                                 // Will it ever harm to have one '\n' too
3916                                 // many? i.e. that we sometimes will have
3917                                 // three in a row. (Lgb)
3918                                 os << '\n';
3919                                 texrow.newline();
3920                         }
3921                         par = par->TeXDeeper(buf, bparams, os, texrow,
3922                                              foot, foot_texrow, foot_count);
3923                 }
3924                 if (par && par->layout == layout && par->depth == depth &&
3925                     (par->pextra_type == PEXTRA_MINIPAGE) && !minipage_open) {
3926                         if (par->pextra_hfill && par->Previous() &&
3927                             (par->Previous()->pextra_type == PEXTRA_MINIPAGE)){
3928                                 os << "\\hfill{}\n";
3929                                 texrow.newline();
3930                         }
3931                         if (par_sep == BufferParams::PARSEP_INDENT) {
3932                                 os << "{\\setlength\\parindent{0pt}\n";
3933                                 texrow.newline();
3934                         }
3935                         os << "\\begin{minipage}";
3936                         switch(par->pextra_alignment) {
3937                         case MINIPAGE_ALIGN_TOP:
3938                                 os << "[t]";
3939                                 break;
3940                         case MINIPAGE_ALIGN_MIDDLE:
3941                                 os << "[m]";
3942                                 break;
3943                         case MINIPAGE_ALIGN_BOTTOM:
3944                                 os << "[b]";
3945                                 break;
3946                         }
3947                         if (!par->pextra_width.empty()) {
3948                                 os << '{' << par->pextra_width << "}\n";
3949                         } else {
3950                                 //float ib = atof(par->pextra_widthp.c_str())/100;
3951                                 // string can't handle floats at present
3952                                 // so I'll do a conversion by hand knowing that
3953                                 // the limits are 0.0 to 1.0. ARRae.
3954                                 os << '{';
3955                                 switch (par->pextra_widthp.length()) {
3956                                 case 3:
3957                                         os << "1.00";
3958                                         break;
3959                                 case 2:
3960                                         os << "0." << par->pextra_widthp;
3961                                         break;
3962                                 case 1:
3963                                         os << "0.0" << par->pextra_widthp;
3964                                 }
3965                                 os << "\\columnwidth}\n";
3966                         }
3967                         texrow.newline();
3968                         if (par_sep == BufferParams::PARSEP_INDENT) {
3969                                 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3970                                 texrow.newline();
3971                         }
3972                         minipage_open = true;
3973                         minipage_open_depth = par->depth;
3974                 }
3975         } while (par
3976                  && par->layout == layout
3977                  && par->depth == depth
3978                  && par->pextra_type == pextra_type
3979 #ifndef NEW_INSETS
3980                  && par->footnoteflag == footnoteflag
3981 #endif
3982                 );
3983  
3984         if (style.isEnvironment()) {
3985                 os << "\\end{" << style.latexname() << '}';
3986                 // maybe this should go after the minipage closes?
3987                 if (foot_this_level) {
3988                         if (foot_count >= 1) {
3989                                 if (foot_count > 1) {
3990                                         os << "\\addtocounter{footnote}{-"
3991                                            << foot_count - 1
3992                                            << '}';
3993                                 }
3994                                 os << foot;
3995                                 texrow += foot_texrow;
3996                                 foot.clear();
3997                                 foot_texrow.reset();
3998                                 foot_count = 0;
3999                         }
4000                 }
4001         }
4002         if (minipage_open && (minipage_open_depth == depth) &&
4003             (!par || par->pextra_start_minipage ||
4004              par->pextra_type != PEXTRA_MINIPAGE)) {
4005                 os << "\\end{minipage}\n";
4006                 texrow.newline();
4007                 if (par_sep == BufferParams::PARSEP_INDENT) {
4008                         os << "}\n";
4009                         texrow.newline();
4010                 }
4011                 if (par && par->pextra_type != PEXTRA_MINIPAGE) {
4012                         os << "\\medskip\n\n";
4013                         texrow.newline();
4014                         texrow.newline();
4015                 }
4016                 minipage_open = false;
4017         }
4018         if (eindent_open) {
4019                 os << "\\end{LyXParagraphIndent}\n";
4020                 texrow.newline();
4021         }
4022         if (!(par && (par->pextra_type == PEXTRA_MINIPAGE) 
4023               && par->pextra_hfill)) {
4024                 os << '\n';
4025                 texrow.newline();
4026         }
4027         lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
4028         return par;  // ale970302
4029 }
4030
4031
4032 #ifndef NEW_INSETS
4033 LyXParagraph * LyXParagraph::TeXFootnote(Buffer const * buf,
4034                                          BufferParams const & bparams,
4035                                          ostream & os, TexRow & texrow,
4036                                          ostream & foot, TexRow & foot_texrow,
4037                                          int & foot_count,
4038                                          bool parent_is_rtl)
4039 {
4040         lyxerr[Debug::LATEX] << "TeXFootnote...  " << this << endl;
4041         if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
4042                 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
4043                         "No footnote!" << endl;
4044
4045         LyXParagraph * par = this;
4046         LyXLayout const & style =
4047                 textclasslist.Style(bparams.textclass, 
4048                                     previous->GetLayout());
4049         
4050         if (style.needprotect && footnotekind != LyXParagraph::FOOTNOTE){
4051                 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
4052                         "Float other than footnote in command"
4053                         " with moving argument is illegal" << endl;
4054         }
4055
4056         if (footnotekind != LyXParagraph::FOOTNOTE
4057             && footnotekind != LyXParagraph::MARGIN
4058             && os.tellp()
4059             // Thinko
4060             // How to solve this?
4061             //&& !suffixIs(file, '\n')
4062                 ) {
4063                 // we need to ensure that real floats like tables and figures
4064                 // have their \begin{} on a new line otherwise we can get
4065                 // incorrect results when using the endfloat.sty package
4066                 // especially if two floats follow one another.  ARRae 981022
4067                 // NOTE: if the file is length 0 it must have just been
4068                 //       written out so we assume it ended with a '\n'
4069                 // Thinkee:
4070                 // As far as I can see there is never any harm in writing
4071                 // a '\n' too much. Please tell me if I am wrong. (Lgb)
4072                 os << '\n';
4073                 texrow.newline();
4074         }
4075
4076         bool moving_arg = false;
4077         bool need_closing = false;
4078         bool is_rtl = isRightToLeftPar(bparams);
4079
4080         if (is_rtl != parent_is_rtl) {
4081                 if (is_rtl)
4082                         os << "\\R{";
4083                 else
4084                         os << "\\L{";
4085                 need_closing = true;
4086         }
4087         
4088         //BufferParams * params = &current_view->buffer()->params;
4089         bool footer_in_body = true;
4090         switch (footnotekind) {
4091         case LyXParagraph::FOOTNOTE:
4092                 if (style.intitle) {
4093                         os << "\\thanks{\n";
4094                         footer_in_body = false;
4095                         moving_arg = true;
4096                 } else {
4097                         if (foot_count == -1) {
4098                                 // we're at depth 0 so we can use:
4099                                 os << "\\footnote{%\n";
4100                                 footer_in_body = false;
4101                         } else {
4102                                 os << "\\footnotemark{}%\n";
4103                                 if (foot_count) {
4104                                         // we only need this when there are
4105                                         // multiple footnotes
4106                                         os << "\\stepcounter{footnote}";
4107                                 }
4108                                 os << "\\footnotetext{%\n";
4109                                 foot_texrow.start(this, 0);
4110                                 foot_texrow.newline();
4111                                 ++foot_count;
4112                         }
4113                 }
4114                 break;
4115         case LyXParagraph::MARGIN:
4116                 os << "\\marginpar{\n";
4117                 break;
4118         case LyXParagraph::FIG:
4119                 if (pextra_type == PEXTRA_FLOATFLT
4120                     && (!pextra_width.empty()
4121                         || !pextra_widthp.empty())) {
4122                         if (!pextra_width.empty())
4123                                 os << "\\begin{floatingfigure}{"
4124                                    << pextra_width << "}\n";
4125                         else
4126                                 os << "\\begin{floatingfigure}{"
4127                                    << atoi(pextra_widthp.c_str())/100.0
4128                                    << "\\textwidth}\n";
4129                 } else {
4130                         os << "\\begin{figure}";
4131                         if (!bparams.float_placement.empty()) { 
4132                                 os << '[' << bparams.float_placement << "]\n";
4133                         } else {
4134                                 os << '\n';
4135                         }
4136                 }
4137                 break;
4138         case LyXParagraph::TAB:
4139                 os << "\\begin{table}";
4140                 if (!bparams.float_placement.empty()) { 
4141                         os << '[' << bparams.float_placement << "]\n";
4142                 } else {
4143                         os << '\n';
4144                 }
4145                 break;
4146         case LyXParagraph::WIDE_FIG:
4147                 os << "\\begin{figure*}";
4148                 if (!bparams.float_placement.empty()) { 
4149                         os << '[' << bparams.float_placement << "]\n";
4150                 } else {
4151                         os << '\n';
4152                 }
4153                 break;
4154         case LyXParagraph::WIDE_TAB:
4155                 os << "\\begin{table*}";
4156                 if (!bparams.float_placement.empty()) { 
4157                         os << '[' << bparams.float_placement << "]\n";
4158                 } else {
4159                         os << '\n';
4160                 }
4161                 break;
4162         case LyXParagraph::ALGORITHM:
4163                 os << "\\begin{algorithm}\n";
4164                 break;
4165         }
4166         texrow.newline();
4167    
4168         if (footnotekind != LyXParagraph::FOOTNOTE
4169             || !footer_in_body) {
4170                 // Process text for all floats except footnotes in body
4171                 do {
4172                         LyXLayout const & style =
4173                                 textclasslist
4174                                 .Style(bparams.textclass, par->layout);
4175                         if (par->IsDummy())
4176                                 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
4177                                        << endl;
4178                         if (style.isEnvironment()
4179                             || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
4180                                 // Allows the use of minipages within float
4181                                 // environments. Shouldn't be circular because
4182                                 // we don't support footnotes inside
4183                                 // floats (yet). ARRae
4184                                 par = par->TeXEnvironment(buf, bparams, os,
4185                                                           texrow,
4186                                                           foot, foot_texrow,
4187                                                           foot_count);
4188                         } else {
4189                                 par = par->TeXOnePar(buf, bparams,
4190                                                      os, texrow, moving_arg,
4191                                                      foot, foot_texrow,
4192                                                      foot_count);
4193                         }
4194                         
4195                         if (par && !par->IsDummy() && par->depth > depth) {
4196                                 par = par->TeXDeeper(buf, bparams, os, texrow,
4197                                                      foot, foot_texrow,
4198                                                      foot_count);
4199                         }
4200                 } while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4201         } else {
4202                 // process footnotes > depth 0 or in environments separately
4203                 // NOTE: Currently don't support footnotes within footnotes
4204                 //       even though that is possible using the \footnotemark
4205 #ifdef HAVE_SSTREAM
4206                 std::ostringstream dummy;
4207 #else
4208                 ostrstream dummy;
4209 #endif
4210                 TexRow dummy_texrow;
4211                 int dummy_count = 0;
4212                 do {
4213                         LyXLayout const & style =
4214                                 textclasslist
4215                                 .Style(bparams.textclass, par->layout);
4216                         if (par->IsDummy())
4217                                 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
4218                                        << endl;
4219                         if (style.isEnvironment()
4220                             || par->pextra_type == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
4221                                 // Allows the use of minipages within float
4222                                 // environments. Shouldn't be circular because
4223                                 // we don't support footnotes inside
4224                                 // floats (yet). ARRae
4225                                 par = par->TeXEnvironment(buf, bparams,
4226                                                           foot, foot_texrow,
4227                                                           dummy, dummy_texrow,
4228                                                           dummy_count);
4229                         } else {
4230                                 par = par->TeXOnePar(buf, bparams,
4231                                                      foot, foot_texrow,
4232                                                      moving_arg,
4233                                                      dummy, dummy_texrow,
4234                                                      dummy_count);
4235                         }
4236
4237                         if (par && !par->IsDummy() && par->depth > depth) {
4238                                 par = par->TeXDeeper(buf, bparams,
4239                                                      foot, foot_texrow,
4240                                                      dummy, dummy_texrow,
4241                                                      dummy_count);
4242                         }
4243                 } while (par
4244                          && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4245                 if (dummy_count) {
4246                         lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
4247                                 "Footnote in a Footnote -- not supported"
4248                                << endl;
4249                 }
4250 #ifndef HAVE_OSTREAM
4251                 delete [] dummy.str();
4252 #endif
4253         }
4254
4255         switch (footnotekind) {
4256         case LyXParagraph::FOOTNOTE:
4257                 if (footer_in_body) {
4258                         // This helps tell which of the multiple
4259                         // footnotetexts an error was in.
4260                         foot << "}%\n";
4261                         foot_texrow.newline();
4262                 } else {
4263                         os << '}';
4264                 }
4265                 break;
4266         case LyXParagraph::MARGIN:
4267                 os << '}';
4268                 break;
4269         case LyXParagraph::FIG:
4270                 if (pextra_type == PEXTRA_FLOATFLT
4271                     && (!pextra_width.empty()
4272                         || !pextra_widthp.empty()))
4273                         os << "\\end{floatingfigure}";
4274                 else
4275                         os << "\\end{figure}";
4276                 break;
4277         case LyXParagraph::TAB:
4278                 os << "\\end{table}";
4279                 break;
4280         case LyXParagraph::WIDE_FIG:
4281                 os << "\\end{figure*}";
4282                 break;
4283         case LyXParagraph::WIDE_TAB:
4284                 os << "\\end{table*}";
4285                 break;
4286         case LyXParagraph::ALGORITHM:
4287                 os << "\\end{algorithm}";
4288                 break;
4289         }
4290
4291         if (need_closing)
4292                 os << "}";
4293
4294         if (footnotekind != LyXParagraph::FOOTNOTE
4295             && footnotekind != LyXParagraph::MARGIN) {
4296                 // we need to ensure that real floats like tables and figures
4297                 // have their \end{} on a line of their own otherwise we can
4298                 // get incorrect results when using the endfloat.sty package.
4299                 os << "\n";
4300                 texrow.newline();
4301         }
4302
4303         lyxerr[Debug::LATEX] << "TeXFootnote...done " << par->next << endl;
4304         return par;
4305 }
4306
4307
4308 bool LyXParagraph::IsDummy() const
4309 {
4310         return (footnoteflag == LyXParagraph::NO_FOOTNOTE && previous
4311                 && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE);
4312 }
4313 #endif
4314
4315 void LyXParagraph::SetPExtraType(BufferParams const & bparams,
4316                                  int type, char const * width,
4317                                  char const * widthp)
4318 {
4319         pextra_type = type;
4320         pextra_width = width;
4321         pextra_widthp = widthp;
4322
4323         if (textclasslist.Style(bparams.textclass, 
4324                                 layout).isEnvironment()) {
4325                 LyXParagraph
4326                         * par = this,
4327                         * ppar = par;
4328
4329                 while (par && (par->layout == layout)
4330                        && (par->depth == depth)) {
4331                         ppar = par;
4332                         par = par->Previous();
4333 #ifndef NEW_INSETS
4334                         if (par)
4335                                 par = par->FirstPhysicalPar();
4336 #endif
4337                         while (par && par->depth > depth) {
4338                                 par = par->Previous();
4339 #ifndef NEW_INSETS
4340                                 if (par)
4341                                         par = par->FirstPhysicalPar();
4342 #endif
4343                         }
4344                 }
4345                 par = ppar;
4346                 while (par && (par->layout == layout)
4347                        && (par->depth == depth)) {
4348                         par->pextra_type = type;
4349                         par->pextra_width = width;
4350                         par->pextra_widthp = widthp;
4351 #ifndef NEW_INSETS
4352                         par = par->NextAfterFootnote();
4353 #else
4354                         par = par->Next();
4355 #endif
4356                         if (par && (par->depth > depth))
4357                                 par->SetPExtraType(bparams,
4358                                                    type, width, widthp);
4359 #ifndef NEW_INSETS
4360                         while (par && ((par->depth > depth) || par->IsDummy()))
4361                                 par = par->NextAfterFootnote();
4362 #else
4363                         while (par && ((par->depth > depth)))
4364                                 par = par->Next();
4365 #endif
4366                 }
4367         }
4368 }
4369
4370
4371 void LyXParagraph::UnsetPExtraType(BufferParams const & bparams)
4372 {
4373         if (pextra_type == PEXTRA_NONE)
4374                 return;
4375     
4376         pextra_type = PEXTRA_NONE;
4377         pextra_width.erase();
4378         pextra_widthp.erase();
4379
4380         if (textclasslist.Style(bparams.textclass, 
4381                                 layout).isEnvironment()) {
4382                 LyXParagraph
4383                         * par = this,
4384                         * ppar = par;
4385
4386                 while (par && (par->layout == layout)
4387                        && (par->depth == depth)) {
4388                         ppar = par;
4389                         par = par->Previous();
4390 #ifndef NEW_INSETS
4391                         if (par)
4392                                 par = par->FirstPhysicalPar();
4393 #endif
4394                         while (par && par->depth > depth) {
4395                                 par = par->Previous();
4396 #ifndef NEW_INSETS
4397                                 if (par)
4398                                         par = par->FirstPhysicalPar();
4399 #endif
4400                         }
4401                 }
4402                 par = ppar;
4403                 while (par && (par->layout == layout)
4404                        && (par->depth == depth)) {
4405                         par->pextra_type = PEXTRA_NONE;
4406                         par->pextra_width.erase();
4407                         par->pextra_widthp.erase();
4408 #ifndef NEW_INSETS
4409                         par = par->NextAfterFootnote();
4410 #else
4411                         par = par->Next();
4412 #endif
4413                         if (par && (par->depth > depth))
4414                                 par->UnsetPExtraType(bparams);
4415 #ifndef NEW_INSETS
4416                         while (par && ((par->depth > depth) || par->IsDummy()))
4417                                 par = par->NextAfterFootnote();
4418 #else
4419                         while (par && ((par->depth > depth)))
4420                                 par = par->Next();
4421 #endif
4422                 }
4423         }
4424 }
4425
4426
4427 bool LyXParagraph::IsHfill(size_type pos) const
4428 {
4429         return IsHfillChar(GetChar(pos));
4430 }
4431
4432
4433 bool LyXParagraph::IsInset(size_type pos) const
4434 {
4435         return IsInsetChar(GetChar(pos));
4436 }
4437
4438
4439 #ifndef NEW_INSETS
4440 bool LyXParagraph::IsFloat(size_type pos) const
4441 {
4442         return IsFloatChar(GetChar(pos));
4443 }
4444 #endif
4445
4446
4447 bool LyXParagraph::IsNewline(size_type pos) const
4448 {
4449         return pos >= 0 && IsNewlineChar(GetChar(pos));
4450 }
4451
4452
4453 bool LyXParagraph::IsSeparator(size_type pos) const
4454 {
4455         return IsSeparatorChar(GetChar(pos));
4456 }
4457
4458
4459 bool LyXParagraph::IsLineSeparator(size_type pos) const
4460 {
4461         return IsLineSeparatorChar(GetChar(pos));
4462 }
4463
4464
4465 bool LyXParagraph::IsKomma(size_type pos) const
4466 {
4467         return IsKommaChar(GetChar(pos));
4468 }
4469
4470
4471 /// Used by the spellchecker
4472 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
4473 {
4474         value_type c = GetChar(pos);
4475         if (IsLetterChar(c))
4476                 return true;
4477         // '\0' is not a letter, allthough every string contains "" (below)
4478         if( c == '\0')
4479                 return false;
4480         // We want to pass the ' and escape chars to ispell
4481         string extra = lyxrc.isp_esc_chars + '\'';
4482         char ch[2];
4483         ch[0] = c;
4484         ch[1] = 0;
4485         return contains(extra, ch);
4486 }
4487  
4488  
4489 bool LyXParagraph::IsWord(size_type pos ) const
4490 {
4491         return IsWordChar(GetChar(pos)) ;
4492 }
4493
4494
4495 Language const *
4496 LyXParagraph::getParLanguage(BufferParams const & bparams) const 
4497 {
4498 #ifndef NEW_INSETS
4499         if (IsDummy())
4500                 return FirstPhysicalPar()->getParLanguage(bparams);
4501         else
4502 #endif
4503         if (size() > 0)
4504 #ifndef NEW_TABULAR
4505                 if (!table)
4506 #endif
4507                         return GetFirstFontSettings().language();
4508 #ifndef NEW_TABULAR
4509                 else {
4510                         for (size_type pos = 0; pos < size(); ++pos)
4511                                 if (IsNewline(pos))
4512                                         return GetFontSettings(bparams, pos).language();
4513                         return GetFirstFontSettings().language();
4514                 }
4515 #endif
4516         else if (previous)
4517                 return previous->getParLanguage(bparams);
4518         else
4519                 return bparams.language_info;
4520 }
4521
4522
4523 bool LyXParagraph::isRightToLeftPar(BufferParams const & bparams) const
4524 {
4525         return lyxrc.rtl_support && !table
4526                 && getParLanguage(bparams)->RightToLeft();
4527 }
4528
4529
4530 void LyXParagraph::ChangeLanguage(BufferParams const & bparams,
4531                                   Language const * from, Language const * to)
4532 {
4533         for(size_type i = 0; i < size(); ++i) {
4534                 LyXFont font = GetFontSettings(bparams, i);
4535                 if (font.language() == from) {
4536                         font.setLanguage(to);
4537                         SetFont(i, font);
4538                 }
4539         }
4540 }
4541
4542
4543 bool LyXParagraph::isMultiLingual(BufferParams const & bparams)
4544 {
4545         Language const * doc_language =
4546                 bparams.language_info;
4547         for(size_type i = 0; i < size(); ++i) {
4548                 LyXFont font = GetFontSettings(bparams, i);
4549                 if (font.language() != doc_language)
4550                         return true;
4551         }
4552         return false;
4553 }
4554
4555
4556 // Convert the paragraph to a string.
4557 // Used for building the table of contents
4558 string LyXParagraph::String(Buffer const * buffer, bool label)
4559 {
4560         BufferParams const & bparams = buffer->params;
4561         string s;
4562 #ifndef NEW_INSETS
4563         if (label && !IsDummy() && !labelstring.empty())
4564 #else
4565         if (label && !labelstring.empty())
4566 #endif
4567                 s += labelstring + ' ';
4568         string::size_type len = s.size();
4569
4570         for (LyXParagraph::size_type i = 0; i < size(); ++i) {
4571                 value_type c = GetChar(i);
4572                 if (IsPrintable(c))
4573                         s += c;
4574                 else if (c == META_INSET &&
4575                          GetInset(i)->LyxCode() == Inset::MATH_CODE) {
4576 #ifdef HAVE_SSTREAM
4577                         std::ostringstream ost;
4578                         GetInset(i)->Ascii(buffer, ost);
4579 #else
4580                         ostrstream ost;
4581                         GetInset(i)->Ascii(buffer, ost);
4582                         ost << '\0';
4583 #endif
4584                         s += subst(ost.str(),'\n',' ');
4585                 }
4586         }
4587
4588 #ifndef NEW_INSETS
4589         if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE 
4590             && footnoteflag == LyXParagraph::NO_FOOTNOTE)
4591                 s += NextAfterFootnote()->String(buffer, false);
4592
4593         if (!IsDummy()) {
4594 #endif
4595                 if (isRightToLeftPar(bparams))
4596                         reverse(s.begin() + len,s.end());
4597 #ifndef NEW_INSETS
4598         }
4599 #endif
4600         return s;
4601 }
4602
4603
4604 string LyXParagraph::String(Buffer const * buffer, 
4605                             LyXParagraph::size_type beg,
4606                             LyXParagraph::size_type end)
4607 {
4608         string s;
4609         int actcell = 0;
4610         int cell = 1;
4611 #ifndef NEW_TABULAR
4612         if (table)
4613                 for (LyXParagraph::size_type i = 0; i < beg; ++i)
4614                         if (IsNewline(i)) {
4615                                 if (cell >= table->NumberOfCellsInRow(actcell))
4616                                         cell = 1;
4617                                 else
4618                                         ++cell;
4619                                 ++actcell;
4620                         }
4621 #endif
4622
4623 #ifndef NEW_INSETS
4624         if (beg == 0 && !IsDummy() && !labelstring.empty())
4625 #else
4626         if (beg == 0 && !labelstring.empty())
4627 #endif
4628                 s += labelstring + ' ';
4629
4630         for (LyXParagraph::size_type i = beg; i < end; ++i) {
4631                 value_type c = GetChar(i);
4632                 if (IsPrintable(c))
4633                         s += c;
4634                 else if (c == META_INSET) {
4635 #ifdef HAVE_SSTREAM
4636                         std::ostringstream ost;
4637                         GetInset(i)->Ascii(buffer, ost);
4638 #else
4639                         ostrstream ost;
4640                         GetInset(i)->Ascii(buffer, ost);
4641                         ost << '\0';
4642 #endif
4643                         s += ost.str();
4644                 } else if (table && IsNewlineChar(c)) {
4645                         if (cell >= table->NumberOfCellsInRow(actcell)) {
4646                                 s += '\n';
4647                                 cell = 1;
4648                         } else {
4649                                 s += ' ';
4650                                 ++cell;
4651                         }
4652                         ++actcell;
4653                 }
4654         }
4655
4656         return s;
4657 }
4658
4659
4660 void LyXParagraph::SetInsetOwner(Inset *i)
4661 {
4662         inset_owner = i;
4663         for (InsetList::const_iterator cit = insetlist.begin();
4664              cit != insetlist.end(); ++cit) {
4665                 if ((*cit).inset)
4666                         (*cit).inset->setOwner(i);
4667         }
4668 }
4669
4670
4671 void LyXParagraph::deleteInsetsLyXText(BufferView * bv)
4672 {
4673         // then the insets
4674         for (InsetList::const_iterator cit = insetlist.begin();
4675              cit != insetlist.end(); ++cit) {
4676                 if ((*cit).inset) {
4677                         if ((*cit).inset->IsTextInset()) {
4678                                 static_cast<UpdatableInset *>
4679                                         ((*cit).inset)->deleteLyXText(bv);
4680                         }
4681                 }
4682         }
4683 }
4684
4685
4686 void LyXParagraph::resizeInsetsLyXText(BufferView * bv)
4687 {
4688         // then the insets
4689         for (InsetList::const_iterator cit = insetlist.begin();
4690              cit != insetlist.end(); ++cit) {
4691                 if ((*cit).inset) {
4692                         if ((*cit).inset->IsTextInset()) {
4693                                 static_cast<UpdatableInset *>
4694                                         ((*cit).inset)->resizeLyXText(bv);
4695                         }
4696                 }
4697         }
4698 }