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