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