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