]> git.lyx.org Git - lyx.git/blob - src/layout.C
several small patches and some fixes, read the ChangeLog
[lyx.git] / src / layout.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1995 Matthias Ettrich
7  *          Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include <algorithm>
18
19 #include "layout.h"
20 #include "lyxlex.h"
21 #include "support/filetools.h"
22 #include "lyx_gui_misc.h"
23 #include "debug.h"
24 #include "gettext.h"
25 #include "support/LAssert.h"
26
27 using std::pair;
28 using std::make_pair;
29 using std::sort;
30 using std::endl;
31
32 // Global variable: textclass table.
33 LyXTextClassList textclasslist;
34
35
36 // Reads the style files
37 void LyXSetStyle()
38 {
39         lyxerr[Debug::TCLASS] << "LyXSetStyle: parsing configuration...\n";
40         
41         if (!textclasslist.Read()) {
42                 lyxerr[Debug::TCLASS] << "LyXSetStyle: an error occured "
43                         "during parsing.\n             Exiting." << endl;
44                 exit(1);
45         }
46
47         lyxerr[Debug::TCLASS] << "LyXSetStyle: configuration parsed." << endl;
48 }
49
50
51 //  The order of the LayoutTags enum is no more important. [asierra300396]
52 // Tags indexes.
53 enum LayoutTags {
54         LT_ALIGN = 1, 
55         LT_ALIGNPOSSIBLE, 
56         LT_MARGIN, 
57         LT_BOTTOMSEP, 
58         LT_COPYSTYLE, 
59         LT_OBSOLETEDBY, 
60         //LT_EMPTY,
61         LT_END, 
62         //LT_ENVIRONMENT_DEFAULT, 
63         //LT_FANCYHDR,
64         LT_FILL_BOTTOM, 
65         LT_FILL_TOP, 
66         //LT_FIRST_COUNTER,
67         LT_FONT, 
68         LT_FREE_SPACING, 
69         //LT_HEADINGS,
70         LT_ITEMSEP, 
71         LT_KEEPEMPTY, 
72         LT_LABEL_BOTTOMSEP, 
73         LT_LABELFONT, 
74         LT_TEXTFONT,
75         LT_LABELINDENT, 
76         LT_LABELSEP, 
77         LT_LABELSTRING, 
78         LT_LABELSTRING_APPENDIX, 
79         LT_LABELTYPE,
80         LT_ENDLABELTYPE,
81         LT_LATEXNAME, 
82         LT_LATEXPARAM, 
83         LT_LATEXTYPE, 
84         LT_LEFTMARGIN, 
85         LT_NEED_PROTECT, 
86         LT_NEWLINE, 
87         LT_NEXTNOINDENT, 
88         LT_PARINDENT, 
89         LT_PARSEP, 
90         LT_PARSKIP, 
91         //LT_PLAIN,
92         LT_PREAMBLE, 
93         LT_RIGHTMARGIN, 
94         LT_SPACING, 
95         LT_TOPSEP, 
96         LT_INTITLE 
97 };
98
99
100 /////////////////////
101
102 // Constructor for layout
103 LyXLayout::LyXLayout ()
104 {
105         margintype = MARGIN_STATIC;
106         latextype = LATEX_PARAGRAPH;
107         intitle = false;
108         needprotect = false;
109         keepempty = false;
110         font = LyXFont(LyXFont::ALL_INHERIT);
111         labelfont = LyXFont(LyXFont::ALL_INHERIT);
112         resfont = LyXFont(LyXFont::ALL_SANE);
113         reslabelfont = LyXFont(LyXFont::ALL_SANE);
114         nextnoindent = false;
115         parskip = 0.0;
116         itemsep = 0;
117         topsep = 0.0;
118         bottomsep = 0.0;
119         labelbottomsep = 0.0;
120         parsep = 0;
121         align = LYX_ALIGN_BLOCK;
122         alignpossible = LYX_ALIGN_BLOCK;
123         labeltype = LABEL_NO_LABEL;
124         endlabeltype = END_LABEL_NO_LABEL;
125         // Should or should not. That is the question.
126         // spacing.set(Spacing::OneHalf);
127         fill_top = false;
128         fill_bottom = false;
129         newline_allowed = true;
130         free_spacing = false;
131 }
132
133
134 // Reads a layout definition from file
135 bool LyXLayout::Read (LyXLex & lexrc, LyXTextClass const & tclass)
136 {
137         // This table is sorted alphabetically [asierra 30March96]
138         keyword_item layoutTags[] = {
139                 { "align",                      LT_ALIGN },
140                 { "alignpossible",              LT_ALIGNPOSSIBLE },
141                 { "bottomsep",                  LT_BOTTOMSEP },
142                 { "copystyle",                  LT_COPYSTYLE },
143                 { "end",                        LT_END },
144                 { "endlabeltype",               LT_ENDLABELTYPE },
145                 { "fill_bottom",                LT_FILL_BOTTOM },
146                 { "fill_top",                   LT_FILL_TOP },
147                 { "font",                       LT_FONT },
148                 { "freespacing",                LT_FREE_SPACING },
149                 { "intitle",                    LT_INTITLE },
150                 { "itemsep",                    LT_ITEMSEP },
151                 { "keepempty",                  LT_KEEPEMPTY },
152                 { "labelbottomsep",             LT_LABEL_BOTTOMSEP },
153                 { "labelfont",                  LT_LABELFONT },
154                 { "labelindent",                LT_LABELINDENT },
155                 { "labelsep",                   LT_LABELSEP },
156                 { "labelstring",                LT_LABELSTRING },
157                 { "labelstringappendix",        LT_LABELSTRING_APPENDIX },
158                 { "labeltype",                  LT_LABELTYPE },
159                 { "latexname",                  LT_LATEXNAME },
160                 { "latexparam",                 LT_LATEXPARAM },
161                 { "latextype",                  LT_LATEXTYPE },
162                 { "leftmargin",                 LT_LEFTMARGIN },
163                 { "margin",                     LT_MARGIN },
164                 { "needprotect",                LT_NEED_PROTECT },
165                 { "newline",                    LT_NEWLINE },
166                 { "nextnoindent",               LT_NEXTNOINDENT },
167                 { "obsoletedby",                LT_OBSOLETEDBY },
168                 { "parindent",                  LT_PARINDENT },
169                 { "parsep",                     LT_PARSEP },
170                 { "parskip",                    LT_PARSKIP },
171                 { "preamble",                   LT_PREAMBLE },
172                 { "rightmargin",                LT_RIGHTMARGIN },
173                 { "spacing",                    LT_SPACING },
174                 { "textfont",                   LT_TEXTFONT },
175                 { "topsep",                     LT_TOPSEP }
176         };
177
178         bool error = false;
179         bool finished = false;
180         lexrc.pushTable(layoutTags, LT_INTITLE);
181         // parse style section
182         while (!finished && lexrc.IsOK() && !error) {
183                 int le = lexrc.lex();
184                 // See comment in lyxrc.C.
185                 switch(le) {
186                 case LyXLex::LEX_FEOF:
187                         continue; 
188
189                 case LyXLex::LEX_UNDEF:         // parse error
190                         lexrc.printError("Unknown layout tag `$$Token'");
191                         error = true;
192                         continue; 
193                 default: break;
194                 }
195                 switch(static_cast<LayoutTags>(le)) {
196                 case LT_END:            // end of structure
197                         finished = true;
198                         break;
199
200                 case LT_COPYSTYLE:     // initialize with a known style
201                         if (lexrc.next()) {
202                                 if (tclass.hasLayout(lexrc.GetString())) {
203                                         string tmpname = name_;
204                                         this->operator= (tclass.GetLayout(lexrc.GetString()));
205                                         name_ = tmpname;
206                                 } else {
207                                         lexrc.printError("Cannot copy known "
208                                                          "style `$$Token'");
209                                 }
210                         }
211                         break;
212
213                 case LT_OBSOLETEDBY:     // replace with a known style
214                         if (lexrc.next()) {
215                                 if (tclass.hasLayout(lexrc.GetString())) {
216                                         string tmpname = name_;
217                                         this->operator= (tclass.GetLayout(lexrc.GetString()));
218                                         name_ = tmpname;
219                                         if (obsoleted_by().empty())
220                                           obsoleted_by_ = lexrc.GetString();
221                                 } else {
222                                         lexrc.printError("Cannot replace with" 
223                                                          " unknown style "
224                                                          "`$$Token'");
225                                 }
226                         }
227                         break;
228
229                 case LT_MARGIN:         // Margin style definition.
230                         readMargin(lexrc);
231                         break;
232
233                 case LT_LATEXTYPE:      // Latex style definition.
234                         readLatexType(lexrc);
235                         break;
236
237                 case LT_INTITLE:
238                         intitle = lexrc.next() && lexrc.GetInteger();
239                         break;
240                         
241                 case LT_NEED_PROTECT:
242                         needprotect = lexrc.next() && lexrc.GetInteger();
243                         break;
244                         
245                 case LT_KEEPEMPTY:
246                         keepempty = lexrc.next() && lexrc.GetInteger();
247                         break;
248
249                 case LT_FONT:
250                         font.lyxRead(lexrc);
251                         labelfont= font;
252                         break;
253
254                 case LT_TEXTFONT:
255                         font.lyxRead(lexrc);
256                         break;
257
258                 case LT_LABELFONT:
259                         labelfont.lyxRead(lexrc);
260                         break;
261
262                 case LT_NEXTNOINDENT:   // Indent next paragraph?
263                         if (lexrc.next() && lexrc.GetInteger())
264                                 nextnoindent = true;
265                         else
266                                 nextnoindent = false;
267                         break;
268
269                 case LT_LATEXNAME:
270                         if (lexrc.next())
271                                 latexname_ = lexrc.GetString();
272                         break;
273                         
274                 case LT_LATEXPARAM:
275                         if (lexrc.next())
276                                 latexparam_ = lexrc.GetString();
277                         break;
278
279                 case LT_PREAMBLE:
280                         preamble_ = lexrc.getLongString("EndPreamble");
281                         break;
282
283                 case LT_LABELTYPE:
284                         readLabelType(lexrc);
285                         break;
286
287                 case LT_ENDLABELTYPE:
288                         readEndLabelType(lexrc);
289                         break;
290                         
291                 case LT_LEFTMARGIN:     // left margin type
292                         if (lexrc.next())
293                                 leftmargin = lexrc.GetString();
294                         break;                  
295
296                 case LT_RIGHTMARGIN:    // right margin type
297                         if (lexrc.next())
298                                 rightmargin = lexrc.GetString();
299                         break;
300
301                 case LT_LABELINDENT:    // label indenting flag
302                         if (lexrc.next())
303                                 labelindent = lexrc.GetString();
304                         break;
305
306                 case LT_PARINDENT:      // paragraph indent. flag
307                         if (lexrc.next())
308                                 parindent = lexrc.GetString();
309                         break;
310
311                 case LT_PARSKIP:        // paragraph skip size
312                         if (lexrc.next())
313                                 parskip = lexrc.GetFloat();
314                         break;
315
316                 case LT_ITEMSEP:        // item separation size
317                         if (lexrc.next())
318                                 itemsep = lexrc.GetFloat();
319                         break;
320
321                 case LT_TOPSEP:         // top separation size
322                         if (lexrc.next())
323                                 topsep = lexrc.GetFloat();
324                         break;
325
326                 case LT_BOTTOMSEP:      // bottom separation size
327                         if (lexrc.next())
328                                 bottomsep = lexrc.GetFloat();
329                         break;
330
331                 case LT_LABEL_BOTTOMSEP: // label bottom separation size
332                         if (lexrc.next())
333                                 labelbottomsep = lexrc.GetFloat();
334                         break;
335
336                 case LT_LABELSEP:       // label separator
337                         if (lexrc.next()) {
338                                 labelsep = subst(lexrc.GetString(), 'x', ' ');
339                         }
340                         break;
341
342                 case LT_PARSEP:         // par. separation size
343                         if (lexrc.next())
344                                 parsep = lexrc.GetFloat();
345                         break;
346
347                 case LT_FILL_TOP:       // fill top flag
348                         if (lexrc.next())
349                                 fill_top = lexrc.GetInteger();
350                         break;
351
352                 case LT_FILL_BOTTOM:    // fill bottom flag
353                         if (lexrc.next())
354                                 fill_bottom = lexrc.GetInteger();
355                         break;
356
357                 case LT_NEWLINE:        // newlines allowed?
358                         if (lexrc.next())
359                                 newline_allowed = lexrc.GetInteger();
360                         break;
361
362                 case LT_ALIGN:          // paragraph align
363                         readAlign(lexrc);
364                         break;
365                 case LT_ALIGNPOSSIBLE:  // paragraph allowed align
366                         readAlignPossible(lexrc);
367                         break;
368
369                 case LT_LABELSTRING:    // label string definition
370                         if (lexrc.next())
371                                 labelstring_ = lexrc.GetString();
372                         break;
373
374                 case LT_LABELSTRING_APPENDIX: // label string appendix definition
375                         if (lexrc.next())
376                                 labelstring_appendix_ = lexrc.GetString();
377                         break;
378
379                 case LT_FREE_SPACING:   // Allow for free spacing.
380                         if (lexrc.next())
381                                 free_spacing = lexrc.GetInteger();
382                         break;
383
384                 case LT_SPACING: // setspace.sty
385                         readSpacing(lexrc);
386                         break;
387                 }
388         }
389         lexrc.popTable();
390         return error;
391 }
392
393
394 enum AlignTags {
395         AT_BLOCK = 1,
396         AT_LEFT,
397         AT_RIGHT,
398         AT_CENTER,
399         AT_LAYOUT
400 };
401
402
403 void LyXLayout::readAlign(LyXLex & lexrc)
404 {
405         keyword_item alignTags[] = {
406                 { "block",  AT_BLOCK },
407                 { "center", AT_CENTER },
408                 { "layout", AT_LAYOUT },
409                 { "left",   AT_LEFT },
410                 { "right",  AT_RIGHT }
411         };
412
413         pushpophelper pph(lexrc, alignTags, AT_LAYOUT);
414         int le = lexrc.lex();
415         switch (le) {
416         case LyXLex::LEX_UNDEF:
417                 lexrc.printError("Unknown alignment `$$Token'");
418                 return; 
419         default: break;
420         };
421         switch(static_cast<AlignTags>(le)) {
422         case AT_BLOCK:
423                 align = LYX_ALIGN_BLOCK;
424                 break;
425         case AT_LEFT:
426                 align = LYX_ALIGN_LEFT;
427                 break;
428         case AT_RIGHT:
429                 align = LYX_ALIGN_RIGHT;
430                 break;
431         case AT_CENTER:
432                 align = LYX_ALIGN_CENTER;
433                 break;
434         case AT_LAYOUT:
435                 align = LYX_ALIGN_LAYOUT;
436                 break;
437         }
438 }
439
440
441 void LyXLayout::readAlignPossible(LyXLex & lexrc)
442 {
443         keyword_item alignTags[] = {
444                 { "block",  AT_BLOCK },
445                 { "center", AT_CENTER },
446                 { "layout", AT_LAYOUT },
447                 { "left",   AT_LEFT },
448                 { "right",  AT_RIGHT }
449         };
450
451         lexrc.pushTable(alignTags, AT_LAYOUT);
452         alignpossible = LYX_ALIGN_NONE;
453         int lineno = lexrc.GetLineNo();
454         do {
455                 int le = lexrc.lex();
456                 switch (le) {
457                 case LyXLex::LEX_UNDEF:
458                         lexrc.printError("Unknown alignment `$$Token'");
459                         continue; 
460                 default: break;
461                 };
462                 switch (static_cast<AlignTags>(le)) {
463                 case AT_BLOCK:
464                         alignpossible |= LYX_ALIGN_BLOCK;
465                         break;
466                 case AT_LEFT:
467                         alignpossible |= LYX_ALIGN_LEFT;
468                         break;
469                 case AT_RIGHT:
470                         alignpossible |= LYX_ALIGN_RIGHT;
471                         break;
472                 case AT_CENTER:
473                         alignpossible |= LYX_ALIGN_CENTER;
474                         break;
475                 case AT_LAYOUT:
476                         alignpossible |= LYX_ALIGN_LAYOUT;
477                         break;
478                 }
479         } while (lineno == lexrc.GetLineNo());
480         lexrc.popTable();
481 }
482
483
484 enum LabelTypeTags {
485         LA_NO_LABEL = 1,
486         LA_MANUAL,
487         LA_TOP_ENVIRONMENT,
488         LA_CENTERED_TOP_ENVIRONMENT,
489         LA_STATIC,
490         LA_SENSITIVE,
491         LA_COUNTER_CHAPTER,
492         LA_COUNTER_SECTION,
493         LA_COUNTER_SUBSECTION,
494         LA_COUNTER_SUBSUBSECTION,
495         LA_COUNTER_PARAGRAPH,
496         LA_COUNTER_SUBPARAGRAPH,
497         LA_COUNTER_ENUMI,
498         LA_COUNTER_ENUMII,
499         LA_COUNTER_ENUMIII,
500         LA_COUNTER_ENUMIV,
501         LA_BIBLIO
502 };
503
504
505 #if 0
506 static keyword_item labelTypeTags[] = {
507         { "bibliography",             LA_BIBLIO },
508         { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
509         { "counter_chapter",          LA_COUNTER_CHAPTER },
510         { "counter_enumi",            LA_COUNTER_ENUMI },
511         { "counter_enumii",           LA_COUNTER_ENUMII },
512         { "counter_enumiii",          LA_COUNTER_ENUMIII },
513         { "counter_enumiv",           LA_COUNTER_ENUMIV },
514         { "counter_paragraph",        LA_COUNTER_PARAGRAPH },
515         { "counter_section",          LA_COUNTER_SECTION },
516         { "counter_subparagraph",     LA_COUNTER_SUBPARAGRAPH },
517         { "counter_subsection",       LA_COUNTER_SUBSECTION },
518         { "counter_subsubsection",    LA_COUNTER_SUBSUBSECTION },
519         { "manual",                   LA_MANUAL },
520         { "no_label",                 LA_NO_LABEL },
521         { "sensitive",                LA_SENSITIVE },
522         { "static",                   LA_STATIC },
523         { "top_environment",          LA_TOP_ENVIRONMENT }
524 };
525 #endif
526
527
528 void LyXLayout::readLabelType(LyXLex & lexrc)
529 {
530         keyword_item labelTypeTags[] = {
531         { "bibliography",             LA_BIBLIO },
532         { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
533         { "counter_chapter",          LA_COUNTER_CHAPTER },
534         { "counter_enumi",            LA_COUNTER_ENUMI },
535         { "counter_enumii",           LA_COUNTER_ENUMII },
536         { "counter_enumiii",          LA_COUNTER_ENUMIII },
537         { "counter_enumiv",           LA_COUNTER_ENUMIV },
538         { "counter_paragraph",        LA_COUNTER_PARAGRAPH },
539         { "counter_section",          LA_COUNTER_SECTION },
540         { "counter_subparagraph",     LA_COUNTER_SUBPARAGRAPH },
541         { "counter_subsection",       LA_COUNTER_SUBSECTION },
542         { "counter_subsubsection",    LA_COUNTER_SUBSUBSECTION },
543         { "manual",                   LA_MANUAL },
544         { "no_label",                 LA_NO_LABEL },
545         { "sensitive",                LA_SENSITIVE },
546         { "static",                   LA_STATIC },
547         { "top_environment",          LA_TOP_ENVIRONMENT }
548 };
549
550         pushpophelper pph(lexrc, labelTypeTags, LA_BIBLIO);
551         int le = lexrc.lex();
552         switch (le) {
553         case LyXLex::LEX_UNDEF:
554                 lexrc.printError("Unknown labeltype tag `$$Token'");
555                 return; 
556         default: break;
557         }
558         switch (static_cast<LabelTypeTags>(le)) {
559         case LA_NO_LABEL:
560                 labeltype = LABEL_NO_LABEL;
561                 break;
562         case LA_MANUAL:
563                 labeltype = LABEL_MANUAL;
564                 break;
565         case LA_TOP_ENVIRONMENT:
566                 labeltype = LABEL_TOP_ENVIRONMENT;
567                 break;
568         case LA_CENTERED_TOP_ENVIRONMENT:
569                 labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
570                 break;
571         case LA_STATIC:
572                 labeltype = LABEL_STATIC;
573                 break;
574         case LA_SENSITIVE:
575                 labeltype = LABEL_SENSITIVE;
576                 break;
577         case LA_COUNTER_CHAPTER:
578                 labeltype = LABEL_COUNTER_CHAPTER;
579                 break;
580         case LA_COUNTER_SECTION:
581                 labeltype = LABEL_COUNTER_SECTION;
582                 break;
583         case LA_COUNTER_SUBSECTION:
584                 labeltype = LABEL_COUNTER_SUBSECTION;
585                 break;
586         case LA_COUNTER_SUBSUBSECTION:
587                 labeltype = LABEL_COUNTER_SUBSUBSECTION;
588                 break;
589         case LA_COUNTER_PARAGRAPH:
590                 labeltype = LABEL_COUNTER_PARAGRAPH;
591                 break;
592         case LA_COUNTER_SUBPARAGRAPH:
593                 labeltype = LABEL_COUNTER_SUBPARAGRAPH;
594                 break;
595         case LA_COUNTER_ENUMI:
596                 labeltype = LABEL_COUNTER_ENUMI;
597                 break;
598         case LA_COUNTER_ENUMII:
599                 labeltype = LABEL_COUNTER_ENUMII;
600                 break;
601         case LA_COUNTER_ENUMIII:
602                 labeltype = LABEL_COUNTER_ENUMIII;
603                 break;
604         case LA_COUNTER_ENUMIV:
605                 labeltype = LABEL_COUNTER_ENUMIV;
606                 break;
607         case LA_BIBLIO:
608                 labeltype = LABEL_BIBLIO;
609                 break;
610         }
611 }
612
613 static keyword_item endlabelTypeTags[] = {
614         { "box",        END_LABEL_BOX },
615         { "filled_box", END_LABEL_FILLED_BOX },
616         { "no_label",   END_LABEL_NO_LABEL }
617 };
618
619 void LyXLayout::readEndLabelType(LyXLex & lexrc)
620 {
621         pushpophelper pph(lexrc, endlabelTypeTags,
622                           END_LABEL_ENUM_LAST-END_LABEL_ENUM_FIRST+1);
623         int le = lexrc.lex();
624         switch(le) {
625         case LyXLex::LEX_UNDEF:
626                 lexrc.printError("Unknown labeltype tag `$$Token'");
627                 break;
628         case END_LABEL_BOX:
629         case END_LABEL_FILLED_BOX:
630         case END_LABEL_NO_LABEL:
631                 endlabeltype = static_cast<LYX_END_LABEL_TYPES>(le);
632                 break;
633         default:
634                 lyxerr << "Unhandled value " << le
635                        << " in LyXLayout::readEndLabelType." << endl;
636                 break;
637         }
638 }
639
640 #if 0
641 static keyword_item marginTags[] = {
642         { "dynamic",           MARGIN_DYNAMIC },
643         { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
644         { "manual",            MARGIN_MANUAL },
645         { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
646         { "static",            MARGIN_STATIC }
647 };
648 #endif
649
650 void LyXLayout::readMargin(LyXLex & lexrc)
651 {
652         keyword_item marginTags[] = {
653                 { "dynamic",           MARGIN_DYNAMIC },
654                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
655                 { "manual",            MARGIN_MANUAL },
656                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
657                 { "static",            MARGIN_STATIC }
658         };
659
660         pushpophelper pph(lexrc, marginTags, MARGIN_RIGHT_ADDRESS_BOX);
661
662         int le = lexrc.lex();
663         switch(le) {
664         case LyXLex::LEX_UNDEF:
665                 lexrc.printError("Unknown margin type tag `$$Token'");
666                 return;
667         case MARGIN_STATIC:
668         case MARGIN_MANUAL:
669         case MARGIN_DYNAMIC:
670         case MARGIN_FIRST_DYNAMIC:
671         case MARGIN_RIGHT_ADDRESS_BOX:
672                 margintype = static_cast<LYX_MARGIN_TYPE>(le);
673                 break;
674         default:
675                 lyxerr << "Unhandled value " << le
676                        << " in LyXLayout::readMargin." << endl;
677                 break;
678         }
679 }
680
681
682 #if 0
683 static keyword_item latexTypeTags[] = {
684         { "command",          LATEX_COMMAND },
685         { "environment",      LATEX_ENVIRONMENT },
686         { "item_environment", LATEX_ITEM_ENVIRONMENT },
687         { "list_environment", LATEX_LIST_ENVIRONMENT },
688         { "paragraph",        LATEX_PARAGRAPH }
689 };
690 #endif
691
692
693 void LyXLayout::readLatexType(LyXLex & lexrc)
694 {
695         keyword_item latexTypeTags[] = {
696                 { "command",          LATEX_COMMAND },
697                 { "environment",      LATEX_ENVIRONMENT },
698                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
699                 { "list_environment", LATEX_LIST_ENVIRONMENT },
700                 { "paragraph",        LATEX_PARAGRAPH }
701         };
702
703         pushpophelper pph(lexrc, latexTypeTags, LATEX_LIST_ENVIRONMENT);
704         int le = lexrc.lex();
705         switch (le) {
706         case LyXLex::LEX_UNDEF:
707                 lexrc.printError("Unknown latextype tag `$$Token'");
708                 return;
709         case LATEX_PARAGRAPH:
710         case LATEX_COMMAND:
711         case LATEX_ENVIRONMENT:
712         case LATEX_ITEM_ENVIRONMENT:
713         case LATEX_LIST_ENVIRONMENT:
714                 latextype = static_cast<LYX_LATEX_TYPES>(le);
715                 break;
716         default:
717                 lyxerr << "Unhandled value " << le
718                        << " in LyXLayout::readLatexType." << endl;
719                 break;
720         }
721 }
722
723
724 enum SpacingTags {
725         ST_SPACING_SINGLE = 1,
726         ST_SPACING_ONEHALF,
727         ST_SPACING_DOUBLE,
728         ST_OTHER
729 };
730
731
732 #if 0
733 static keyword_item spacingTags[] = {
734         {"double",  ST_SPACING_DOUBLE },
735         {"onehalf", ST_SPACING_ONEHALF },
736         {"other",   ST_OTHER },
737         {"single",  ST_SPACING_SINGLE }
738 };
739 #endif
740
741
742 void LyXLayout::readSpacing(LyXLex & lexrc)
743 {
744         keyword_item spacingTags[] = {
745                 {"double",  ST_SPACING_DOUBLE },
746                 {"onehalf", ST_SPACING_ONEHALF },
747                 {"other",   ST_OTHER },
748                 {"single",  ST_SPACING_SINGLE }
749         };
750
751         pushpophelper pph(lexrc, spacingTags, ST_OTHER);
752         int le = lexrc.lex();
753         switch(le) {
754         case LyXLex::LEX_UNDEF:
755                 lexrc.printError("Unknown spacing token `$$Token'");
756                 return;
757         default: break;
758         }
759         switch(static_cast<SpacingTags>(le)) {
760         case ST_SPACING_SINGLE:
761                 spacing.set(Spacing::Single);
762                 break;
763         case ST_SPACING_ONEHALF:
764                 spacing.set(Spacing::Onehalf);
765                 break;
766         case ST_SPACING_DOUBLE:
767                 spacing.set(Spacing::Double);
768                 break;
769         case ST_OTHER:
770                 lexrc.next();
771                 spacing.set(Spacing::Other, lexrc.GetFloat());
772                 break;
773         }
774 }
775
776
777 /* ******************************************************************* */
778
779 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
780                            string const & desc)
781         : name_(fn), latexname_(cln), description_(desc)
782 {
783         outputType_ = LATEX;
784         columns_ = 1;
785         sides_ = OneSide;
786         secnumdepth_ = 3;
787         tocdepth_ = 3;
788         pagestyle_ = "default";
789         maxcounter_ = LABEL_COUNTER_CHAPTER;
790         defaultfont_ = LyXFont(LyXFont::ALL_SANE);
791         opt_fontsize_ = "10|11|12";
792         opt_pagestyle_ = "empty|plain|headings|fancy";
793         provides_ = nothing;
794         loaded = false;
795 }
796
797
798 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
799 {
800         lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
801         if (!lay.Read(lexrc, *this)) {
802                 // Reslove fonts
803                 lay.resfont = lay.font;
804                 lay.resfont.realize(defaultfont());
805                 lay.reslabelfont = lay.labelfont;
806                 lay.reslabelfont.realize(defaultfont());
807                 return false; // no errors
808         } 
809         lyxerr << "Error parsing style `" << lay.name() << "'" << endl;
810         return true;
811 }
812
813
814 enum TextClassTags {
815         TC_OUTPUTTYPE = 1,
816         TC_INPUT,
817         TC_STYLE,
818         TC_NOSTYLE,
819         TC_COLUMNS,
820         TC_SIDES,
821         TC_PAGESTYLE,
822         TC_DEFAULTFONT,
823         TC_MAXCOUNTER,
824         TC_SECNUMDEPTH,
825         TC_TOCDEPTH,
826         TC_CLASSOPTIONS,
827         TC_PREAMBLE,
828         TC_PROVIDESAMSMATH,
829         TC_PROVIDESMAKEIDX,
830         TC_PROVIDESURL,
831         TC_LEFTMARGIN,
832         TC_RIGHTMARGIN
833 };
834
835
836 #if 0
837 static keyword_item textClassTags[] = {
838         { "classoptions",    TC_CLASSOPTIONS },
839         { "columns",         TC_COLUMNS },
840         { "defaultfont",     TC_DEFAULTFONT },
841         { "input",           TC_INPUT },
842         { "leftmargin",      TC_LEFTMARGIN },
843         { "maxcounter",      TC_MAXCOUNTER },
844         { "nostyle",         TC_NOSTYLE },
845         { "outputtype",      TC_OUTPUTTYPE },
846         { "pagestyle",       TC_PAGESTYLE },
847         { "preamble",        TC_PREAMBLE },
848         { "providesamsmath", TC_PROVIDESAMSMATH },
849         { "providesmakeidx", TC_PROVIDESMAKEIDX },
850         { "providesurl",     TC_PROVIDESURL },
851         { "rightmargin",     TC_RIGHTMARGIN },
852         { "secnumdepth",     TC_SECNUMDEPTH },
853         { "sides",           TC_SIDES },
854         { "style",           TC_STYLE },
855         { "tocdepth",        TC_TOCDEPTH }
856 };
857 #endif
858
859
860 // Reads a textclass structure from file.
861 bool LyXTextClass::Read(string const & filename, bool merge)
862 {
863         keyword_item textClassTags[] = {
864                 { "classoptions",    TC_CLASSOPTIONS },
865                 { "columns",         TC_COLUMNS },
866                 { "defaultfont",     TC_DEFAULTFONT },
867                 { "input",           TC_INPUT },
868                 { "leftmargin",      TC_LEFTMARGIN },
869                 { "maxcounter",      TC_MAXCOUNTER },
870                 { "nostyle",         TC_NOSTYLE },
871                 { "outputtype",      TC_OUTPUTTYPE },
872                 { "pagestyle",       TC_PAGESTYLE },
873                 { "preamble",        TC_PREAMBLE },
874                 { "providesamsmath", TC_PROVIDESAMSMATH },
875                 { "providesmakeidx", TC_PROVIDESMAKEIDX },
876                 { "providesurl",     TC_PROVIDESURL },
877                 { "rightmargin",     TC_RIGHTMARGIN },
878                 { "secnumdepth",     TC_SECNUMDEPTH },
879                 { "sides",           TC_SIDES },
880                 { "style",           TC_STYLE },
881                 { "tocdepth",        TC_TOCDEPTH }
882         };
883
884         if (!merge)
885                 lyxerr[Debug::TCLASS] << "Reading textclass "
886                                       << MakeDisplayPath(filename)
887                                       << endl;
888         else
889                 lyxerr[Debug::TCLASS] << "Reading input file "
890                                      << MakeDisplayPath(filename)
891                                      << endl;
892         
893         LyXLex lexrc(textClassTags, TC_RIGHTMARGIN);
894         bool error = false;
895
896         lexrc.setFile(filename);
897         if (!lexrc.IsOK()) error = true; 
898
899         // parsing
900         while (lexrc.IsOK() && !error) {
901                 int le = lexrc.lex();
902                 switch(le) {
903                 case LyXLex::LEX_FEOF:
904                         continue; 
905
906                 case LyXLex::LEX_UNDEF:                                 
907                         lexrc.printError("Unknown TextClass tag `$$Token'");
908                         error = true;
909                         continue; 
910                 default: break;
911                 }
912                 switch(static_cast<TextClassTags>(le)) {
913                 case TC_OUTPUTTYPE:   // output type definition
914                         readOutputType(lexrc);
915                         break;
916                         
917                 case TC_INPUT: // Include file
918                         if (lexrc.next()) {
919                                 string tmp = LibFileSearch("layouts",
920                                                             lexrc.GetString(), 
921                                                             "layout");
922                                 
923                                 if (Read(tmp, true)) {
924                                         lexrc.printError("Error reading input"
925                                                          "file: "+tmp);
926                                         error = true;
927                                 }
928                         }
929                         break;
930
931                 case TC_STYLE:
932                         if (lexrc.next()) {
933                                 string name = subst(lexrc.GetString(),
934                                                     '_', ' ');
935                                 if (hasLayout(name)) {
936                                         LyXLayout & lay = GetLayout(name);
937                                         error = do_readStyle(lexrc, lay);
938                                 } else {
939                                         LyXLayout lay;
940                                         lay.name(name);
941                                         if (!(error = do_readStyle(lexrc, lay)))
942                                                 layoutlist.push_back(lay);
943                                 }
944                         }
945                         else {
946                                 lexrc.printError("No name given for style: `$$Token'.");
947                                 error = true;
948                         }
949                         break;
950
951                 case TC_NOSTYLE:
952                         if (lexrc.next()) {
953                                 string style = subst(lexrc.GetString(),
954                                                      '_', ' ');
955                                 if (!delete_layout(style))
956                                         lexrc.printError("Cannot delete style"
957                                                          " `$$Token'");
958                         }
959                         break;
960
961                 case TC_COLUMNS:
962                         if (lexrc.next())
963                                 columns_ = lexrc.GetInteger();
964                         break;
965                         
966                 case TC_SIDES:
967                         if (lexrc.next()) {
968                                 switch(lexrc.GetInteger()) {
969                                 case 1: sides_ = OneSide; break;
970                                 case 2: sides_ = TwoSides; break;
971                                 default:
972                                         lyxerr << "Impossible number of page"
973                                                 " sides, setting to one."
974                                                << endl;
975                                         sides_ = OneSide;
976                                         break;
977                                 }
978                         }
979                         break;
980                         
981                 case TC_PAGESTYLE:
982                         lexrc.next();
983                         pagestyle_ = strip(lexrc.GetString());
984                         break;
985                         
986                 case TC_DEFAULTFONT:
987                         defaultfont_.lyxRead(lexrc);
988                         if (!defaultfont_.resolved()) {
989                                 lexrc.printError("Warning: defaultfont should "
990                                                  "be fully instantiated!");
991                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
992                         }
993                         break;
994
995                 case TC_MAXCOUNTER:
996                         readMaxCounter(lexrc);
997                         break;
998
999                 case TC_SECNUMDEPTH:
1000                         lexrc.next();
1001                         secnumdepth_ = lexrc.GetInteger();
1002                         break;
1003
1004                 case TC_TOCDEPTH:
1005                         lexrc.next();
1006                         tocdepth_ = lexrc.GetInteger();
1007                         break;
1008
1009                         // First step to support options 
1010                 case TC_CLASSOPTIONS:
1011                         readClassOptions(lexrc);
1012                         break;
1013
1014                 case TC_PREAMBLE:
1015                         preamble_ = lexrc.getLongString("EndPreamble");
1016                         break;
1017
1018                 case TC_PROVIDESAMSMATH:
1019                         if (lexrc.next() && lexrc.GetInteger())
1020                                 provides_ |= amsmath;
1021                         break;
1022
1023                 case TC_PROVIDESMAKEIDX:
1024                         if (lexrc.next() && lexrc.GetInteger())
1025                                 provides_ |= makeidx;
1026                         break;
1027
1028                 case TC_PROVIDESURL:
1029                         if (lexrc.next() && lexrc.GetInteger())
1030                                 provides_ = url;
1031                         break;
1032
1033                 case TC_LEFTMARGIN:     // left margin type
1034                         if (lexrc.next())
1035                                 leftmargin_ = lexrc.GetString();
1036                         break;                  
1037
1038                 case TC_RIGHTMARGIN:    // right margin type
1039                         if (lexrc.next())
1040                                 rightmargin_ = lexrc.GetString();
1041                         break;
1042                 }
1043         }       
1044
1045         if (!merge) { // we are at top level here.
1046                 lyxerr[Debug::TCLASS] << "Finished reading textclass " 
1047                                       << MakeDisplayPath(filename)
1048                                       << endl;
1049         } else
1050                 lyxerr[Debug::TCLASS] << "Finished reading input file " 
1051                                       << MakeDisplayPath(filename)
1052                                       << endl;
1053
1054         return error;
1055 }
1056
1057
1058 #if 0
1059 static keyword_item outputTypeTags[] = {
1060         { "docbook", DOCBOOK },
1061         { "latex", LATEX },
1062         { "linuxdoc", LINUXDOC },
1063         { "literate", LITERATE }
1064 };
1065 #endif
1066
1067 void LyXTextClass::readOutputType(LyXLex & lexrc)
1068 {
1069         keyword_item outputTypeTags[] = {
1070                 { "docbook", DOCBOOK },
1071                 { "latex", LATEX },
1072                 { "linuxdoc", LINUXDOC },
1073                 { "literate", LITERATE }
1074         };
1075
1076         pushpophelper pph(lexrc, outputTypeTags, LITERATE);
1077
1078         int le = lexrc.lex();
1079         switch(le) {
1080         case LyXLex::LEX_UNDEF:
1081                 lexrc.printError("Unknown output type `$$Token'");
1082                 return;
1083         case LATEX:
1084         case LINUXDOC:
1085         case DOCBOOK:
1086         case LITERATE:
1087                 outputType_ = static_cast<OutputType>(le);
1088                 break;
1089         default:
1090                 lyxerr << "Unhandled value " << le
1091                        << " in LyXTextClass::readOutputType." << endl;
1092
1093                 break;
1094         }
1095 }
1096
1097
1098 enum MaxCounterTags {
1099         MC_COUNTER_CHAPTER = 1,
1100         MC_COUNTER_SECTION,
1101         MC_COUNTER_SUBSECTION,
1102         MC_COUNTER_SUBSUBSECTION,
1103         MC_COUNTER_PARAGRAPH,
1104         MC_COUNTER_SUBPARAGRAPH,
1105         MC_COUNTER_ENUMI,
1106         MC_COUNTER_ENUMII,
1107         MC_COUNTER_ENUMIII,
1108         MC_COUNTER_ENUMIV
1109 };
1110
1111
1112 #if 0
1113 static keyword_item maxCounterTags[] = {
1114         {"counter_chapter", MC_COUNTER_CHAPTER },
1115         {"counter_enumi", MC_COUNTER_ENUMI },
1116         {"counter_enumii", MC_COUNTER_ENUMII },
1117         {"counter_enumiii", MC_COUNTER_ENUMIII },
1118         {"counter_enumiv", MC_COUNTER_ENUMIV },
1119         {"counter_paragraph", MC_COUNTER_PARAGRAPH },
1120         {"counter_section", MC_COUNTER_SECTION },
1121         {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
1122         {"counter_subsection", MC_COUNTER_SUBSECTION },
1123         {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
1124 };
1125 #endif
1126
1127
1128 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
1129 {
1130         keyword_item maxCounterTags[] = {
1131                 {"counter_chapter", MC_COUNTER_CHAPTER },
1132                 {"counter_enumi", MC_COUNTER_ENUMI },
1133                 {"counter_enumii", MC_COUNTER_ENUMII },
1134                 {"counter_enumiii", MC_COUNTER_ENUMIII },
1135                 {"counter_enumiv", MC_COUNTER_ENUMIV },
1136                 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
1137                 {"counter_section", MC_COUNTER_SECTION },
1138                 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
1139                 {"counter_subsection", MC_COUNTER_SUBSECTION },
1140                 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
1141         };
1142
1143         pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
1144         int le = lexrc.lex();
1145         switch(le) {
1146         case LyXLex::LEX_UNDEF:
1147                 lexrc.printError("Unknown MaxCounter tag `$$Token'");
1148                 return; 
1149         default: break;
1150         }
1151         switch (static_cast<MaxCounterTags>(le)) {
1152         case MC_COUNTER_CHAPTER:
1153                 maxcounter_ = LABEL_COUNTER_CHAPTER;
1154                 break;
1155         case MC_COUNTER_SECTION:
1156                 maxcounter_ = LABEL_COUNTER_SECTION;
1157                 break;
1158         case MC_COUNTER_SUBSECTION:
1159                 maxcounter_ = LABEL_COUNTER_SUBSECTION;
1160                 break;
1161         case MC_COUNTER_SUBSUBSECTION:
1162                 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
1163                 break;
1164         case MC_COUNTER_PARAGRAPH:
1165                 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
1166                 break;
1167         case MC_COUNTER_SUBPARAGRAPH:
1168                 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
1169                 break;
1170         case MC_COUNTER_ENUMI:
1171                 maxcounter_ = LABEL_COUNTER_ENUMI;
1172                 break;
1173         case MC_COUNTER_ENUMII:
1174                 maxcounter_ = LABEL_COUNTER_ENUMII;
1175                 break;
1176         case MC_COUNTER_ENUMIII:
1177                 maxcounter_ = LABEL_COUNTER_ENUMIII;
1178                 break;
1179         case MC_COUNTER_ENUMIV:
1180                 maxcounter_ = LABEL_COUNTER_ENUMIV;
1181                 break;
1182         }
1183 }
1184
1185
1186 enum ClassOptionsTags {
1187         CO_FONTSIZE = 1,
1188         CO_PAGESTYLE,
1189         CO_OTHER,
1190         CO_END
1191 };
1192
1193
1194 #if 0
1195 static keyword_item classOptionsTags[] = {
1196         {"end", CO_END },
1197         {"fontsize", CO_FONTSIZE },
1198         {"other", CO_OTHER },
1199         {"pagestyle", CO_PAGESTYLE }
1200 };
1201 #endif
1202
1203
1204 void LyXTextClass::readClassOptions(LyXLex & lexrc)
1205 {
1206         keyword_item classOptionsTags[] = {
1207                 {"end", CO_END },
1208                 {"fontsize", CO_FONTSIZE },
1209                 {"other", CO_OTHER },
1210                 {"pagestyle", CO_PAGESTYLE }
1211         };
1212
1213         lexrc.pushTable(classOptionsTags, CO_END);
1214         bool getout = false;
1215         while (!getout && lexrc.IsOK()) {
1216                 int le = lexrc.lex();
1217                 switch (le) {
1218                 case LyXLex::LEX_UNDEF:
1219                         lexrc.printError("Unknown ClassOption tag `$$Token'");
1220                         continue; 
1221                 default: break;
1222                 }
1223                 switch (static_cast<ClassOptionsTags>(le)) {
1224                 case CO_FONTSIZE:
1225                         lexrc.next();
1226                         opt_fontsize_ = strip(lexrc.GetString());
1227                         break;
1228                 case CO_PAGESTYLE:
1229                         lexrc.next();
1230                         opt_pagestyle_ = strip(lexrc.GetString()); 
1231                         break;
1232                 case CO_OTHER:
1233                         lexrc.next();
1234                         options_ = lexrc.GetString();
1235                         break;
1236                 case CO_END:
1237                         getout = true;
1238                         break;
1239                 }
1240         }
1241         lexrc.popTable();
1242 }
1243
1244
1245 bool LyXTextClass::hasLayout(string const & name) const
1246 {
1247         for (LayoutList::const_iterator cit = layoutlist.begin();
1248              cit != layoutlist.end(); ++cit) {
1249                 if ((*cit).name() == name)
1250                         return true;
1251         }
1252         return false;
1253 }
1254
1255
1256 LyXLayout const & LyXTextClass::GetLayout (string const & name) const
1257 {
1258         for (LayoutList::const_iterator cit = layoutlist.begin();
1259              cit != layoutlist.end(); ++cit) {
1260                 if ((*cit).name() == name)
1261                         return (*cit);
1262         }
1263         Assert(false); // we actually require the name to exist.
1264         return layoutlist.front();
1265 }
1266
1267
1268 LyXLayout & LyXTextClass::GetLayout(string const & name)
1269 {
1270         for (LayoutList::iterator it = layoutlist.begin();
1271              it != layoutlist.end(); ++it) {
1272                 if ((*it).name() == name)
1273                         return (*it);
1274         }
1275         Assert(false); // we actually require the name to exist.
1276         return layoutlist.front();
1277 }
1278
1279
1280 bool LyXTextClass::delete_layout (string const & name)
1281 {
1282         for(LayoutList::iterator it = layoutlist.begin();
1283             it != layoutlist.end(); ++it) {
1284                 if ((*it).name() == name) {
1285                         layoutlist.erase(it);
1286                         return true;
1287                 }
1288         }
1289         return false;
1290 }
1291
1292
1293 // Load textclass info if not loaded yet
1294 void LyXTextClass::load()
1295 {
1296         if (loaded) return;
1297
1298         // Read style-file
1299         string real_file = LibFileSearch("layouts", name_, "layout");
1300
1301         if (Read(real_file)) {
1302                 lyxerr << "Error reading `"
1303                        << MakeDisplayPath(real_file)
1304                        << "'\n(Check `" << name_
1305                        << "')\nCheck your installation and "
1306                         "try Options/Reconfigure..." << endl;
1307         }
1308         loaded = true;
1309 }
1310
1311
1312 //////////////////////////////////////////
1313
1314 // Gets textclass number from name
1315 pair<bool, LyXTextClassList::size_type>
1316 LyXTextClassList::NumberOfClass(string const & textclass) const
1317 {
1318         for (ClassList::const_iterator cit = classlist.begin();
1319              cit != classlist.end(); ++cit) {
1320                 if ((*cit).name() == textclass)
1321                         return make_pair(true, cit - classlist.begin());
1322         }
1323         return make_pair(false, size_type(0));
1324 }
1325
1326
1327 // Gets layout structure from style number and textclass number
1328 LyXLayout const &
1329 LyXTextClassList::Style(LyXTextClassList::size_type textclass,
1330                         LyXTextClass::size_type layout) const
1331 {
1332         classlist[textclass].load();
1333         if (layout < classlist[textclass].numLayouts())
1334                 return classlist[textclass][layout];
1335         return classlist[textclass][0];
1336 }
1337
1338
1339 // Gets layout number from name and textclass number
1340 pair<bool, LyXTextClass::size_type>
1341 LyXTextClassList::NumberOfLayout(LyXTextClassList::size_type textclass,
1342                                  string const & name) const
1343 {
1344         classlist[textclass].load();
1345         for(unsigned int i = 0; i < classlist[textclass].numLayouts(); ++i) {
1346                 if (classlist[textclass][i].name() == name)
1347                         return make_pair(true, i);
1348         }
1349         if (name == "dummy")
1350                 return make_pair(true, LYX_DUMMY_LAYOUT);
1351         return make_pair(false, LyXTextClass::LayoutList::size_type(0)); // not found
1352 }
1353
1354
1355 // Gets a layout (style) name from layout number and textclass number
1356 string const &
1357 LyXTextClassList::NameOfLayout(LyXTextClassList::size_type textclass,
1358                                LyXTextClass::size_type layout) const
1359 {
1360         static string dummy("dummy");
1361         classlist[textclass].load();
1362         if (layout < classlist[textclass].numLayouts())
1363                 return classlist[textclass][layout].name();
1364         return dummy;
1365 }
1366
1367
1368 // Gets a textclass name from number
1369 string const &
1370 LyXTextClassList::NameOfClass(LyXTextClassList::size_type number) const
1371 {
1372         static string dummy("dummy");
1373         if (classlist.size() == 0) {
1374                 return dummy;
1375         }
1376         Assert(number < classlist.size());
1377         return classlist[number].name();
1378 }
1379
1380
1381 // Gets a textclass latexname from number
1382 string const &
1383 LyXTextClassList::LatexnameOfClass(LyXTextClassList::size_type number) const
1384 {
1385         static string dummy("dummy");
1386         classlist[number].load();
1387         if (classlist.size() == 0) {
1388                 return dummy;
1389         }
1390         Assert(number < classlist.size());
1391         return classlist[number].latexname();
1392 }
1393
1394
1395 // Gets a textclass description from number
1396 string const &
1397 LyXTextClassList::DescOfClass(LyXTextClassList::size_type number) const
1398 {
1399         static string dummy("dummy");
1400         if (classlist.size() == 0) {
1401                 return dummy;
1402         }
1403         Assert(number < classlist.size());
1404         return classlist[number].description();
1405 }
1406
1407
1408 // Gets a textclass structure from number
1409 LyXTextClass const &
1410 LyXTextClassList::TextClass(LyXTextClassList::size_type textclass) const
1411 {
1412         classlist[textclass].load();
1413         if (textclass < classlist.size())
1414                 return classlist[textclass];
1415         else
1416                 return classlist[0];
1417 }
1418
1419
1420 void LyXTextClassList::Add(LyXTextClass const & t)
1421 {
1422         classlist.push_back(t);
1423 }
1424
1425
1426 // used when sorting the textclass list.
1427 class less_textclass_desc {
1428 public:
1429         int operator()(LyXTextClass const & tc1, LyXTextClass const & tc2) {
1430                 return tc1.description() < tc2.description();
1431         }
1432 };
1433
1434
1435 // Reads LyX textclass definitions according to textclass config file
1436 bool LyXTextClassList::Read ()
1437 {
1438         LyXLex lex(0, 0);
1439         string real_file = LibFileSearch("", "textclass.lst");
1440         lyxerr[Debug::TCLASS] << "Reading textclasses from `"
1441                               << real_file << "'" << endl;
1442
1443         if (real_file.empty()) {
1444                 lyxerr << "LyXTextClassList::Read: unable to find "
1445                         "textclass file  `" << MakeDisplayPath(real_file, 1000)
1446                        << "'. Exiting." << endl;
1447
1448                 WriteAlert(_("LyX wasn't able to find its layout descriptions!"),
1449                            _("Check that the file \"textclass.lst\""),
1450                            _("is installed correctly. Sorry, has to exit :-("));
1451                 return false;
1452                 // This causes LyX to end... Not a desirable behaviour. Lgb
1453                 // What do you propose? That the user gets a file dialog
1454                 // and is allowed to hunt for the file? (Asger)
1455                 // more that we have a layout for minimal.cls statically
1456                 // compiled in... (Lgb)
1457         }
1458
1459         if (!lex.setFile(real_file)) {
1460                 lyxerr << "LyXTextClassList::Read: "
1461                         "lyxlex was not able to set file: "
1462                        << real_file << endl;
1463         }
1464         
1465         if (!lex.IsOK()) {
1466                 lyxerr << "LyXTextClassList::Read: unable to open "
1467                         "textclass file  `" << MakeDisplayPath(real_file, 1000)
1468                        << "'\nCheck your installation. LyX can't continue."
1469                        << endl;
1470                 return false;
1471         }
1472         bool finished = false;
1473         string fname, clname, desc;
1474         // Parse config-file
1475         lyxerr[Debug::TCLASS] << "Starting parsing of textclass.lst" << endl;
1476         while (lex.IsOK() && !finished) {
1477                 lyxerr[Debug::TCLASS] << "\tline by line" << endl;
1478                 switch (lex.lex()) {
1479                 case LyXLex::LEX_FEOF:
1480                         finished = true;
1481                         break;
1482                 default:
1483                         fname = lex.GetString();
1484                         lyxerr[Debug::TCLASS] << "Fname: " << fname << endl;
1485                         if (lex.next()) {
1486                                 clname = lex.GetString();
1487                                 lyxerr[Debug::TCLASS]
1488                                         << "Clname: " << clname << endl;
1489                                 if (lex.next()) {
1490                                               desc = lex.GetString();
1491                                               lyxerr[Debug::TCLASS]
1492                                                       << "Desc: " << desc << endl;
1493                                               // This code is run when we have
1494                                               // fname, clname and desc
1495                                               LyXTextClass tmpl(fname,
1496                                                                 clname,
1497                                                                 desc);
1498                                               if (lyxerr.
1499                                                   debugging(Debug::TCLASS)) {
1500                                                       tmpl.load();
1501                                               }
1502                                               Add (tmpl);
1503                                 }
1504                         }
1505                 }
1506         }
1507         lyxerr[Debug::TCLASS] << "End of parsing of textclass.lst" << endl;
1508
1509         if (classlist.size() == 0) {
1510                 lyxerr << "LyXTextClassList::Read: no textclasses found!"
1511                        << endl;
1512                 WriteAlert(_("LyX wasn't able to find any layout description!"),
1513                            _("Check the contents of  the file \"textclass.lst\""),
1514                            _("Sorry, has to exit :-("));
1515                 return false;
1516         }
1517         // Ok everything loaded ok, now sort the list.
1518         sort(classlist.begin(), classlist.end(), less_textclass_desc());
1519         return true;
1520 }
1521
1522         
1523 /* Load textclass
1524    Returns false if this fails
1525 */
1526 bool
1527 LyXTextClassList::Load (LyXTextClassList::size_type number) const
1528 {
1529         bool result = true;
1530         if (number < classlist.size()) {
1531                 classlist[number].load();
1532                 if (classlist[number].numLayouts() == 0) {
1533                         result = false;
1534                 }
1535         } else {
1536                 result = false;
1537         }
1538         return result;
1539 }
1540
1541
1542 std::ostream & operator<<(std::ostream & os, LyXTextClass::PageSides p)
1543 {
1544         switch (p) {
1545         case LyXTextClass::OneSide:
1546                 os << "1";
1547                 break;
1548         case LyXTextClass::TwoSides:
1549                 os << "2";
1550                 break;
1551         }
1552         return os;
1553 }