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