]> git.lyx.org Git - lyx.git/blob - src/lyxtextclass.C
fix compilation; remove cruft in configure script (I may have removed too much, but...
[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 #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 };
112
113
114 // Reads a textclass structure from file.
115 bool LyXTextClass::Read(string const & filename, bool merge)
116 {
117         keyword_item textClassTags[] = {
118                 { "classoptions",    TC_CLASSOPTIONS },
119                 { "columns",         TC_COLUMNS },
120                 { "defaultfont",     TC_DEFAULTFONT },
121                 { "defaultstyle",    TC_DEFAULTSTYLE },
122                 { "input",           TC_INPUT },
123                 { "leftmargin",      TC_LEFTMARGIN },
124                 { "maxcounter",      TC_MAXCOUNTER },
125                 { "nostyle",         TC_NOSTYLE },
126                 { "outputtype",      TC_OUTPUTTYPE },
127                 { "pagestyle",       TC_PAGESTYLE },
128                 { "preamble",        TC_PREAMBLE },
129                 { "providesamsmath", TC_PROVIDESAMSMATH },
130                 { "providesmakeidx", TC_PROVIDESMAKEIDX },
131                 { "providesnatbib",  TC_PROVIDESNATBIB },
132                 { "providesurl",     TC_PROVIDESURL },
133                 { "rightmargin",     TC_RIGHTMARGIN },
134                 { "secnumdepth",     TC_SECNUMDEPTH },
135                 { "sides",           TC_SIDES },
136                 { "style",           TC_STYLE },
137                 { "tocdepth",        TC_TOCDEPTH }
138         };
139
140         if (!merge)
141                 lyxerr[Debug::TCLASS] << "Reading textclass "
142                                       << MakeDisplayPath(filename)
143                                       << endl;
144         else
145                 lyxerr[Debug::TCLASS] << "Reading input file "
146                                      << MakeDisplayPath(filename)
147                                      << endl;
148
149         LyXLex lexrc(textClassTags, TC_RIGHTMARGIN);
150         bool error = false;
151
152         lexrc.setFile(filename);
153         if (!lexrc.isOK()) error = true;
154
155         // parsing
156         while (lexrc.isOK() && !error) {
157                 int le = lexrc.lex();
158                 switch (le) {
159                 case LyXLex::LEX_FEOF:
160                         continue;
161
162                 case LyXLex::LEX_UNDEF:
163                         lexrc.printError("Unknown TextClass tag `$$Token'");
164                         error = true;
165                         continue;
166                 default: break;
167                 }
168                 switch (static_cast<TextClassTags>(le)) {
169                 case TC_OUTPUTTYPE:   // output type definition
170                         readOutputType(lexrc);
171                         break;
172
173                 case TC_INPUT: // Include file
174                         if (lexrc.next()) {
175                                 string tmp = LibFileSearch("layouts",
176                                                             lexrc.getString(),
177                                                             "layout");
178
179                                 if (Read(tmp, true)) {
180                                         lexrc.printError("Error reading input"
181                                                          "file: "+tmp);
182                                         error = true;
183                                 }
184                         }
185                         break;
186
187                 case TC_DEFAULTSTYLE:
188                         if (lexrc.next()) {
189                                 string const name = subst(lexrc.getString(),
190                                                           '_', ' ');
191                                 defaultlayout_ = name;
192                         }
193                         break;
194
195                 case TC_STYLE:
196                         if (lexrc.next()) {
197                                 string const name = subst(lexrc.getString(),
198                                                     '_', ' ');
199                                 if (hasLayout(name)) {
200                                         LyXLayout * lay =
201                                                 operator[](name).get();
202                                         error = do_readStyle(lexrc, *lay);
203                                 } else {
204                                         LyXLayout lay;
205                                         lay.setName(name);
206                                         if (!(error = do_readStyle(lexrc, lay)))
207                                                 layoutlist.push_back(boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
208                                         if (defaultlayout_.empty()) {
209                                                 // We do not have a default
210                                                 // layout yet, so we choose
211                                                 // the first layout we
212                                                 // encounter.
213                                                 defaultlayout_ = name;
214                                         }
215                                 }
216                         }
217                         else {
218                                 lexrc.printError("No name given for style: `$$Token'.");
219                                 error = true;
220                         }
221                         break;
222
223                 case TC_NOSTYLE:
224                         if (lexrc.next()) {
225                                 string const style = subst(lexrc.getString(),
226                                                      '_', ' ');
227                                 if (!delete_layout(style))
228                                         lyxerr << "Cannot delete style `" << style << "'" << endl;
229 //                                      lexrc.printError("Cannot delete style"
230 //                                                       " `$$Token'");
231                         }
232                         break;
233
234                 case TC_COLUMNS:
235                         if (lexrc.next())
236                                 columns_ = lexrc.getInteger();
237                         break;
238
239                 case TC_SIDES:
240                         if (lexrc.next()) {
241                                 switch (lexrc.getInteger()) {
242                                 case 1: sides_ = OneSide; break;
243                                 case 2: sides_ = TwoSides; break;
244                                 default:
245                                         lyxerr << "Impossible number of page"
246                                                 " sides, setting to one."
247                                                << endl;
248                                         sides_ = OneSide;
249                                         break;
250                                 }
251                         }
252                         break;
253
254                 case TC_PAGESTYLE:
255                         lexrc.next();
256                         pagestyle_ = strip(lexrc.getString());
257                         break;
258
259                 case TC_DEFAULTFONT:
260                         defaultfont_.lyxRead(lexrc);
261                         if (!defaultfont_.resolved()) {
262                                 lexrc.printError("Warning: defaultfont should "
263                                                  "be fully instantiated!");
264 #ifndef INHERIT_LANGUAGE
265                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
266 #else
267                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE),
268                                                      default_language);
269 #endif
270                         }
271                         break;
272
273                 case TC_MAXCOUNTER:
274                         readMaxCounter(lexrc);
275                         break;
276
277                 case TC_SECNUMDEPTH:
278                         lexrc.next();
279                         secnumdepth_ = lexrc.getInteger();
280                         break;
281
282                 case TC_TOCDEPTH:
283                         lexrc.next();
284                         tocdepth_ = lexrc.getInteger();
285                         break;
286
287                         // First step to support options
288                 case TC_CLASSOPTIONS:
289                         readClassOptions(lexrc);
290                         break;
291
292                 case TC_PREAMBLE:
293                         preamble_ = lexrc.getLongString("EndPreamble");
294                         break;
295
296                 case TC_PROVIDESAMSMATH:
297                         if (lexrc.next() && lexrc.getInteger())
298                                 provides_ |= amsmath;
299                         break;
300
301                 case TC_PROVIDESNATBIB:
302                         if (lexrc.next() && lexrc.getInteger())
303                                 provides_ |= natbib;
304                         break;
305
306                 case TC_PROVIDESMAKEIDX:
307                         if (lexrc.next() && lexrc.getInteger())
308                                 provides_ |= makeidx;
309                         break;
310
311                 case TC_PROVIDESURL:
312                         if (lexrc.next() && lexrc.getInteger())
313                                 provides_ |= url;
314                         break;
315
316                 case TC_LEFTMARGIN:     // left margin type
317                         if (lexrc.next())
318                                 leftmargin_ = lexrc.getString();
319                         break;
320
321                 case TC_RIGHTMARGIN:    // right margin type
322                         if (lexrc.next())
323                                 rightmargin_ = lexrc.getString();
324                         break;
325                 }
326         }
327
328         if (!merge) { // we are at top level here.
329                 lyxerr[Debug::TCLASS] << "Finished reading textclass "
330                                       << MakeDisplayPath(filename)
331                                       << endl;
332                 if (defaultlayout_.empty()) {
333                         lyxerr << "Error: Textclass '" << name_
334                                << "' is missing a defaultstyle." << endl;
335                         error = true;
336                 }
337         } else
338                 lyxerr[Debug::TCLASS] << "Finished reading input file "
339                                       << MakeDisplayPath(filename)
340                                       << endl;
341
342         return error;
343 }
344
345
346 void LyXTextClass::readOutputType(LyXLex & lexrc)
347 {
348         keyword_item outputTypeTags[] = {
349                 { "docbook", DOCBOOK },
350                 { "latex", LATEX },
351                 { "linuxdoc", LINUXDOC },
352                 { "literate", LITERATE }
353         };
354
355         pushpophelper pph(lexrc, outputTypeTags, LITERATE);
356
357         int le = lexrc.lex();
358         switch (le) {
359         case LyXLex::LEX_UNDEF:
360                 lexrc.printError("Unknown output type `$$Token'");
361                 return;
362         case LATEX:
363         case LINUXDOC:
364         case DOCBOOK:
365         case LITERATE:
366                 outputType_ = static_cast<OutputType>(le);
367                 break;
368         default:
369                 lyxerr << "Unhandled value " << le
370                        << " in LyXTextClass::readOutputType." << endl;
371
372                 break;
373         }
374 }
375
376
377 enum MaxCounterTags {
378         MC_COUNTER_CHAPTER = 1,
379         MC_COUNTER_SECTION,
380         MC_COUNTER_SUBSECTION,
381         MC_COUNTER_SUBSUBSECTION,
382         MC_COUNTER_PARAGRAPH,
383         MC_COUNTER_SUBPARAGRAPH,
384         MC_COUNTER_ENUMI,
385         MC_COUNTER_ENUMII,
386         MC_COUNTER_ENUMIII,
387         MC_COUNTER_ENUMIV
388 };
389
390
391 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
392 {
393         keyword_item maxCounterTags[] = {
394                 {"counter_chapter", MC_COUNTER_CHAPTER },
395                 {"counter_enumi", MC_COUNTER_ENUMI },
396                 {"counter_enumii", MC_COUNTER_ENUMII },
397                 {"counter_enumiii", MC_COUNTER_ENUMIII },
398                 {"counter_enumiv", MC_COUNTER_ENUMIV },
399                 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
400                 {"counter_section", MC_COUNTER_SECTION },
401                 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
402                 {"counter_subsection", MC_COUNTER_SUBSECTION },
403                 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
404         };
405
406         pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
407         int le = lexrc.lex();
408         switch (le) {
409         case LyXLex::LEX_UNDEF:
410                 lexrc.printError("Unknown MaxCounter tag `$$Token'");
411                 return;
412         default: break;
413         }
414         switch (static_cast<MaxCounterTags>(le)) {
415         case MC_COUNTER_CHAPTER:
416                 maxcounter_ = LABEL_COUNTER_CHAPTER;
417                 break;
418         case MC_COUNTER_SECTION:
419                 maxcounter_ = LABEL_COUNTER_SECTION;
420                 break;
421         case MC_COUNTER_SUBSECTION:
422                 maxcounter_ = LABEL_COUNTER_SUBSECTION;
423                 break;
424         case MC_COUNTER_SUBSUBSECTION:
425                 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
426                 break;
427         case MC_COUNTER_PARAGRAPH:
428                 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
429                 break;
430         case MC_COUNTER_SUBPARAGRAPH:
431                 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
432                 break;
433         case MC_COUNTER_ENUMI:
434                 maxcounter_ = LABEL_COUNTER_ENUMI;
435                 break;
436         case MC_COUNTER_ENUMII:
437                 maxcounter_ = LABEL_COUNTER_ENUMII;
438                 break;
439         case MC_COUNTER_ENUMIII:
440                 maxcounter_ = LABEL_COUNTER_ENUMIII;
441                 break;
442         case MC_COUNTER_ENUMIV:
443                 maxcounter_ = LABEL_COUNTER_ENUMIV;
444                 break;
445         }
446 }
447
448
449 enum ClassOptionsTags {
450         CO_FONTSIZE = 1,
451         CO_PAGESTYLE,
452         CO_OTHER,
453         CO_END
454 };
455
456
457 void LyXTextClass::readClassOptions(LyXLex & lexrc)
458 {
459         keyword_item classOptionsTags[] = {
460                 {"end", CO_END },
461                 {"fontsize", CO_FONTSIZE },
462                 {"other", CO_OTHER },
463                 {"pagestyle", CO_PAGESTYLE }
464         };
465
466         lexrc.pushTable(classOptionsTags, CO_END);
467         bool getout = false;
468         while (!getout && lexrc.isOK()) {
469                 int le = lexrc.lex();
470                 switch (le) {
471                 case LyXLex::LEX_UNDEF:
472                         lexrc.printError("Unknown ClassOption tag `$$Token'");
473                         continue;
474                 default: break;
475                 }
476                 switch (static_cast<ClassOptionsTags>(le)) {
477                 case CO_FONTSIZE:
478                         lexrc.next();
479                         opt_fontsize_ = strip(lexrc.getString());
480                         break;
481                 case CO_PAGESTYLE:
482                         lexrc.next();
483                         opt_pagestyle_ = strip(lexrc.getString());
484                         break;
485                 case CO_OTHER:
486                         lexrc.next();
487                         options_ = lexrc.getString();
488                         break;
489                 case CO_END:
490                         getout = true;
491                         break;
492                 }
493         }
494         lexrc.popTable();
495 }
496
497
498 LyXFont const & LyXTextClass::defaultfont() const
499 {
500         return defaultfont_;
501 }
502
503
504 string const & LyXTextClass::leftmargin() const
505 {
506         return leftmargin_;
507 }
508
509
510 string const & LyXTextClass::rightmargin() const
511 {
512         return rightmargin_;
513 }
514
515
516 bool LyXTextClass::hasLayout(string const & n) const
517 {
518         string const name = (n.empty() ? defaultLayoutName() : n);
519
520         return find_if(layoutlist.begin(), layoutlist.end(),
521                        compare_name(name))
522                 != layoutlist.end();
523 }
524
525
526 LyXLayout_ptr const & LyXTextClass::operator[](string const & n) const
527 {
528         lyx::Assert(!n.empty());
529
530         if (n.empty())
531                 lyxerr << "Operator[] called with empty n" << endl;
532
533         string const name = (n.empty() ? defaultLayoutName() : n);
534
535         static string lastLayoutName;
536         static LayoutList::difference_type lastLayoutIndex;
537
538         if (name == lastLayoutName)
539                 return layoutlist[lastLayoutIndex];
540
541         LayoutList::const_iterator cit =
542                 find_if(layoutlist.begin(),
543                         layoutlist.end(),
544                         compare_name(name));
545
546         if (cit == layoutlist.end()) {
547                 lyxerr << "We failed to find the layout '" << name
548                        << "' in the layout list. You MUST investigate!"
549                        << endl;
550
551                 // we require the name to exist
552                 lyx::Assert(false);
553         }
554
555         lastLayoutName = name;
556         lastLayoutIndex = std::distance(layoutlist.begin(), cit);
557
558         return (*cit);
559 }
560
561
562 bool LyXTextClass::delete_layout(string const & name)
563 {
564         if (name == defaultLayoutName())
565                 return false;
566
567         LayoutList::iterator it =
568                 remove_if(layoutlist.begin(), layoutlist.end(),
569                           compare_name(name));
570
571         LayoutList::iterator end = layoutlist.end();
572         bool const ret = (it != end);
573         layoutlist.erase(it, end);
574         return ret;
575 }
576
577
578 // Load textclass info if not loaded yet
579 bool LyXTextClass::load() const
580 {
581         if (loaded)
582                 return true;
583
584         // Read style-file
585         string const real_file = LibFileSearch("layouts", name_, "layout");
586
587         if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
588                 lyxerr << "Error reading `"
589                        << MakeDisplayPath(real_file)
590                        << "'\n(Check `" << name_
591                        << "')\nCheck your installation and "
592                         "try Options/Reconfigure..." << endl;
593                 loaded = false;
594         }
595         loaded = true;
596         return loaded;
597 }
598
599
600 string const LyXTextClass::defaultLayoutName() const
601 {
602         // This really should come from the actual layout... (Lgb)
603         return defaultlayout_;
604 }
605
606
607 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
608 {
609         return operator[](defaultLayoutName());
610 }
611
612
613 string const & LyXTextClass::name() const
614 {
615         return name_;
616 }
617
618
619 string const & LyXTextClass::latexname() const
620 {
621         const_cast<LyXTextClass*>(this)->load();
622         return latexname_;
623 }
624
625
626 string const & LyXTextClass::description() const
627 {
628         return description_;
629 }
630
631
632 string const & LyXTextClass::opt_fontsize() const
633 {
634         return opt_fontsize_;
635 }
636
637
638 string const & LyXTextClass::opt_pagestyle() const
639 {
640         return opt_pagestyle_;
641 }
642
643
644 string const & LyXTextClass::options() const
645 {
646         return options_;
647 }
648
649
650 string const & LyXTextClass::pagestyle() const
651 {
652         return pagestyle_;
653 }
654
655
656 string const & LyXTextClass::preamble() const
657 {
658         return preamble_;
659 }
660
661
662 LyXTextClass::PageSides LyXTextClass::sides() const
663 {
664         return sides_;
665 }
666
667
668 int LyXTextClass::secnumdepth() const
669 {
670         return secnumdepth_;
671 }
672
673
674 int LyXTextClass::tocdepth() const
675 {
676         return tocdepth_;
677 }
678
679
680 OutputType LyXTextClass::outputType() const
681 {
682         return outputType_;
683 }
684
685
686 bool LyXTextClass::provides(LyXTextClass::Provides p) const
687 {
688         return provides_ & p;
689 }
690
691
692 unsigned int LyXTextClass::columns() const
693 {
694         return columns_;
695 }
696
697
698 int LyXTextClass::maxcounter() const
699 {
700         return maxcounter_;
701 }
702
703
704 int LyXTextClass::size() const
705 {
706         return layoutlist.size();
707 }
708
709
710 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
711 {
712         switch (p) {
713         case LyXTextClass::OneSide:
714                 os << "1";
715                 break;
716         case LyXTextClass::TwoSides:
717                 os << "2";
718                 break;
719         }
720         return os;
721 }