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