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