]> git.lyx.org Git - lyx.git/blob - src/lyxtextclass.C
110f2c7d8944ba090f3e82464d30d80ec33594c1
[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
35 /* ******************************************************************* */
36
37 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
38                            string const & desc)
39         : name_(fn), latexname_(cln), description_(desc)
40 {
41         outputType_ = LATEX;
42         columns_ = 1;
43         sides_ = OneSide;
44         secnumdepth_ = 3;
45         tocdepth_ = 3;
46         pagestyle_ = "default";
47         maxcounter_ = LABEL_COUNTER_CHAPTER;
48         defaultfont_ = LyXFont(LyXFont::ALL_SANE);
49         opt_fontsize_ = "10|11|12";
50         opt_pagestyle_ = "empty|plain|headings|fancy";
51         provides_ = nothing;
52         loaded = false;
53 }
54
55
56 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
57 {
58         lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
59         if (!lay.Read(lexrc, *this)) {
60                 // Reslove fonts
61                 lay.resfont = lay.font;
62 #ifndef INHERIT_LANGUAGE
63                 lay.resfont.realize(defaultfont());
64                 lay.reslabelfont = lay.labelfont;
65                 lay.reslabelfont.realize(defaultfont());
66 #else
67                 lay.resfont.realize(defaultfont(), default_language);
68                 lay.reslabelfont = lay.labelfont;
69                 lay.reslabelfont.realize(defaultfont(), default_language);
70 #endif
71                 return false; // no errors
72         } 
73         lyxerr << "Error parsing style `" << lay.name() << "'" << endl;
74         return true;
75 }
76
77
78 enum TextClassTags {
79         TC_OUTPUTTYPE = 1,
80         TC_INPUT,
81         TC_STYLE,
82         TC_NOSTYLE,
83         TC_COLUMNS,
84         TC_SIDES,
85         TC_PAGESTYLE,
86         TC_DEFAULTFONT,
87         TC_MAXCOUNTER,
88         TC_SECNUMDEPTH,
89         TC_TOCDEPTH,
90         TC_CLASSOPTIONS,
91         TC_PREAMBLE,
92         TC_PROVIDESAMSMATH,
93         TC_PROVIDESMAKEIDX,
94         TC_PROVIDESURL,
95         TC_LEFTMARGIN,
96         TC_RIGHTMARGIN
97 };
98
99
100 // Reads a textclass structure from file.
101 bool LyXTextClass::Read(string const & filename, bool merge)
102 {
103         keyword_item textClassTags[] = {
104                 { "classoptions",    TC_CLASSOPTIONS },
105                 { "columns",         TC_COLUMNS },
106                 { "defaultfont",     TC_DEFAULTFONT },
107                 { "input",           TC_INPUT },
108                 { "leftmargin",      TC_LEFTMARGIN },
109                 { "maxcounter",      TC_MAXCOUNTER },
110                 { "nostyle",         TC_NOSTYLE },
111                 { "outputtype",      TC_OUTPUTTYPE },
112                 { "pagestyle",       TC_PAGESTYLE },
113                 { "preamble",        TC_PREAMBLE },
114                 { "providesamsmath", TC_PROVIDESAMSMATH },
115                 { "providesmakeidx", TC_PROVIDESMAKEIDX },
116                 { "providesurl",     TC_PROVIDESURL },
117                 { "rightmargin",     TC_RIGHTMARGIN },
118                 { "secnumdepth",     TC_SECNUMDEPTH },
119                 { "sides",           TC_SIDES },
120                 { "style",           TC_STYLE },
121                 { "tocdepth",        TC_TOCDEPTH }
122         };
123
124         if (!merge)
125                 lyxerr[Debug::TCLASS] << "Reading textclass "
126                                       << MakeDisplayPath(filename)
127                                       << endl;
128         else
129                 lyxerr[Debug::TCLASS] << "Reading input file "
130                                      << MakeDisplayPath(filename)
131                                      << endl;
132         
133         LyXLex lexrc(textClassTags, TC_RIGHTMARGIN);
134         bool error = false;
135
136         lexrc.setFile(filename);
137         if (!lexrc.isOK()) error = true; 
138
139         // parsing
140         while (lexrc.isOK() && !error) {
141                 int le = lexrc.lex();
142                 switch (le) {
143                 case LyXLex::LEX_FEOF:
144                         continue; 
145
146                 case LyXLex::LEX_UNDEF:                                 
147                         lexrc.printError("Unknown TextClass tag `$$Token'");
148                         error = true;
149                         continue; 
150                 default: break;
151                 }
152                 switch (static_cast<TextClassTags>(le)) {
153                 case TC_OUTPUTTYPE:   // output type definition
154                         readOutputType(lexrc);
155                         break;
156                         
157                 case TC_INPUT: // Include file
158                         if (lexrc.next()) {
159                                 string tmp = LibFileSearch("layouts",
160                                                             lexrc.getString(), 
161                                                             "layout");
162                                 
163                                 if (Read(tmp, true)) {
164                                         lexrc.printError("Error reading input"
165                                                          "file: "+tmp);
166                                         error = true;
167                                 }
168                         }
169                         break;
170
171                 case TC_STYLE:
172                         if (lexrc.next()) {
173                                 string name = subst(lexrc.getString(),
174                                                     '_', ' ');
175                                 if (hasLayout(name)) {
176                                         LyXLayout & lay = GetLayout(name);
177                                         error = do_readStyle(lexrc, lay);
178                                 } else {
179                                         LyXLayout lay;
180                                         lay.setName(name);
181                                         if (!(error = do_readStyle(lexrc, lay)))
182                                                 layoutlist.push_back(lay);
183                                 }
184                         }
185                         else {
186                                 lexrc.printError("No name given for style: `$$Token'.");
187                                 error = true;
188                         }
189                         break;
190
191                 case TC_NOSTYLE:
192                         if (lexrc.next()) {
193                                 string const style = subst(lexrc.getString(),
194                                                      '_', ' ');
195                                 if (!delete_layout(style))
196                                         lexrc.printError("Cannot delete style"
197                                                          " `$$Token'");
198                         }
199                         break;
200
201                 case TC_COLUMNS:
202                         if (lexrc.next())
203                                 columns_ = lexrc.getInteger();
204                         break;
205                         
206                 case TC_SIDES:
207                         if (lexrc.next()) {
208                                 switch (lexrc.getInteger()) {
209                                 case 1: sides_ = OneSide; break;
210                                 case 2: sides_ = TwoSides; break;
211                                 default:
212                                         lyxerr << "Impossible number of page"
213                                                 " sides, setting to one."
214                                                << endl;
215                                         sides_ = OneSide;
216                                         break;
217                                 }
218                         }
219                         break;
220                         
221                 case TC_PAGESTYLE:
222                         lexrc.next();
223                         pagestyle_ = strip(lexrc.getString());
224                         break;
225                         
226                 case TC_DEFAULTFONT:
227                         defaultfont_.lyxRead(lexrc);
228                         if (!defaultfont_.resolved()) {
229                                 lexrc.printError("Warning: defaultfont should "
230                                                  "be fully instantiated!");
231 #ifndef INHERIT_LANGUAGE
232                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
233 #else
234                                 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE),
235                                                      default_language);
236 #endif
237                         }
238                         break;
239
240                 case TC_MAXCOUNTER:
241                         readMaxCounter(lexrc);
242                         break;
243
244                 case TC_SECNUMDEPTH:
245                         lexrc.next();
246                         secnumdepth_ = lexrc.getInteger();
247                         break;
248
249                 case TC_TOCDEPTH:
250                         lexrc.next();
251                         tocdepth_ = lexrc.getInteger();
252                         break;
253
254                         // First step to support options 
255                 case TC_CLASSOPTIONS:
256                         readClassOptions(lexrc);
257                         break;
258
259                 case TC_PREAMBLE:
260                         preamble_ = lexrc.getLongString("EndPreamble");
261                         break;
262
263                 case TC_PROVIDESAMSMATH:
264                         if (lexrc.next() && lexrc.getInteger())
265                                 provides_ |= amsmath;
266                         break;
267
268                 case TC_PROVIDESMAKEIDX:
269                         if (lexrc.next() && lexrc.getInteger())
270                                 provides_ |= makeidx;
271                         break;
272
273                 case TC_PROVIDESURL:
274                         if (lexrc.next() && lexrc.getInteger())
275                                 provides_ = url;
276                         break;
277
278                 case TC_LEFTMARGIN:     // left margin type
279                         if (lexrc.next())
280                                 leftmargin_ = lexrc.getString();
281                         break;                  
282
283                 case TC_RIGHTMARGIN:    // right margin type
284                         if (lexrc.next())
285                                 rightmargin_ = lexrc.getString();
286                         break;
287                 }
288         }       
289
290         if (!merge) { // we are at top level here.
291                 lyxerr[Debug::TCLASS] << "Finished reading textclass " 
292                                       << MakeDisplayPath(filename)
293                                       << endl;
294         } else
295                 lyxerr[Debug::TCLASS] << "Finished reading input file " 
296                                       << MakeDisplayPath(filename)
297                                       << endl;
298
299         return error;
300 }
301
302
303 void LyXTextClass::readOutputType(LyXLex & lexrc)
304 {
305         keyword_item outputTypeTags[] = {
306                 { "docbook", DOCBOOK },
307                 { "latex", LATEX },
308                 { "linuxdoc", LINUXDOC },
309                 { "literate", LITERATE }
310         };
311
312         pushpophelper pph(lexrc, outputTypeTags, LITERATE);
313
314         int le = lexrc.lex();
315         switch (le) {
316         case LyXLex::LEX_UNDEF:
317                 lexrc.printError("Unknown output type `$$Token'");
318                 return;
319         case LATEX:
320         case LINUXDOC:
321         case DOCBOOK:
322         case LITERATE:
323                 outputType_ = static_cast<OutputType>(le);
324                 break;
325         default:
326                 lyxerr << "Unhandled value " << le
327                        << " in LyXTextClass::readOutputType." << endl;
328
329                 break;
330         }
331 }
332
333
334 enum MaxCounterTags {
335         MC_COUNTER_CHAPTER = 1,
336         MC_COUNTER_SECTION,
337         MC_COUNTER_SUBSECTION,
338         MC_COUNTER_SUBSUBSECTION,
339         MC_COUNTER_PARAGRAPH,
340         MC_COUNTER_SUBPARAGRAPH,
341         MC_COUNTER_ENUMI,
342         MC_COUNTER_ENUMII,
343         MC_COUNTER_ENUMIII,
344         MC_COUNTER_ENUMIV
345 };
346
347
348 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
349 {
350         keyword_item maxCounterTags[] = {
351                 {"counter_chapter", MC_COUNTER_CHAPTER },
352                 {"counter_enumi", MC_COUNTER_ENUMI },
353                 {"counter_enumii", MC_COUNTER_ENUMII },
354                 {"counter_enumiii", MC_COUNTER_ENUMIII },
355                 {"counter_enumiv", MC_COUNTER_ENUMIV },
356                 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
357                 {"counter_section", MC_COUNTER_SECTION },
358                 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
359                 {"counter_subsection", MC_COUNTER_SUBSECTION },
360                 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
361         };
362
363         pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
364         int le = lexrc.lex();
365         switch (le) {
366         case LyXLex::LEX_UNDEF:
367                 lexrc.printError("Unknown MaxCounter tag `$$Token'");
368                 return; 
369         default: break;
370         }
371         switch (static_cast<MaxCounterTags>(le)) {
372         case MC_COUNTER_CHAPTER:
373                 maxcounter_ = LABEL_COUNTER_CHAPTER;
374                 break;
375         case MC_COUNTER_SECTION:
376                 maxcounter_ = LABEL_COUNTER_SECTION;
377                 break;
378         case MC_COUNTER_SUBSECTION:
379                 maxcounter_ = LABEL_COUNTER_SUBSECTION;
380                 break;
381         case MC_COUNTER_SUBSUBSECTION:
382                 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
383                 break;
384         case MC_COUNTER_PARAGRAPH:
385                 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
386                 break;
387         case MC_COUNTER_SUBPARAGRAPH:
388                 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
389                 break;
390         case MC_COUNTER_ENUMI:
391                 maxcounter_ = LABEL_COUNTER_ENUMI;
392                 break;
393         case MC_COUNTER_ENUMII:
394                 maxcounter_ = LABEL_COUNTER_ENUMII;
395                 break;
396         case MC_COUNTER_ENUMIII:
397                 maxcounter_ = LABEL_COUNTER_ENUMIII;
398                 break;
399         case MC_COUNTER_ENUMIV:
400                 maxcounter_ = LABEL_COUNTER_ENUMIV;
401                 break;
402         }
403 }
404
405
406 enum ClassOptionsTags {
407         CO_FONTSIZE = 1,
408         CO_PAGESTYLE,
409         CO_OTHER,
410         CO_END
411 };
412
413
414 void LyXTextClass::readClassOptions(LyXLex & lexrc)
415 {
416         keyword_item classOptionsTags[] = {
417                 {"end", CO_END },
418                 {"fontsize", CO_FONTSIZE },
419                 {"other", CO_OTHER },
420                 {"pagestyle", CO_PAGESTYLE }
421         };
422
423         lexrc.pushTable(classOptionsTags, CO_END);
424         bool getout = false;
425         while (!getout && lexrc.isOK()) {
426                 int le = lexrc.lex();
427                 switch (le) {
428                 case LyXLex::LEX_UNDEF:
429                         lexrc.printError("Unknown ClassOption tag `$$Token'");
430                         continue; 
431                 default: break;
432                 }
433                 switch (static_cast<ClassOptionsTags>(le)) {
434                 case CO_FONTSIZE:
435                         lexrc.next();
436                         opt_fontsize_ = strip(lexrc.getString());
437                         break;
438                 case CO_PAGESTYLE:
439                         lexrc.next();
440                         opt_pagestyle_ = strip(lexrc.getString()); 
441                         break;
442                 case CO_OTHER:
443                         lexrc.next();
444                         options_ = lexrc.getString();
445                         break;
446                 case CO_END:
447                         getout = true;
448                         break;
449                 }
450         }
451         lexrc.popTable();
452 }
453
454
455 LyXFont const & LyXTextClass::defaultfont() const
456 {
457         return defaultfont_;
458 }
459
460
461 string const & LyXTextClass::leftmargin() const
462 {
463         return leftmargin_;
464 }
465
466
467 string const & LyXTextClass::rightmargin() const
468 {
469         return rightmargin_;
470 }
471
472
473 bool LyXTextClass::hasLayout(string const & name) const
474 {
475         return find_if(layoutlist.begin(), layoutlist.end(),
476                        lyx::compare_memfun(&LyXLayout::name, name))
477                 != layoutlist.end();
478 }
479
480
481 LyXLayout const & LyXTextClass::GetLayout (string const & name) const
482 {
483         LayoutList::const_iterator cit =
484                 find_if(layoutlist.begin(),
485                         layoutlist.end(),
486                         lyx::compare_memfun(&LyXLayout::name, name));
487         lyx::Assert(cit != layoutlist.end()); // we require the name to exist
488         return (*cit);
489 }
490
491
492 LyXLayout & LyXTextClass::GetLayout(string const & name)
493 {
494         LayoutList::iterator it =
495                 find_if(layoutlist.begin(),
496                         layoutlist.end(),
497                         lyx::compare_memfun(&LyXLayout::name, name));
498         lyx::Assert(it != layoutlist.end()); // we require the name to exist
499         return (*it);
500 }
501
502
503 bool LyXTextClass::delete_layout(string const & name)
504 {
505         LayoutList::iterator it =
506                 remove_if(layoutlist.begin(), layoutlist.end(),
507                           lyx::compare_memfun(&LyXLayout::name, name));
508         LayoutList::iterator end = layoutlist.end();
509         bool const ret = (it != end);
510         layoutlist.erase(it, end);
511         return ret;
512 }
513
514
515 // Load textclass info if not loaded yet
516 void LyXTextClass::load()
517 {
518         if (loaded) return;
519
520         // Read style-file
521         string const real_file = LibFileSearch("layouts", name_, "layout");
522
523         if (Read(real_file)) {
524                 lyxerr << "Error reading `"
525                        << MakeDisplayPath(real_file)
526                        << "'\n(Check `" << name_
527                        << "')\nCheck your installation and "
528                         "try Options/Reconfigure..." << endl;
529         }
530         loaded = true;
531 }
532
533
534 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
535 {
536         switch (p) {
537         case LyXTextClass::OneSide:
538                 os << "1";
539                 break;
540         case LyXTextClass::TwoSides:
541                 os << "2";
542                 break;
543         }
544         return os;
545 }