]> git.lyx.org Git - features.git/blob - src/output_plaintext.cpp
f9629e920307ec3ca1c4ed2fe9acb5c9c28215ef
[features.git] / src / output_plaintext.cpp
1 /**
2  * \file output_plaintext.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  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "output_plaintext.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "support/debug.h"
18 #include "support/gettext.h"
19 #include "Layout.h"
20 #include "output.h"
21 #include "OutputParams.h"
22 #include "Paragraph.h"
23 #include "ParagraphList.h"
24 #include "ParagraphParameters.h"
25
26 #include "support/lstrings.h"
27
28 using namespace std;
29
30 namespace lyx {
31
32 using support::ascii_lowercase;
33 using support::compare_ascii_no_case;
34 using support::contains;
35 using support::FileName;
36
37
38 void writePlaintextFile(Buffer const & buf, FileName const & fname,
39         OutputParams const & runparams)
40 {
41         odocfstream ofs("UTF-8");
42         if (!openFileWrite(ofs, fname))
43                 return;
44         writePlaintextFile(buf, ofs, runparams);
45 }
46
47
48 void writePlaintextFile(Buffer const & buf, odocstream & os,
49         OutputParams const & runparams)
50 {
51         bool ref_printed = false;
52         ParagraphList const par = buf.paragraphs();
53         ParagraphList::const_iterator beg = par.begin();
54         ParagraphList::const_iterator end = par.end();
55         ParagraphList::const_iterator it = beg;
56         for (; it != end; ++it) {
57                 writePlaintextParagraph(buf, *it, os, runparams, ref_printed);
58                 os << "\n";
59                 if (runparams.linelen > 0)
60                         os << "\n";
61         }
62 }
63
64
65 namespace {
66
67 pair<int, docstring> const addDepth(int depth, int ldepth)
68 {
69         int d = depth * 2;
70         if (ldepth > depth)
71                 d += (ldepth - depth) * 2;
72         return make_pair(d, docstring(d, ' '));
73 }
74
75 }
76
77
78 void writePlaintextParagraph(Buffer const & buf,
79                     Paragraph const & par,
80                     odocstream & os,
81                     OutputParams const & runparams,
82                     bool & ref_printed)
83 {
84         int ltype = 0;
85         depth_type ltype_depth = 0;
86         depth_type depth = par.params().depth();
87
88         // First write the layout
89         string const tmp = to_utf8(par.layout()->name());
90         if (compare_ascii_no_case(tmp, "itemize") == 0) {
91                 ltype = 1;
92                 ltype_depth = depth + 1;
93         } else if (compare_ascii_no_case(tmp, "enumerate") == 0) {
94                 ltype = 2;
95                 ltype_depth = depth + 1;
96         } else if (contains(ascii_lowercase(tmp), "ection")) {
97                 ltype = 3;
98                 ltype_depth = depth + 1;
99         } else if (contains(ascii_lowercase(tmp), "aragraph")) {
100                 ltype = 4;
101                 ltype_depth = depth + 1;
102         } else if (compare_ascii_no_case(tmp, "description") == 0) {
103                 ltype = 5;
104                 ltype_depth = depth + 1;
105         } else if (compare_ascii_no_case(tmp, "abstract") == 0) {
106                 ltype = 6;
107                 ltype_depth = 0;
108         } else if (compare_ascii_no_case(tmp, "bibliography") == 0) {
109                 ltype = 7;
110                 ltype_depth = 0;
111         } else {
112                 ltype = 0;
113                 ltype_depth = 0;
114         }
115
116         /* the labelwidthstring used in lists */
117
118         /* noindent ? */
119
120         /* what about the alignment */
121
122         // runparams.linelen == 0 is special and means we don't have paragraph breaks
123
124         string::size_type currlinelen = 0;
125
126         os << docstring(depth * 2, ' ');
127         currlinelen += depth * 2;
128
129         //--
130         // we should probably change to the paragraph language in the
131         // support/gettext.here (if possible) so that strings are output in
132         // the correct language! (20012712 Jug)
133         //--
134         switch (ltype) {
135         case 0: // Standard
136         case 4: // (Sub)Paragraph
137         case 5: // Description
138                 break;
139
140         case 6: // Abstract
141                 if (runparams.linelen > 0) {
142                         os << buf.B_("Abstract") << "\n\n";
143                         currlinelen = 0;
144                 } else {
145                         docstring const abst = buf.B_("Abstract: ");
146                         os << abst;
147                         currlinelen += abst.length();
148                 }
149                 break;
150
151         case 7: // Bibliography
152                 if (!ref_printed) {
153                         if (runparams.linelen > 0) {
154                                 os << buf.B_("References") << "\n\n";
155                                 currlinelen = 0;
156                         } else {
157                                 docstring const refs = buf.B_("References: ");
158                                 os << refs;
159                                 currlinelen += refs.length();
160                         }
161                         ref_printed = true;
162                 }
163                 break;
164
165         default: {
166                 docstring const label = par.params().labelString();
167                 if (!label.empty()) {
168                         os << label << ' ';
169                         currlinelen += label.length() + 1;
170                 }
171                 break;
172         }
173
174         }
175
176         if (currlinelen == 0) {
177                 pair<int, docstring> p = addDepth(depth, ltype_depth);
178                 os << p.second;
179                 currlinelen += p.first;
180         }
181
182         docstring word;
183
184         for (pos_type i = 0; i < par.size(); ++i) {
185                 // deleted characters don't make much sense in plain text output
186                 if (par.isDeleted(i))
187                         continue;
188
189                 char_type c = par.getUChar(buf.params(), i);
190
191                 if (par.isInset(i) || c == ' ') {
192                         if (runparams.linelen > 0 &&
193                             currlinelen + word.length() > runparams.linelen) {
194                                 os << '\n';
195                                 pair<int, docstring> p = addDepth(depth, ltype_depth);
196                                 os << p.second;
197                                 currlinelen = p.first;
198                         }
199                         os << word;
200                         currlinelen += word.length();
201                         word.erase();
202                 }
203
204                 if (par.isInset(i)) {
205                         OutputParams rp = runparams;
206                         rp.depth = par.params().depth();
207                         int len = par.getInset(i)->plaintext(buf, os, rp);
208                         if (len >= Inset::PLAINTEXT_NEWLINE)
209                                 currlinelen = len - Inset::PLAINTEXT_NEWLINE;
210                         else
211                                 currlinelen += len;
212                         continue;
213                 }
214
215                 switch (c) {
216                 case ' ':
217                         os << ' ';
218                         currlinelen++;
219                         break;
220
221                 case '\0':
222                         LYXERR(Debug::INFO, "writePlaintextFile: NULL char in structure.");
223                         break;
224
225                 default:
226                         word += c;
227                         break;
228                 }
229         }
230
231         // currlinelen may be greater than runparams.linelen!
232         // => check whether word is empty and do nothing in this case
233         if (!word.empty()) {
234                 if (runparams.linelen > 0 &&
235                     currlinelen + word.length() > runparams.linelen) {
236                         os << '\n';
237                         pair<int, docstring> p = addDepth(depth, ltype_depth);
238                         os << p.second;
239                         currlinelen = p.first;
240                 }
241                 os << word;
242         }
243 }
244
245
246 } // namespace lyx