]> git.lyx.org Git - lyx.git/blob - src/lyxtextclass.C
3e2365c60ad0486842a49aeeefaaf774517882ee
[lyx.git] / src / lyxtextclass.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *          Copyright 1995 Matthias Ettrich
7  *          Copyright 1995-2001 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13
14 #include "lyxtextclass.h"
15 #include "debug.h"
16 #include "lyxlex.h"
17 #include "counters.h"
18 #include "FloatList.h"
19
20 #include "support/lstrings.h"
21 #include "support/LAssert.h"
22 #include "support/lyxfunctional.h"
23 #include "support/filetools.h"
24
25 #include <algorithm>
26
27 using std::endl;
28 using std::find_if;
29 using std::remove_if;
30 using std::ostream;
31
32 namespace { // anon
33
34 struct compare_name {
35
36         compare_name(string const & name)
37                 : name_(name)
38         {}
39
40         bool operator()(boost::shared_ptr<LyXLayout> const & c)
41         {
42                 //lyxerr << "comparing '" << name_ << "' to '" << c->name() << "'\n";
43                 return c->name() == name_;
44         }
45
46         string name_;
47
48 };
49
50 } // anon
51
52
53 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
54                            string const & desc)
55         : name_(fn), latexname_(cln), description_(desc),
56           floatlist_(new FloatList), ctrs_(new Counters)
57 {
58         outputType_ = LATEX;
59         columns_ = 1;
60         sides_ = OneSide;
61         secnumdepth_ = 3;
62         tocdepth_ = 3;
63         pagestyle_ = "default";
64         maxcounter_ = LABEL_COUNTER_CHAPTER;
65         defaultfont_ = LyXFont(LyXFont::ALL_SANE);
66         opt_fontsize_ = "10|11|12";
67         opt_pagestyle_ = "empty|plain|headings|fancy";
68         provides_ = nothing;
69         titletype_ = TITLE_COMMAND_AFTER;
70         titlename_ = "maketitle";
71         loaded = false;
72 }
73
74
75 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
76 {
77         lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
78         if (!lay.Read(lexrc, *this)) {
79                 // Resolve fonts
80                 lay.resfont = lay.font;
81                 lay.resfont.realize(defaultfont());
82                 lay.reslabelfont = lay.labelfont;
83                 lay.reslabelfont.realize(defaultfont());
84                 return false; // no errors
85         }
86         lyxerr << "Error parsing style `" << lay.name() << '\'' << endl;
87         return true;
88 }
89
90
91 enum TextClassTags {
92         TC_OUTPUTTYPE = 1,
93         TC_INPUT,
94         TC_STYLE,
95         TC_DEFAULTSTYLE,
96         TC_NOSTYLE,
97         TC_COLUMNS,
98         TC_SIDES,
99         TC_PAGESTYLE,
100         TC_DEFAULTFONT,
101         TC_MAXCOUNTER,
102         TC_SECNUMDEPTH,
103         TC_TOCDEPTH,
104         TC_CLASSOPTIONS,
105         TC_PREAMBLE,
106         TC_PROVIDESAMSMATH,
107         TC_PROVIDESNATBIB,
108         TC_PROVIDESMAKEIDX,
109         TC_PROVIDESURL,
110         TC_LEFTMARGIN,
111         TC_RIGHTMARGIN,
112         TC_FLOAT,
113         TC_COUNTER,
114         TC_NOFLOAT,
115         TC_TITLELATEXNAME,
116         TC_TITLELATEXTYPE,
117         TC_ENVIRONMENT
118 };
119
120 // Reads a textclass structure from file.
121 bool LyXTextClass::Read(string const & filename, bool merge)
122 {
123         keyword_item textClassTags[] = {
124                 { "classoptions",    TC_CLASSOPTIONS },
125                 { "columns",         TC_COLUMNS },
126                 { "counter",         TC_COUNTER },
127                 { "defaultfont",     TC_DEFAULTFONT },
128                 { "defaultstyle",    TC_DEFAULTSTYLE },
129                 { "float",           TC_FLOAT },
130                 { "input",           TC_INPUT },
131                 { "leftmargin",      TC_LEFTMARGIN },
132                 { "maxcounter",      TC_MAXCOUNTER },
133                 { "nofloat",         TC_NOFLOAT },
134                 { "nostyle",         TC_NOSTYLE },
135                 { "outputtype",      TC_OUTPUTTYPE },
136                 { "pagestyle",       TC_PAGESTYLE },
137                 { "preamble",        TC_PREAMBLE },
138                 { "providesamsmath", TC_PROVIDESAMSMATH },
139                 { "providesmakeidx", TC_PROVIDESMAKEIDX },
140                 { "providesnatbib",  TC_PROVIDESNATBIB },
141                 { "providesurl",     TC_PROVIDESURL },
142                 { "rightmargin",     TC_RIGHTMARGIN },
143                 { "secnumdepth",     TC_SECNUMDEPTH },
144                 { "sides",           TC_SIDES },
145                 { "style",           TC_STYLE },
146                 { "titlelatexname",  TC_TITLELATEXNAME },
147                 { "titlelatextype",  TC_TITLELATEXTYPE },
148                 { "tocdepth",        TC_TOCDEPTH }
149         };
150
151         if (!merge)
152                 lyxerr[Debug::TCLASS] << "Reading textclass "
153                                       << MakeDisplayPath(filename)
154                                       << endl;
155         else
156                 lyxerr[Debug::TCLASS] << "Reading input file "
157                                      << MakeDisplayPath(filename)
158                                      << endl;
159
160         LyXLex lexrc(textClassTags, TC_TITLELATEXTYPE);
161         bool error = false;
162
163         lexrc.setFile(filename);
164         if (!lexrc.isOK()) error = true;
165
166         // parsing
167         while (lexrc.isOK() && !error) {
168                 int le = lexrc.lex();
169                 switch (le) {
170                 case LyXLex::LEX_FEOF:
171                         continue;
172
173                 case LyXLex::LEX_UNDEF:
174                         lexrc.printError("Unknown TextClass tag `$$Token'");
175                         error = true;
176                         continue;
177                 default: break;
178                 }
179                 switch (static_cast<TextClassTags>(le)) {
180                 case TC_OUTPUTTYPE:   // output type definition
181                         readOutputType(lexrc);
182                         break;
183
184                 case TC_INPUT: // Include file
185                         if (lexrc.next()) {
186                                 string tmp = LibFileSearch("layouts",
187                                                             lexrc.getString(),
188                                                             "layout");
189
190                                 if (Read(tmp, true)) {
191                                         lexrc.printError("Error reading input"
192                                                          "file: "+tmp);
193                                         error = true;
194                                 }
195                         }
196                         break;
197
198                 case TC_DEFAULTSTYLE:
199                         if (lexrc.next()) {
200                                 string const name = subst(lexrc.getString(),
201                                                           '_', ' ');
202                                 defaultlayout_ = name;
203                         }
204                         break;
205
206                 case TC_STYLE:
207                         if (lexrc.next()) {
208                                 string const name = subst(lexrc.getString(),
209                                                     '_', ' ');
210                                 if (hasLayout(name)) {
211                                         LyXLayout * lay = operator[](name).get();
212                                         error = do_readStyle(lexrc, *lay);
213                                 } else {
214                                         LyXLayout lay;
215                                         lay.setName(name);
216                                         if (!(error = do_readStyle(lexrc, lay)))
217                                                 layoutlist_.push_back(boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
218                                         if (defaultlayout_.empty()) {
219                                                 // We do not have a default
220                                                 // layout yet, so we choose
221                                                 // the first layout we
222                                                 // encounter.
223                                                 defaultlayout_ = name;
224                                         }
225                                 }
226                         }
227                         else {
228                                 lexrc.printError("No name given for style: `$$Token'.");
229                                 error = true;
230                         }
231                         break;
232
233                 case TC_ENVIRONMENT:
234                         if (lexrc.next()) {
235                                 string const name = subst(lexrc.getString(),
236                                                     '_', ' ');
237                                 if (hasLayout(name)) {
238                                         LyXLayout * lay = operator[](name).get();
239                                         error = do_readStyle(lexrc, *lay);
240                                 } else {
241                                         LyXLayout lay;
242                                         lay.setName(name);
243                                         if (!(error = do_readStyle(lexrc, lay)))
244                                                 envlist_.push_back
245                                                         (boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
246                                         else
247                                                 lexrc.printError("Problems reading environment: `$$Token'.");
248                                 }
249                         }
250                         else {
251                                 lexrc.printError("No name given for style: `$$Token'.");
252                                 error = true;
253                         }
254                         break;
255
256                 case TC_NOSTYLE:
257                         if (lexrc.next()) {
258                                 string const style = subst(lexrc.getString(),
259                                                      '_', ' ');
260                                 if (!delete_layout(style))
261                                         lyxerr << "Cannot delete style `"
262                                                << style << '\'' << endl;
263 //                                      lexrc.printError("Cannot delete style"
264 //                                                       " `$$Token'");
265                         }
266                         break;
267
268                 case TC_COLUMNS:
269                         if (lexrc.next())
270                                 columns_ = lexrc.getInteger();
271                         break;
272
273                 case TC_SIDES:
274                         if (lexrc.next()) {
275                                 switch (lexrc.getInteger()) {
276                                 case 1: sides_ = OneSide; break;
277                                 case 2: sides_ = TwoSides; break;
278                                 default:
279                                         lyxerr << "Impossible number of page"
280                                                 " sides, setting to one."
281                                                << endl;
282                                         sides_ = OneSide;
283                                         break;
284                                 }
285                         }
286                         break;
287
288                 case TC_PAGESTYLE:
289                         lexrc.next();
290                         pagestyle_ = rtrim(lexrc.getString());
291                         break;
292
293                 case TC_DEFAULTFONT:
294                         defaultfont_.lyxRead(lexrc);
295                         if (!defaultfont_.resolved()) {
296                                 lexrc.printError("Warning: defaultfont should "
297                                                  "be fully instantiated!");
298                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
299                         }
300                         break;
301
302                 case TC_MAXCOUNTER:
303                         readMaxCounter(lexrc);
304                         break;
305
306                 case TC_SECNUMDEPTH:
307                         lexrc.next();
308                         secnumdepth_ = lexrc.getInteger();
309                         break;
310
311                 case TC_TOCDEPTH:
312                         lexrc.next();
313                         tocdepth_ = lexrc.getInteger();
314                         break;
315
316                         // First step to support options
317                 case TC_CLASSOPTIONS:
318                         readClassOptions(lexrc);
319                         break;
320
321                 case TC_PREAMBLE:
322                         preamble_ = lexrc.getLongString("EndPreamble");
323                         break;
324
325                 case TC_PROVIDESAMSMATH:
326                         if (lexrc.next() && lexrc.getInteger())
327                                 provides_ |= amsmath;
328                         break;
329
330                 case TC_PROVIDESNATBIB:
331                         if (lexrc.next() && lexrc.getInteger())
332                                 provides_ |= natbib;
333                         break;
334
335                 case TC_PROVIDESMAKEIDX:
336                         if (lexrc.next() && lexrc.getInteger())
337                                 provides_ |= makeidx;
338                         break;
339
340                 case TC_PROVIDESURL:
341                         if (lexrc.next() && lexrc.getInteger())
342                                 provides_ |= url;
343                         break;
344
345                 case TC_LEFTMARGIN:     // left margin type
346                         if (lexrc.next())
347                                 leftmargin_ = lexrc.getString();
348                         break;
349
350                 case TC_RIGHTMARGIN:    // right margin type
351                         if (lexrc.next())
352                                 rightmargin_ = lexrc.getString();
353                         break;
354                 case TC_FLOAT:
355                         readFloat(lexrc);
356                         break;
357                 case TC_COUNTER:
358                         readCounter(lexrc);
359                         break;
360                 case TC_TITLELATEXTYPE:
361                         readTitleType(lexrc);
362                         break;
363                 case TC_TITLELATEXNAME:
364                         if (lexrc.next())
365                                 titlename_ = lexrc.getString();
366                         break;
367                 case TC_NOFLOAT:
368                         if (lexrc.next()) {
369                                 string const nofloat = lexrc.getString();
370                                 floatlist_->erase(nofloat);
371                         }
372                         break;
373                 }
374         }
375
376         if (!merge) { // we are at top level here.
377                 lyxerr[Debug::TCLASS] << "Finished reading textclass "
378                                       << MakeDisplayPath(filename)
379                                       << endl;
380                 if (defaultlayout_.empty()) {
381                         lyxerr << "Error: Textclass '" << name_
382                                << "' is missing a defaultstyle." << endl;
383                         error = true;
384                 }
385         } else
386                 lyxerr[Debug::TCLASS] << "Finished reading input file "
387                                       << MakeDisplayPath(filename)
388                                       << endl;
389
390         return error;
391 }
392
393
394 void LyXTextClass::readTitleType(LyXLex & lexrc)
395 {
396         keyword_item titleTypeTags[] = {
397                 { "commandafter", TITLE_COMMAND_AFTER },
398                 { "environment", TITLE_ENVIRONMENT }
399         };
400
401         pushpophelper pph(lexrc, titleTypeTags, TITLE_ENVIRONMENT);
402
403         int le = lexrc.lex();
404         switch (le) {
405         case LyXLex::LEX_UNDEF:
406                 lexrc.printError("Unknown output type `$$Token'");
407                 return;
408         case TITLE_COMMAND_AFTER:
409         case TITLE_ENVIRONMENT:
410                 titletype_ = static_cast<LYX_TITLE_LATEX_TYPES>(le);
411                 break;
412         default:
413                 lyxerr << "Unhandled value " << le
414                        << " in LyXTextClass::readTitleType." << endl;
415
416                 break;
417         }
418 }
419
420
421 void LyXTextClass::readOutputType(LyXLex & lexrc)
422 {
423         keyword_item outputTypeTags[] = {
424                 { "docbook", DOCBOOK },
425                 { "latex", LATEX },
426                 { "linuxdoc", LINUXDOC },
427                 { "literate", LITERATE }
428         };
429
430         pushpophelper pph(lexrc, outputTypeTags, LITERATE);
431
432         int le = lexrc.lex();
433         switch (le) {
434         case LyXLex::LEX_UNDEF:
435                 lexrc.printError("Unknown output type `$$Token'");
436                 return;
437         case LATEX:
438         case LINUXDOC:
439         case DOCBOOK:
440         case LITERATE:
441                 outputType_ = static_cast<OutputType>(le);
442                 break;
443         default:
444                 lyxerr << "Unhandled value " << le
445                        << " in LyXTextClass::readOutputType." << endl;
446
447                 break;
448         }
449 }
450
451
452 enum MaxCounterTags {
453         MC_COUNTER_CHAPTER = 1,
454         MC_COUNTER_SECTION,
455         MC_COUNTER_SUBSECTION,
456         MC_COUNTER_SUBSUBSECTION,
457         MC_COUNTER_PARAGRAPH,
458         MC_COUNTER_SUBPARAGRAPH,
459         MC_COUNTER_ENUMI,
460         MC_COUNTER_ENUMII,
461         MC_COUNTER_ENUMIII,
462         MC_COUNTER_ENUMIV
463 };
464
465
466 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
467 {
468         keyword_item maxCounterTags[] = {
469                 {"counter_chapter", MC_COUNTER_CHAPTER },
470                 {"counter_enumi", MC_COUNTER_ENUMI },
471                 {"counter_enumii", MC_COUNTER_ENUMII },
472                 {"counter_enumiii", MC_COUNTER_ENUMIII },
473                 {"counter_enumiv", MC_COUNTER_ENUMIV },
474                 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
475                 {"counter_section", MC_COUNTER_SECTION },
476                 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
477                 {"counter_subsection", MC_COUNTER_SUBSECTION },
478                 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
479         };
480
481         pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
482         int le = lexrc.lex();
483         switch (le) {
484         case LyXLex::LEX_UNDEF:
485                 lexrc.printError("Unknown MaxCounter tag `$$Token'");
486                 return;
487         default: break;
488         }
489         switch (static_cast<MaxCounterTags>(le)) {
490         case MC_COUNTER_CHAPTER:
491                 maxcounter_ = LABEL_COUNTER_CHAPTER;
492                 break;
493         case MC_COUNTER_SECTION:
494                 maxcounter_ = LABEL_COUNTER_SECTION;
495                 break;
496         case MC_COUNTER_SUBSECTION:
497                 maxcounter_ = LABEL_COUNTER_SUBSECTION;
498                 break;
499         case MC_COUNTER_SUBSUBSECTION:
500                 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
501                 break;
502         case MC_COUNTER_PARAGRAPH:
503                 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
504                 break;
505         case MC_COUNTER_SUBPARAGRAPH:
506                 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
507                 break;
508         case MC_COUNTER_ENUMI:
509                 maxcounter_ = LABEL_COUNTER_ENUMI;
510                 break;
511         case MC_COUNTER_ENUMII:
512                 maxcounter_ = LABEL_COUNTER_ENUMII;
513                 break;
514         case MC_COUNTER_ENUMIII:
515                 maxcounter_ = LABEL_COUNTER_ENUMIII;
516                 break;
517         case MC_COUNTER_ENUMIV:
518                 maxcounter_ = LABEL_COUNTER_ENUMIV;
519                 break;
520         }
521 }
522
523
524 enum ClassOptionsTags {
525         CO_FONTSIZE = 1,
526         CO_PAGESTYLE,
527         CO_OTHER,
528         CO_END
529 };
530
531
532 void LyXTextClass::readClassOptions(LyXLex & lexrc)
533 {
534         keyword_item classOptionsTags[] = {
535                 {"end", CO_END },
536                 {"fontsize", CO_FONTSIZE },
537                 {"other", CO_OTHER },
538                 {"pagestyle", CO_PAGESTYLE }
539         };
540
541         lexrc.pushTable(classOptionsTags, CO_END);
542         bool getout = false;
543         while (!getout && lexrc.isOK()) {
544                 int le = lexrc.lex();
545                 switch (le) {
546                 case LyXLex::LEX_UNDEF:
547                         lexrc.printError("Unknown ClassOption tag `$$Token'");
548                         continue;
549                 default: break;
550                 }
551                 switch (static_cast<ClassOptionsTags>(le)) {
552                 case CO_FONTSIZE:
553                         lexrc.next();
554                         opt_fontsize_ = rtrim(lexrc.getString());
555                         break;
556                 case CO_PAGESTYLE:
557                         lexrc.next();
558                         opt_pagestyle_ = rtrim(lexrc.getString());
559                         break;
560                 case CO_OTHER:
561                         lexrc.next();
562                         options_ = lexrc.getString();
563                         break;
564                 case CO_END:
565                         getout = true;
566                         break;
567                 }
568         }
569         lexrc.popTable();
570 }
571
572
573 enum FloatTags {
574         FT_TYPE = 1,
575         FT_NAME,
576         FT_PLACEMENT,
577         FT_EXT,
578         FT_WITHIN,
579         FT_STYLE,
580         FT_LISTNAME,
581         FT_BUILTIN,
582         FT_END
583 };
584
585 void LyXTextClass::readFloat(LyXLex & lexrc)
586 {
587         keyword_item floatTags[] = {
588                 { "end", FT_END },
589                 { "extension", FT_EXT },
590                 { "guiname", FT_NAME },
591                 { "latexbuiltin", FT_BUILTIN },
592                 { "listname", FT_LISTNAME },
593                 { "numberwithin", FT_WITHIN },
594                 { "placement", FT_PLACEMENT },
595                 { "style", FT_STYLE },
596                 { "type", FT_TYPE }
597         };
598
599         lexrc.pushTable(floatTags, FT_END);
600
601         string type;
602         string placement;
603         string ext;
604         string within;
605         string style;
606         string name;
607         string listname;
608         bool builtin = false;
609
610         bool getout = false;
611         while (!getout && lexrc.isOK()) {
612                 int le = lexrc.lex();
613                 switch (le) {
614                 case LyXLex::LEX_UNDEF:
615                         lexrc.printError("Unknown ClassOption tag `$$Token'");
616                         continue;
617                 default: break;
618                 }
619                 switch (static_cast<FloatTags>(le)) {
620                 case FT_TYPE:
621                         lexrc.next();
622                         type = lexrc.getString();
623                         // Here we could check if this type is already defined
624                         // and modify it with the rest of the vars instead.
625                         break;
626                 case FT_NAME:
627                         lexrc.next();
628                         name = lexrc.getString();
629                         break;
630                 case FT_PLACEMENT:
631                         lexrc.next();
632                         placement = lexrc.getString();
633                         break;
634                 case FT_EXT:
635                         lexrc.next();
636                         ext = lexrc.getString();
637                         break;
638                 case FT_WITHIN:
639                         lexrc.next();
640                         within = lexrc.getString();
641                         if (within == "none")
642                                 within.erase();
643                         break;
644                 case FT_STYLE:
645                         lexrc.next();
646                         style = lexrc.getString();
647                         break;
648                 case FT_LISTNAME:
649                         lexrc.next();
650                         listname = lexrc.getString();
651                         break;
652                 case FT_BUILTIN:
653                         lexrc.next();
654                         builtin = lexrc.getBool();
655                         break;
656                 case FT_END:
657                         getout = true;
658                         break;
659                 }
660         }
661
662         // Here if have a full float if getout == true
663         if (getout) {
664                 Floating newfloat(type, placement, ext, within,
665                                   style, name, listname, builtin);
666                 floatlist_->newFloat(newfloat);
667         }
668
669         lexrc.popTable();
670 }
671
672
673 enum CounterTags {
674         CT_NAME = 1,
675         CT_WITHIN,
676         CT_END
677 };
678
679 void LyXTextClass::readCounter(LyXLex & lexrc)
680 {
681         keyword_item counterTags[] = {
682                 { "end", CT_END },
683                 { "name", CT_NAME },
684                 { "within", CT_WITHIN }
685         };
686
687         lexrc.pushTable(counterTags, CT_END);
688
689         string name;
690         string within;
691
692         bool getout = false;
693         while (!getout && lexrc.isOK()) {
694                 int le = lexrc.lex();
695                 switch (le) {
696                 case LyXLex::LEX_UNDEF:
697                         lexrc.printError("Unknown ClassOption tag `$$Token'");
698                         continue;
699                 default: break;
700                 }
701                 switch (static_cast<CounterTags>(le)) {
702                 case CT_NAME:
703                         lexrc.next();
704                         name = lexrc.getString();
705                         break;
706                 case CT_WITHIN:
707                         lexrc.next();
708                         within = lexrc.getString();
709                         if (within == "none")
710                                 within.erase();
711                         break;
712                 case CT_END:
713                         getout = true;
714                         break;
715                 }
716         }
717
718         // Here if have a full float if getout == true
719         if (getout) {
720                 if (within.empty()) {
721                         ctrs_->newCounter(name);
722                 } else {
723                         ctrs_->newCounter(name, within);
724                 }
725         }
726
727         lexrc.popTable();
728 }
729
730
731 LyXFont const & LyXTextClass::defaultfont() const
732 {
733         return defaultfont_;
734 }
735
736
737 string const & LyXTextClass::leftmargin() const
738 {
739         return leftmargin_;
740 }
741
742
743 string const & LyXTextClass::rightmargin() const
744 {
745         return rightmargin_;
746 }
747
748
749 bool LyXTextClass::hasLayout(string const & n) const
750 {
751         string const name = (n.empty() ? defaultLayoutName() : n);
752
753         return find_if(layoutlist_.begin(), layoutlist_.end(),
754                        compare_name(name))
755                 != layoutlist_.end();
756 }
757
758
759 LyXLayout_ptr const & LyXTextClass::operator[](string const & n) const
760 {
761         lyx::Assert(!n.empty());
762
763         if (n.empty())
764                 lyxerr << "LyXTextClass::operator[] called with empty n" << endl;
765
766         string const name = (n.empty() ? defaultLayoutName() : n);
767
768         static string lastLayoutName;
769         static LayoutList::difference_type lastLayoutIndex;
770
771         if (name == lastLayoutName)
772                 return layoutlist_[lastLayoutIndex];
773
774         LayoutList::const_iterator cit =
775                 find_if(layoutlist_.begin(),
776                         layoutlist_.end(),
777                         compare_name(name));
778
779         if (cit == layoutlist_.end()) {
780                 lyxerr << "We failed to find the layout '" << name
781                        << "' in the layout list. You MUST investigate!"
782                        << endl;
783
784                 // we require the name to exist
785                 lyx::Assert(false);
786         }
787
788         lastLayoutName = name;
789         lastLayoutIndex = std::distance(layoutlist_.begin(), cit);
790
791         return (*cit);
792 }
793
794
795 LyXLayout_ptr const & LyXTextClass::getEnv(string const & name) const
796 {
797         lyx::Assert(!name.empty());
798
799         if (name.empty())
800                 lyxerr << "LyXTextClass::getEnv() called with empty n" << endl;
801
802         LayoutList::const_iterator cit =
803                 find_if(envlist_.begin(), envlist_.end(), compare_name(name));
804
805         if (cit == envlist_.end()) {
806                 lyxerr << "We failed to find the environment '" << name
807                        << "' in the layout list. You MUST investigate!"
808                        << endl;
809                 // we require the name to exist
810                 lyx::Assert(false);
811         }
812
813         return *cit;
814 }
815
816
817 bool LyXTextClass::delete_layout(string const & name)
818 {
819         if (name == defaultLayoutName())
820                 return false;
821
822         LayoutList::iterator it =
823                 remove_if(layoutlist_.begin(), layoutlist_.end(),
824                           compare_name(name));
825
826         LayoutList::iterator end = layoutlist_.end();
827         bool const ret = (it != end);
828         layoutlist_.erase(it, end);
829         return ret;
830 }
831
832
833 // Load textclass info if not loaded yet
834 bool LyXTextClass::load() const
835 {
836         if (loaded)
837                 return true;
838
839         // Read style-file
840         string const real_file = LibFileSearch("layouts", name_, "layout");
841
842         if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
843                 lyxerr << "Error reading `"
844                        << MakeDisplayPath(real_file)
845                        << "'\n(Check `" << name_
846                        << "')\nCheck your installation and "
847                         "try Options/Reconfigure..." << endl;
848                 loaded = false;
849         }
850         loaded = true;
851         return loaded;
852 }
853
854
855 FloatList & LyXTextClass::floats()
856 {
857         return *floatlist_.get();
858 }
859
860
861 FloatList const & LyXTextClass::floats() const
862 {
863         return *floatlist_.get();
864 }
865
866
867 Counters & LyXTextClass::counters() const
868 {
869         return *ctrs_.get();
870 }
871
872
873 string const & LyXTextClass::defaultLayoutName() const
874 {
875         // This really should come from the actual layout... (Lgb)
876         return defaultlayout_;
877 }
878
879
880 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
881 {
882         return operator[](defaultLayoutName());
883 }
884
885
886 string const & LyXTextClass::name() const
887 {
888         return name_;
889 }
890
891
892 string const & LyXTextClass::latexname() const
893 {
894         const_cast<LyXTextClass*>(this)->load();
895         return latexname_;
896 }
897
898
899 string const & LyXTextClass::description() const
900 {
901         return description_;
902 }
903
904
905 string const & LyXTextClass::opt_fontsize() const
906 {
907         return opt_fontsize_;
908 }
909
910
911 string const & LyXTextClass::opt_pagestyle() const
912 {
913         return opt_pagestyle_;
914 }
915
916
917 string const & LyXTextClass::options() const
918 {
919         return options_;
920 }
921
922
923 string const & LyXTextClass::pagestyle() const
924 {
925         return pagestyle_;
926 }
927
928
929 string const & LyXTextClass::preamble() const
930 {
931         return preamble_;
932 }
933
934
935 LyXTextClass::PageSides LyXTextClass::sides() const
936 {
937         return sides_;
938 }
939
940
941 int LyXTextClass::secnumdepth() const
942 {
943         return secnumdepth_;
944 }
945
946
947 int LyXTextClass::tocdepth() const
948 {
949         return tocdepth_;
950 }
951
952
953 OutputType LyXTextClass::outputType() const
954 {
955         return outputType_;
956 }
957
958
959 bool LyXTextClass::provides(LyXTextClass::Provides p) const
960 {
961         return provides_ & p;
962 }
963
964
965 unsigned int LyXTextClass::columns() const
966 {
967         return columns_;
968 }
969
970
971 int LyXTextClass::maxcounter() const
972 {
973         return maxcounter_;
974 }
975
976
977 LYX_TITLE_LATEX_TYPES LyXTextClass::titletype() const
978 {
979         return titletype_;
980 }
981
982
983 string const & LyXTextClass::titlename() const
984 {
985         return titlename_;
986 }
987
988
989
990
991
992 int LyXTextClass::size() const
993 {
994         return layoutlist_.size();
995 }
996
997
998 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
999 {
1000         switch (p) {
1001         case LyXTextClass::OneSide:
1002                 os << '1';
1003                 break;
1004         case LyXTextClass::TwoSides:
1005                 os << '2';
1006                 break;
1007         }
1008         return os;
1009 }