]> git.lyx.org Git - lyx.git/blob - src/output_docbook.cpp
Fix text direction issue for InsetInfo in RTL context
[lyx.git] / src / output_docbook.cpp
1 /**
2  * \file output_docbook.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author José Matos
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "output_docbook.h"
15
16 #include "Buffer.h"
17 #include "buffer_funcs.h"
18 #include "BufferParams.h"
19 #include "Counters.h"
20 #include "Font.h"
21 #include "Layout.h"
22 #include "OutputParams.h"
23 #include "Paragraph.h"
24 #include "ParagraphList.h"
25 #include "ParagraphParameters.h"
26 #include "sgml.h"
27 #include "Text.h"
28 #include "TextClass.h"
29
30 #include "support/lassert.h"
31 #include "support/debug.h"
32 #include "support/lstrings.h"
33 #include "support/lyxalgo.h"
34
35 #include <iostream>
36
37 using namespace std;
38 using namespace lyx::support;
39
40 namespace lyx {
41
42 namespace {
43
44 ParagraphList::const_iterator searchParagraph(
45         ParagraphList::const_iterator p,
46         ParagraphList::const_iterator const & pend)
47 {
48         for (++p; p != pend && p->layout().latextype == LATEX_PARAGRAPH; ++p)
49                 ;
50
51         return p;
52 }
53
54
55 ParagraphList::const_iterator searchCommand(
56         ParagraphList::const_iterator p,
57         ParagraphList::const_iterator const & pend)
58 {
59         Layout const & bstyle = p->layout();
60
61         for (++p; p != pend; ++p) {
62                 Layout const & style = p->layout();
63                 if (style.latextype == LATEX_COMMAND
64                                 && style.commanddepth <= bstyle.commanddepth)
65                         return p;
66         }
67         return pend;
68 }
69
70
71 ParagraphList::const_iterator searchEnvironment(
72         ParagraphList::const_iterator p,
73         ParagraphList::const_iterator const & pend)
74 {
75         Layout const & bstyle = p->layout();
76         size_t const depth = p->params().depth();
77         for (++p; p != pend; ++p) {
78                 Layout const & style = p->layout();
79                 if (style.latextype == LATEX_COMMAND)
80                         return p;
81
82                 if (style.latextype == LATEX_PARAGRAPH) {
83                         if (p->params().depth() > depth)
84                                 continue;
85                         return p;
86                 }
87
88                 if (p->params().depth() < depth)
89                         return p;
90
91                 if (style.latexname() != bstyle.latexname()
92                                 && p->params().depth() == depth)
93                         return p;
94         }
95         return pend;
96 }
97
98
99 ParagraphList::const_iterator makeParagraph(
100         Buffer const & buf,
101         odocstream & os,
102         OutputParams const & runparams,
103         Text const & text,
104         ParagraphList::const_iterator const & pbegin,
105         ParagraphList::const_iterator const & pend)
106 {
107         ParagraphList const & paragraphs = text.paragraphs();
108         for (ParagraphList::const_iterator par = pbegin; par != pend; ++par) {
109                 if (par != pbegin)
110                         os << '\n';
111                 bool const default_or_plain =
112                         (buf.params().documentClass().isDefaultLayout(par->layout())
113                                 || buf.params().documentClass().isPlainLayout(par->layout()));
114                 if (default_or_plain && par->emptyTag()) {
115                         par->simpleDocBookOnePar(buf, os, runparams,
116                                         text.outerFont(distance(paragraphs.begin(), par)));
117                 } else {
118                         sgml::openTag(buf, os, runparams, *par);
119                         par->simpleDocBookOnePar(buf, os, runparams,
120                                         text.outerFont(distance(paragraphs.begin(), par)));
121                         sgml::closeTag(os, *par);
122                 }
123         }
124         return pend;
125 }
126
127
128 ParagraphList::const_iterator makeEnvironment(
129         Buffer const & buf,
130         odocstream & os,
131         OutputParams const & runparams,
132         Text const & text,
133         ParagraphList::const_iterator const & pbegin,
134         ParagraphList::const_iterator const & pend)
135 {
136         ParagraphList const & paragraphs = text.paragraphs();
137         ParagraphList::const_iterator par = pbegin;
138
139         Layout const & defaultstyle = buf.params().documentClass().defaultLayout();
140         Layout const & bstyle = par->layout();
141
142         // Opening outter tag
143         sgml::openTag(buf, os, runparams, *pbegin);
144         os << '\n';
145         if (bstyle.latextype == LATEX_ENVIRONMENT && bstyle.pass_thru)
146                 os << "<![CDATA[";
147
148         while (par != pend) {
149                 Layout const & style = par->layout();
150                 ParagraphList::const_iterator send;
151                 string id = par->getID(buf, runparams);
152                 string wrapper = "";
153                 pos_type sep = 0;
154
155                 // Opening inner tag
156                 switch (bstyle.latextype) {
157                 case LATEX_ENVIRONMENT:
158                         if (!bstyle.innertag().empty()) {
159                                 sgml::openTag(os, bstyle.innertag(), id);
160                         }
161                         break;
162
163                 case LATEX_ITEM_ENVIRONMENT:
164                         if (!bstyle.labeltag().empty()) {
165                                 sgml::openTag(os, bstyle.innertag(), id);
166                                 sgml::openTag(os, bstyle.labeltag());
167                                 sep = par->firstWordDocBook(os, runparams) + 1;
168                                 sgml::closeTag(os, bstyle.labeltag());
169                         }
170                         wrapper = defaultstyle.latexname();
171                         // If a sub list (embedded list) appears next with a
172                         // different depth, then there is no need to open
173                         // another tag at the current depth.
174                         if(par->params().depth() == pbegin->params().depth()) {
175                                 sgml::openTag(os, bstyle.itemtag());
176                         }
177                         break;
178                 default:
179                         break;
180                 }
181
182                 switch (style.latextype) {
183                 case LATEX_ENVIRONMENT:
184                 case LATEX_ITEM_ENVIRONMENT: {
185                         if (par->params().depth() == pbegin->params().depth()) {
186                                 sgml::openTag(os, wrapper);
187                                 par->simpleDocBookOnePar(buf, os, runparams,
188                                         text.outerFont(distance(paragraphs.begin(), par)), sep);
189                                 sgml::closeTag(os, wrapper);
190                                 ++par;
191                         }
192                         else {
193                                 send = searchEnvironment(par, pend);
194                                 par = makeEnvironment(buf, os, runparams, text, par,send);
195                         }
196                         break;
197                 }
198                 case LATEX_PARAGRAPH:
199                         send = searchParagraph(par, pend);
200                         par = makeParagraph(buf, os, runparams, text, par,send);
201                         break;
202                 case LATEX_LIST_ENVIRONMENT:
203                 case LATEX_BIB_ENVIRONMENT:
204                 case LATEX_COMMAND:
205                         // FIXME This means that we are just skipping any paragraph that
206                         // isn't implemented above, and this includes lists.
207                         ++par;
208                         break;
209                 }
210
211                 // Closing inner tag
212                 switch (bstyle.latextype) {
213                 case LATEX_ENVIRONMENT:
214                         if (!bstyle.innertag().empty()) {
215                                 sgml::closeTag(os, bstyle.innertag());
216                                 os << '\n';
217                         }
218                         break;
219                 case LATEX_ITEM_ENVIRONMENT:
220                         // If a sub list (embedded list) appears next, then
221                         // there is no need to close the current tag.
222                         // par should have already been incremented to the next
223                         // element. So we can compare the depth of the next
224                         // element with pbegin.
225                         // We need to be careful, that we don't dereference par
226                         // when par == pend but at the same time that the
227                         // current tag is closed.
228                         if((par != pend && par->params().depth() == pbegin->params().depth()) || par == pend) {
229                                 sgml::closeTag(os, bstyle.itemtag());
230                         }
231                         if (!bstyle.labeltag().empty())
232                                 sgml::closeTag(os, bstyle.innertag());
233                         break;
234                 default:
235                         break;
236                 }
237         }
238
239         if (bstyle.latextype == LATEX_ENVIRONMENT && bstyle.pass_thru)
240                 os << "]]>";
241
242         // Closing outer tag
243         sgml::closeTag(os, *pbegin);
244
245         return pend;
246 }
247
248
249 ParagraphList::const_iterator makeCommand(
250         Buffer const & buf,
251         odocstream & os,
252         OutputParams const & runparams,
253         Text const & text,
254         ParagraphList::const_iterator const & pbegin,
255         ParagraphList::const_iterator const & pend)
256 {
257         ParagraphList const & paragraphs = text.paragraphs();
258         ParagraphList::const_iterator par = pbegin;
259         Layout const & bstyle = par->layout();
260
261         //Open outter tag
262         sgml::openTag(buf, os, runparams, *pbegin);
263         os << '\n';
264
265         // Label around sectioning number:
266         if (!bstyle.labeltag().empty()) {
267                 sgml::openTag(os, bstyle.labeltag());
268                 // We don't care about appendix in DOCBOOK.
269                 os << par->expandDocBookLabel(bstyle, buf.params());
270                 sgml::closeTag(os, bstyle.labeltag());
271         }
272
273         // Opend inner tag and  close inner tags
274         sgml::openTag(os, bstyle.innertag());
275         par->simpleDocBookOnePar(buf, os, runparams,
276                 text.outerFont(distance(paragraphs.begin(), par)));
277         sgml::closeTag(os, bstyle.innertag());
278         os << '\n';
279
280         ++par;
281         while (par != pend) {
282                 Layout const & style = par->layout();
283                 ParagraphList::const_iterator send;
284
285                 switch (style.latextype) {
286                 case LATEX_COMMAND: {
287                         send = searchCommand(par, pend);
288                         par = makeCommand(buf, os, runparams, text, par,send);
289                         break;
290                 }
291                 case LATEX_ENVIRONMENT:
292                 case LATEX_ITEM_ENVIRONMENT: {
293                         send = searchEnvironment(par, pend);
294                         par = makeEnvironment(buf, os, runparams, text, par,send);
295                         break;
296                 }
297                 case LATEX_PARAGRAPH:
298                         send = searchParagraph(par, pend);
299                         par = makeParagraph(buf, os, runparams, text, par,send);
300                         break;
301                 case LATEX_BIB_ENVIRONMENT:
302                 case LATEX_LIST_ENVIRONMENT:
303                         // FIXME This means that we are just skipping any paragraph that
304                         // isn't implemented above.
305                         ++par;
306                         break;
307                 }
308         }
309         // Close outter tag
310         sgml::closeTag(os, *pbegin);
311
312         return pend;
313 }
314
315 } // namespace
316
317
318 void docbookParagraphs(Text const & text,
319                        Buffer const & buf,
320                        odocstream & os,
321                        OutputParams const & runparams)
322 {
323         LASSERT(runparams.par_begin <= runparams.par_end,
324                 { os << "<!-- Docbook Output Error -->\n"; return; });
325
326         ParagraphList const & paragraphs = text.paragraphs();
327         ParagraphList::const_iterator par = paragraphs.begin();
328         ParagraphList::const_iterator pend = paragraphs.end();
329
330         // if only part of the paragraphs will be outputed
331         if (runparams.par_begin !=  runparams.par_end) {
332                 par = lyx::next(paragraphs.begin(), runparams.par_begin);
333                 pend = lyx::next(paragraphs.begin(), runparams.par_end);
334                 // runparams will be passed to nested paragraphs, so
335                 // we have to reset the range parameters.
336                 const_cast<OutputParams&>(runparams).par_begin = 0;
337                 const_cast<OutputParams&>(runparams).par_end = 0;
338         }
339
340         while (par != pend) {
341                 Layout const & style = par->layout();
342                 ParagraphList::const_iterator lastpar = par;
343                 ParagraphList::const_iterator send;
344
345                 switch (style.latextype) {
346                 case LATEX_COMMAND: {
347                         send = searchCommand(par, pend);
348                         par = makeCommand(buf, os, runparams, text, par, send);
349                         break;
350                 }
351                 case LATEX_ENVIRONMENT:
352                 case LATEX_ITEM_ENVIRONMENT: {
353                         send = searchEnvironment(par, pend);
354                         par = makeEnvironment(buf, os, runparams, text, par, send);
355                         break;
356                 }
357                 case LATEX_PARAGRAPH:
358                         send = searchParagraph(par, pend);
359                         par = makeParagraph(buf, os, runparams, text, par, send);
360                         break;
361                 case LATEX_BIB_ENVIRONMENT:
362                 case LATEX_LIST_ENVIRONMENT:
363                         // FIXME This means that we are just skipping any paragraph that
364                         // isn't implemented above.
365                         ++par;
366                         break;
367                 }
368                 // makeEnvironment may process more than one paragraphs and bypass pend
369                 if (distance(lastpar, par) >= distance(lastpar, pend))
370                         break;
371         }
372 }
373
374
375 } // namespace lyx