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