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