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