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