/src/libetonyek/src/lib/IWORKTable.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* |
3 | | * This file is part of the libetonyek project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #include "IWORKTable.h" |
11 | | |
12 | | #include <cassert> |
13 | | #include <ctime> |
14 | | #include <iomanip> |
15 | | #include <set> |
16 | | #include <sstream> |
17 | | |
18 | | #include <boost/numeric/conversion/cast.hpp> |
19 | | |
20 | | #include <glm/glm.hpp> |
21 | | |
22 | | #include "libetonyek_xml.h" |
23 | | #include "libetonyek_utils.h" |
24 | | #include "IWORKDocumentInterface.h" |
25 | | #include "IWORKProperties.h" |
26 | | #include "IWORKStyle.h" |
27 | | #include "IWORKStyleStack.h" |
28 | | #include "IWORKTableRecorder.h" |
29 | | #include "IWORKText.h" |
30 | | #include "IWORKTypes.h" |
31 | | |
32 | | using boost::none; |
33 | | using boost::numeric_cast; |
34 | | using boost::optional; |
35 | | |
36 | | using std::string; |
37 | | |
38 | | namespace libetonyek |
39 | | { |
40 | | |
41 | | namespace |
42 | | { |
43 | | |
44 | | void parseDateTimeFormat(std::string const &format, librevenge::RVNGPropertyList &props, boost::optional<std::string> &rvngValueType) |
45 | 0 | { |
46 | 0 | if (format.empty()) |
47 | 0 | { |
48 | 0 | ETONYEK_DEBUG_MSG(("parseDateTimeFormat[IWORKTable.cpp]: called without format string\n")); |
49 | 0 | return; |
50 | 0 | } |
51 | 0 | std::string text(""); |
52 | 0 | librevenge::RVNGPropertyListVector propVect; |
53 | 0 | size_t len=format.size(); |
54 | 0 | bool hasDate=false, findSomeToken=false, inText=false; |
55 | 0 | for (size_t c=0; c < len;) |
56 | 0 | { |
57 | 0 | size_t numCh=1; |
58 | 0 | char ch=format[c++]; |
59 | 0 | if (inText) |
60 | 0 | { |
61 | 0 | if (ch=='\'') |
62 | 0 | inText=false; |
63 | 0 | else |
64 | 0 | text+=ch; |
65 | 0 | continue; |
66 | 0 | } |
67 | 0 | if (ch=='\'') |
68 | 0 | { |
69 | 0 | inText=true; |
70 | 0 | continue; |
71 | 0 | } |
72 | 0 | while (numCh<4 && c < len && format[c]==ch) |
73 | 0 | { |
74 | 0 | ++numCh; |
75 | 0 | ++c; |
76 | 0 | } |
77 | 0 | librevenge::RVNGPropertyList list; |
78 | 0 | switch (ch) |
79 | 0 | { |
80 | 0 | case 'a': |
81 | 0 | list.insert("librevenge:value-type", "am-pm"); |
82 | 0 | c-=(numCh-1); |
83 | 0 | break; |
84 | 0 | case 'd': |
85 | 0 | hasDate=true; |
86 | 0 | list.insert("librevenge:value-type", "day"); |
87 | 0 | if (numCh>1) list.insert("number:style", "long"); |
88 | 0 | if (numCh>2) c-=(numCh-2); |
89 | 0 | break; |
90 | 0 | case 'h': |
91 | 0 | case 'k': |
92 | 0 | list.insert("librevenge:value-type", "hours"); |
93 | 0 | if (numCh>2) c-=(numCh-2); |
94 | 0 | break; |
95 | 0 | case 'm': |
96 | 0 | list.insert("librevenge:value-type", "minutes"); |
97 | 0 | list.insert("number:style", "long"); |
98 | 0 | if (numCh>2) c-=(numCh-2); |
99 | 0 | break; |
100 | 0 | case 's': |
101 | 0 | list.insert("librevenge:value-type", "seconds"); |
102 | 0 | list.insert("number:style", "long"); |
103 | 0 | if (numCh>2) c-=(numCh-2); |
104 | 0 | break; |
105 | 0 | case 'y': |
106 | 0 | hasDate=true; |
107 | 0 | list.insert("librevenge:value-type", "year"); |
108 | 0 | if (numCh>2) list.insert("number:style", "long"); |
109 | 0 | break; |
110 | 0 | case 'E': |
111 | 0 | hasDate=true; |
112 | 0 | list.insert("librevenge:value-type", "day-of-week"); |
113 | 0 | if (numCh>3) list.insert("number:style", "long"); |
114 | 0 | break; |
115 | 0 | case 'H': |
116 | 0 | case 'K': |
117 | 0 | list.insert("librevenge:value-type", "hours"); |
118 | 0 | list.insert("number:style", "long"); |
119 | 0 | if (numCh>2) c-=(numCh-2); |
120 | 0 | break; |
121 | 0 | case 'M': |
122 | 0 | hasDate=true; |
123 | 0 | list.insert("librevenge:value-type", "month"); |
124 | 0 | if ((numCh%2)==0) list.insert("number:style", "long"); |
125 | 0 | if (numCh>2) list.insert("number:textual", true); |
126 | 0 | break; |
127 | | // G: Era designator? |
128 | 0 | default: |
129 | 0 | break; |
130 | 0 | } |
131 | 0 | if (!list.empty()) |
132 | 0 | { |
133 | 0 | if (!text.empty()) |
134 | 0 | { |
135 | 0 | librevenge::RVNGPropertyList tList; |
136 | 0 | tList.insert("librevenge:value-type", "text"); |
137 | 0 | tList.insert("librevenge:text", text.c_str()); |
138 | 0 | propVect.append(tList); |
139 | 0 | } |
140 | 0 | text.clear(); |
141 | 0 | propVect.append(list); |
142 | 0 | findSomeToken=true; |
143 | 0 | } |
144 | 0 | else |
145 | 0 | { |
146 | 0 | for (size_t n=0; n<numCh; ++n) |
147 | 0 | text += ch; |
148 | 0 | } |
149 | 0 | } |
150 | 0 | if (!findSomeToken || inText) |
151 | 0 | { |
152 | 0 | ETONYEK_DEBUG_MSG(("parseDateTimeFormat[IWORKTable.cpp]: something went bad when parsing %s\n", format.c_str())); |
153 | 0 | return; |
154 | 0 | } |
155 | 0 | if (!text.empty()) |
156 | 0 | { |
157 | 0 | librevenge::RVNGPropertyList list; |
158 | 0 | list.insert("librevenge:value-type", "text"); |
159 | 0 | list.insert("librevenge:text", text.c_str()); |
160 | 0 | propVect.append(list); |
161 | 0 | } |
162 | 0 | rvngValueType = hasDate ? "date" : "time"; |
163 | 0 | props.insert("librevenge:value-type", get(rvngValueType).c_str()); |
164 | 0 | props.insert("number:automatic-order", "true"); |
165 | 0 | if (propVect.count()) |
166 | 0 | props.insert("librevenge:format", propVect); |
167 | 0 | } |
168 | | |
169 | | void writeBorder(librevenge::RVNGPropertyList &props, const char *name, IWORKGridLine_t &line, unsigned index) |
170 | 1.19k | { |
171 | 1.19k | if (!line.valid_tree()) |
172 | 197 | line.build_tree(); |
173 | | |
174 | 1.19k | IWORKStylePtr_t style; |
175 | 1.19k | line.search_tree(index, style); |
176 | 1.19k | if (style && style->has<property::SFTStrokeProperty>()) |
177 | 194 | writeBorder(style->get<property::SFTStrokeProperty>(), name, props); |
178 | 1.19k | } |
179 | | |
180 | | void writeCellStyle(librevenge::RVNGPropertyList &props, const IWORKStyleStack &style) |
181 | 2.88k | { |
182 | 2.88k | using namespace property; |
183 | | |
184 | 2.88k | IWORKVerticalAlignment vertAlign(IWORK_VERTICAL_ALIGNMENT_MIDDLE); |
185 | 2.88k | if (style.has<VerticalAlignment>()) |
186 | 1.08k | vertAlign = style.get<VerticalAlignment>(); |
187 | 2.88k | switch (vertAlign) |
188 | 2.88k | { |
189 | 240 | case IWORK_VERTICAL_ALIGNMENT_TOP : |
190 | 240 | props.insert("style:vertical-align", "top"); |
191 | 240 | break; |
192 | 2.64k | case IWORK_VERTICAL_ALIGNMENT_MIDDLE : |
193 | 2.64k | props.insert("style:vertical-align", "middle"); |
194 | 2.64k | break; |
195 | 0 | case IWORK_VERTICAL_ALIGNMENT_BOTTOM : |
196 | 0 | props.insert("style:vertical-align", "bottom"); |
197 | 0 | break; |
198 | 0 | default: |
199 | 0 | ETONYEK_DEBUG_MSG(("writeCellStyle[IWORKTable.cpp]: unexpected alignement\n")); |
200 | 2.88k | } |
201 | | |
202 | 2.88k | if (style.has<TopBorder>()) |
203 | 0 | writeBorder(style.get<TopBorder>(), "fo:border-top", props); |
204 | 2.88k | if (style.has<BottomBorder>()) |
205 | 0 | writeBorder(style.get<BottomBorder>(), "fo:border-bottom", props); |
206 | 2.88k | if (style.has<LeftBorder>()) |
207 | 0 | writeBorder(style.get<LeftBorder>(), "fo:border-left", props); |
208 | 2.88k | if (style.has<RightBorder>()) |
209 | 0 | writeBorder(style.get<RightBorder>(), "fo:border-right", props); |
210 | | |
211 | 2.88k | if (style.has<Fill>()) |
212 | 1.24k | { |
213 | | // TODO: add support for style:background-image to libodfgen |
214 | 1.24k | double opacity=style.has<Opacity>() ? style.get<Opacity>() : 1.; |
215 | 1.24k | if (const IWORKColor *const color = boost::get<IWORKColor>(&style.get<Fill>())) |
216 | 1.23k | { |
217 | 1.23k | props.insert("fo:background-color", makeColor(*color)); |
218 | 1.23k | opacity *= color->m_alpha; |
219 | 1.23k | } |
220 | 6 | else if (const IWORKGradient *const gradient = boost::get<IWORKGradient>(&style.get<Fill>())) |
221 | 0 | props.insert("fo:background-color", makeColor(*gradient)); |
222 | 1.24k | if (opacity<1) |
223 | 151 | props.insert("draw:opacity", opacity, librevenge::RVNG_PERCENT); |
224 | 1.24k | } |
225 | | |
226 | 2.88k | if (style.has<Padding>()) |
227 | 1.04k | { |
228 | 1.04k | const IWORKPadding &padding = style.get<Padding>(); |
229 | 1.04k | if (padding.m_left) |
230 | 1.04k | props.insert("fo:padding-left", get(padding.m_left), librevenge::RVNG_POINT); |
231 | 1.04k | if (padding.m_right) |
232 | 1.02k | props.insert("fo:padding-right", get(padding.m_right), librevenge::RVNG_POINT); |
233 | 1.04k | if (padding.m_top) |
234 | 1.03k | props.insert("fo:padding-top", get(padding.m_top), librevenge::RVNG_POINT); |
235 | 1.04k | if (padding.m_bottom) |
236 | 1.01k | props.insert("fo:padding-bottom", get(padding.m_bottom), librevenge::RVNG_POINT); |
237 | 1.04k | } |
238 | 2.88k | } |
239 | | |
240 | | bool writeCellValue(librevenge::RVNGPropertyList &props, |
241 | | const boost::optional<std::string> &styleName, |
242 | | const IWORKCellType type, const boost::optional<std::string> &valueType, |
243 | | const boost::optional<std::string> &value, const boost::optional<IWORKDateTimeData> &dateTime) |
244 | 0 | try |
245 | 0 | { |
246 | 0 | using namespace property; |
247 | | |
248 | | // TODO: what's this anyway? |
249 | 0 | if (styleName) |
250 | 0 | props.insert("librevenge:name", get(styleName).c_str()); |
251 | 0 | switch (type) |
252 | 0 | { |
253 | 0 | case IWORK_CELL_TYPE_NUMBER : |
254 | 0 | if (valueType) |
255 | 0 | { |
256 | 0 | props.insert("librevenge:value-type", get(valueType).c_str()); |
257 | 0 | props.insert("librevenge:value", value ? get(value).c_str() : "0"); |
258 | 0 | return true; |
259 | 0 | } |
260 | 0 | else if (value) |
261 | 0 | { |
262 | 0 | props.insert("librevenge:value-type", "double"); |
263 | 0 | props.insert("librevenge:value", get(value).c_str()); |
264 | 0 | return true; |
265 | 0 | } |
266 | 0 | break; |
267 | 0 | case IWORK_CELL_TYPE_DATE_TIME : |
268 | 0 | if (value || dateTime) |
269 | 0 | { |
270 | 0 | props.insert("librevenge:value-type", valueType ? get(valueType).c_str() : "date"); |
271 | |
|
272 | 0 | if (dateTime) |
273 | 0 | { |
274 | 0 | props.insert("librevenge:day", get(dateTime).m_day); |
275 | 0 | props.insert("librevenge:month", get(dateTime).m_month); |
276 | 0 | props.insert("librevenge:year", get(dateTime).m_year); |
277 | 0 | props.insert("librevenge:hours", get(dateTime).m_hour); |
278 | 0 | props.insert("librevenge:minutes", get(dateTime).m_minute); |
279 | 0 | props.insert("librevenge:seconds", get(dateTime).m_second); |
280 | 0 | return true; |
281 | 0 | } |
282 | 0 | else |
283 | 0 | { |
284 | 0 | boost::optional<double> seconds=try_double_cast(get(value).c_str()); |
285 | 0 | if (!seconds) |
286 | 0 | { |
287 | 0 | ETONYEK_DEBUG_MSG(("writeCellValue[IWORKTable.cpp]: can not read seconds\n")); |
288 | 0 | break; |
289 | 0 | } |
290 | 0 | const auto t = std::time_t(ETONYEK_EPOCH_BEGIN + get(seconds)); |
291 | 0 | struct tm *const time = gmtime(&t); |
292 | |
|
293 | 0 | if (!time) |
294 | 0 | { |
295 | 0 | ETONYEK_DEBUG_MSG(("writeCellValue[IWORKTable.cpp]: can not convert seconds in time\n")); |
296 | 0 | break; |
297 | 0 | } |
298 | 0 | props.insert("librevenge:day", time->tm_mday); |
299 | 0 | props.insert("librevenge:month", time->tm_mon + 1); |
300 | 0 | props.insert("librevenge:year", time->tm_year + 1900); |
301 | 0 | props.insert("librevenge:hours", time->tm_hour); |
302 | 0 | props.insert("librevenge:minutes", time->tm_min); |
303 | 0 | props.insert("librevenge:seconds", time->tm_sec); |
304 | 0 | return true; |
305 | 0 | } |
306 | 0 | } |
307 | 0 | break; |
308 | 0 | case IWORK_CELL_TYPE_DURATION : |
309 | 0 | if (value) |
310 | 0 | { |
311 | 0 | const int seconds = int(double_cast(get(value).c_str())); |
312 | 0 | props.insert("librevenge:value-type", valueType ? get(valueType).c_str() : "time"); |
313 | 0 | props.insert("librevenge:hours", int(seconds / 3600)); |
314 | 0 | props.insert("librevenge:minutes", int((seconds % 3600) / 60)); |
315 | 0 | props.insert("librevenge:seconds", int((seconds % 3600) % 60)); |
316 | 0 | return true; |
317 | 0 | } |
318 | 0 | break; |
319 | 0 | case IWORK_CELL_TYPE_BOOL : |
320 | 0 | props.insert("librevenge:value-type", valueType ? get(valueType).c_str() : "boolean"); |
321 | 0 | props.insert("librevenge:value", value ? get(value).c_str() : "0"); // false is default |
322 | 0 | return true; |
323 | 0 | case IWORK_CELL_TYPE_TEXT : |
324 | 0 | default: |
325 | | //TODO: librevenge:name ? |
326 | 0 | if (value) |
327 | 0 | props.insert("librevenge:value-type", "string"); |
328 | 0 | break; |
329 | 0 | } |
330 | 0 | return false; |
331 | 0 | } |
332 | 0 | catch (...) |
333 | 0 | { |
334 | 0 | ETONYEK_DEBUG_MSG(("writeCellValue[IWORKTable.cpp]: catch exception\n")); |
335 | 0 | return false; |
336 | 0 | } |
337 | | |
338 | | librevenge::RVNGString convertCellValueInText(const IWORKStyleStack &style, const IWORKCellType type, const boost::optional<std::string> &value, const boost::optional<IWORKDateTimeData> &dateTime) |
339 | 2.84k | { |
340 | 2.84k | try |
341 | 2.84k | { |
342 | 2.84k | using namespace property; |
343 | 2.84k | switch (type) |
344 | 2.84k | { |
345 | 3 | case IWORK_CELL_TYPE_NUMBER : |
346 | 3 | { |
347 | 3 | int numDecimals=2; |
348 | 3 | IWORKCellNumberType formatType=IWORK_CELL_NUMBER_TYPE_DOUBLE; |
349 | 3 | std::string currency("$"); |
350 | 3 | if (style.has<SFTCellStylePropertyNumberFormat>()) |
351 | 0 | { |
352 | 0 | const IWORKNumberFormat &format = style.get<SFTCellStylePropertyNumberFormat>(); |
353 | 0 | numDecimals=format.m_decimalPlaces; |
354 | 0 | formatType=format.m_type; |
355 | 0 | currency=format.m_currencyCode.c_str(); |
356 | 0 | } |
357 | 3 | const double val = value ? double_cast(get(value).c_str()) : 0; |
358 | 3 | std::stringstream s; |
359 | 3 | if (numDecimals>=0 && numDecimals<100) // 65535 means default |
360 | 3 | s << std::setprecision(-numDecimals); |
361 | 3 | switch (formatType) |
362 | 3 | { |
363 | 0 | case IWORK_CELL_NUMBER_TYPE_CURRENCY : |
364 | 0 | s << std::fixed << val << currency; |
365 | 0 | break; |
366 | 0 | case IWORK_CELL_NUMBER_TYPE_PERCENTAGE : |
367 | 0 | s << std::fixed << 100*val << "%"; |
368 | 0 | break; |
369 | 0 | case IWORK_CELL_NUMBER_TYPE_SCIENTIFIC : |
370 | 0 | s << std::scientific << val; |
371 | 0 | break; |
372 | 3 | case IWORK_CELL_NUMBER_TYPE_DOUBLE : |
373 | 3 | s << val; |
374 | 3 | break; |
375 | 0 | case IWORK_CELL_NUMBER_TYPE_FRACTION : |
376 | 0 | default: |
377 | 0 | ETONYEK_DEBUG_MSG(("convertCellValueInText: unexpected number format\n")); |
378 | 3 | } |
379 | 3 | return s.str().c_str(); |
380 | 3 | } |
381 | 0 | case IWORK_CELL_TYPE_DATE_TIME : |
382 | 0 | { |
383 | 0 | if (dateTime) |
384 | 0 | { |
385 | 0 | librevenge::RVNGString res; |
386 | 0 | if (get(dateTime).m_hour) |
387 | 0 | res.sprintf("%d/%d/%d %d:%d", get(dateTime).m_month, get(dateTime).m_day, get(dateTime).m_year, get(dateTime).m_hour, get(dateTime).m_minute); |
388 | 0 | else |
389 | 0 | res.sprintf("%d/%d/%d", get(dateTime).m_month, get(dateTime).m_day, get(dateTime).m_year); |
390 | 0 | return res; |
391 | 0 | } |
392 | 0 | if (!value) break; |
393 | 0 | boost::optional<double> seconds=try_double_cast(get(value).c_str()); |
394 | 0 | if (!seconds) |
395 | 0 | { |
396 | 0 | ETONYEK_DEBUG_MSG(("convertCellValueInText: can not read seconds\n")); |
397 | 0 | break; |
398 | 0 | } |
399 | 0 | const auto t = std::time_t(ETONYEK_EPOCH_BEGIN + get(seconds)); |
400 | 0 | struct tm *const time = gmtime(&t); |
401 | 0 | librevenge::RVNGString res; |
402 | 0 | if (time->tm_hour) |
403 | 0 | res.sprintf("%d/%d/%d %d:%d", time->tm_mon + 1, time->tm_mday, time->tm_year + 1900, time->tm_hour, time->tm_min); |
404 | 0 | else |
405 | 0 | res.sprintf("%d/%d/%d", time->tm_mon + 1, time->tm_mday, time->tm_year + 1900); |
406 | 0 | return res; |
407 | 0 | } |
408 | 0 | case IWORK_CELL_TYPE_DURATION : |
409 | 0 | { |
410 | 0 | if (!value) break; |
411 | 0 | const int seconds = int(double_cast(get(value).c_str())); |
412 | 0 | librevenge::RVNGString res; |
413 | 0 | res.sprintf("%d:%d:%d", int(seconds / 3600), int((seconds % 3600) / 60), int((seconds % 3600) % 60)); |
414 | 0 | return res; |
415 | 0 | } |
416 | 0 | case IWORK_CELL_TYPE_BOOL : |
417 | 0 | return value && get(value)!="0" ? "true" : "false"; |
418 | 2.83k | case IWORK_CELL_TYPE_TEXT : |
419 | 2.83k | default: |
420 | 2.83k | break; |
421 | 2.84k | } |
422 | 2.84k | } |
423 | 2.84k | catch (...) |
424 | 2.84k | { |
425 | 0 | ETONYEK_DEBUG_MSG(("convertCellValueInText: exception\n")); |
426 | 0 | } |
427 | 2.83k | return ""; |
428 | 2.84k | } |
429 | | |
430 | | } |
431 | | |
432 | | IWORKTable::Cell::Cell() |
433 | 1.06k | : m_content() |
434 | 1.06k | , m_columnSpan(1) |
435 | 1.06k | , m_rowSpan(1) |
436 | 1.06k | , m_covered(false) |
437 | 1.06k | , m_formula() |
438 | 1.06k | , m_formulaHC() |
439 | 1.06k | , m_style() |
440 | 1.06k | , m_type(IWORK_CELL_TYPE_TEXT) |
441 | 1.06k | , m_value() |
442 | 1.06k | , m_dateTime() |
443 | 1.06k | { |
444 | 1.06k | } |
445 | | |
446 | | IWORKTable::IWORKTable(const IWORKTableNameMapPtr_t &tableNameMap, IWORKFormatNameMap &formatNameMap, const IWORKLanguageManager &langManager) |
447 | 147 | : m_tableNameMap(tableNameMap) |
448 | 147 | , m_langManager(langManager) |
449 | 147 | , m_formatNameMap(formatNameMap) |
450 | 147 | , m_commentMap() |
451 | 147 | , m_table() |
452 | 147 | , m_style() |
453 | 147 | , m_name() |
454 | 147 | , m_order() |
455 | 147 | , m_columnSizes() |
456 | 147 | , m_rowSizes() |
457 | 147 | , m_verticalLines() |
458 | 147 | , m_verticalRightLines() |
459 | 147 | , m_horizontalLines() |
460 | 147 | , m_horizontalBottomLines() |
461 | 147 | , m_rows(0) |
462 | 147 | , m_columns(0) |
463 | 147 | , m_headerRows(0) |
464 | 147 | , m_footerRows(0) |
465 | 147 | , m_headerColumns(0) |
466 | 147 | , m_bandedRows(false) |
467 | 147 | , m_headerRowsRepeated(false) |
468 | 147 | , m_headerColumnsRepeated(false) |
469 | 147 | , m_recorder() |
470 | 147 | { |
471 | 147 | } |
472 | | |
473 | | void IWORKTable::setRecorder(const std::shared_ptr<IWORKTableRecorder> &recorder) |
474 | 0 | { |
475 | 0 | m_recorder = recorder; |
476 | 0 | } |
477 | | |
478 | | const std::shared_ptr<IWORKTableRecorder> &IWORKTable::getRecorder() const |
479 | 0 | { |
480 | 0 | return m_recorder; |
481 | 0 | } |
482 | | |
483 | | void IWORKTable::setName(std::string const &name) |
484 | 125 | { |
485 | 125 | m_name=name; |
486 | 125 | } |
487 | | |
488 | | void IWORKTable::setSize(const unsigned columns, const unsigned rows) |
489 | 147 | { |
490 | 147 | if (bool(m_recorder)) |
491 | 0 | { |
492 | 0 | m_recorder->setSize(columns, rows); |
493 | 0 | return; |
494 | 0 | } |
495 | | |
496 | 147 | m_columns = columns; |
497 | 147 | m_rows = rows; |
498 | 147 | } |
499 | | |
500 | | void IWORKTable::setHeaders(const unsigned headerColumns, const unsigned headerRows, const unsigned footerRows) |
501 | 127 | { |
502 | 127 | if (bool(m_recorder)) |
503 | 0 | { |
504 | 0 | m_recorder->setHeaders(headerColumns, headerRows, footerRows); |
505 | 0 | return; |
506 | 0 | } |
507 | | |
508 | 127 | m_headerColumns = headerColumns; |
509 | 127 | m_headerRows = headerRows; |
510 | 127 | m_footerRows = footerRows; |
511 | 127 | } |
512 | | |
513 | | void IWORKTable::setBandedRows(const bool banded) |
514 | 37 | { |
515 | 37 | if (bool(m_recorder)) |
516 | 0 | { |
517 | 0 | m_recorder->setBandedRows(banded); |
518 | 0 | return; |
519 | 0 | } |
520 | | |
521 | 37 | m_bandedRows = banded; |
522 | 37 | } |
523 | | |
524 | | void IWORKTable::setRepeated(const bool columns, const bool rows) |
525 | 126 | { |
526 | 126 | if (bool(m_recorder)) |
527 | 0 | { |
528 | 0 | m_recorder->setRepeated(columns, rows); |
529 | 0 | return; |
530 | 0 | } |
531 | | |
532 | 126 | m_headerColumnsRepeated = columns; |
533 | 126 | m_headerRowsRepeated = rows; |
534 | 126 | } |
535 | | |
536 | | void IWORKTable::setOrder(int order) |
537 | 0 | { |
538 | 0 | if (bool(m_recorder)) |
539 | 0 | { |
540 | 0 | m_recorder->setOrder(order); |
541 | 0 | return; |
542 | 0 | } |
543 | | |
544 | 0 | m_order = order; |
545 | 0 | } |
546 | | |
547 | | void IWORKTable::setStyle(const IWORKStylePtr_t &style) |
548 | 48 | { |
549 | 48 | if (bool(m_recorder)) |
550 | 0 | { |
551 | 0 | m_recorder->setStyle(style); |
552 | 0 | return; |
553 | 0 | } |
554 | | |
555 | 48 | m_style = style; |
556 | 48 | } |
557 | | |
558 | | void IWORKTable::setSizes(const IWORKColumnSizes_t &columnSizes, const IWORKRowSizes_t &rowSizes) |
559 | 128 | { |
560 | 128 | if (bool(m_recorder)) |
561 | 0 | { |
562 | 0 | m_recorder->setSizes(columnSizes, rowSizes); |
563 | 0 | return; |
564 | 0 | } |
565 | | |
566 | 128 | m_columnSizes = columnSizes; |
567 | 128 | m_rowSizes = rowSizes; |
568 | | |
569 | | // init. content table of appropriate dimensions |
570 | 128 | m_table = Table_t(m_rowSizes.size(), Row_t()); |
571 | 128 | } |
572 | | |
573 | | void IWORKTable::setBorders(const IWORKGridLineMap_t &verticalLines, const IWORKGridLineMap_t &horizontalLines) |
574 | 0 | { |
575 | 0 | if (bool(m_recorder)) |
576 | 0 | { |
577 | 0 | m_recorder->setBorders(verticalLines, horizontalLines); |
578 | 0 | return; |
579 | 0 | } |
580 | | |
581 | 0 | m_verticalLines = verticalLines; |
582 | 0 | m_horizontalLines = horizontalLines; |
583 | 0 | } |
584 | | |
585 | | void IWORKTable::setComment(unsigned column, unsigned row, IWORKOutputElements const &text) |
586 | 0 | { |
587 | 0 | if (bool(m_recorder)) |
588 | 0 | { |
589 | 0 | m_recorder->setComment(column,row,text); |
590 | 0 | return; |
591 | 0 | } |
592 | 0 | m_commentMap[std::make_pair(row,column)]=text; |
593 | 0 | } |
594 | | |
595 | | void IWORKTable::setBorders(const IWORKGridLineMap_t &verticalLeftLines, const IWORKGridLineMap_t &verticalRightLines, |
596 | | const IWORKGridLineMap_t &horizontalTopLines, const IWORKGridLineMap_t &horizontalBottomLines) |
597 | 108 | { |
598 | 108 | if (bool(m_recorder)) |
599 | 0 | { |
600 | 0 | m_recorder->setBorders(verticalLeftLines, verticalRightLines, horizontalTopLines, horizontalBottomLines); |
601 | 0 | return; |
602 | 0 | } |
603 | | |
604 | 108 | m_verticalLines = verticalLeftLines; |
605 | 108 | m_verticalRightLines = verticalRightLines; |
606 | 108 | m_horizontalLines = horizontalTopLines; |
607 | 108 | m_horizontalBottomLines = horizontalBottomLines; |
608 | 108 | } |
609 | | |
610 | | void IWORKTable::insertCell(const unsigned column, const unsigned row, const boost::optional<std::string> &value, const std::shared_ptr<IWORKText> &text, const boost::optional<IWORKDateTimeData> &dateTime, const unsigned columnSpan, const unsigned rowSpan, const IWORKFormulaPtr_t &formula, const boost::optional<unsigned> &formulaHC, const IWORKStylePtr_t &style, const IWORKCellType type) |
611 | 179 | { |
612 | 179 | if (bool(m_recorder)) |
613 | 0 | { |
614 | 0 | m_recorder->insertCell(column, row, value, text, dateTime, columnSpan, rowSpan, formula, formulaHC, style, type); |
615 | 0 | return; |
616 | 0 | } |
617 | | |
618 | 179 | if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column)) |
619 | 5 | return; |
620 | | |
621 | 174 | Cell cell; |
622 | 174 | if (bool(text)) |
623 | 38 | { |
624 | 38 | IWORKStyleStack fStyle; |
625 | 38 | fStyle.push(getDefaultCellStyle(column, row)); |
626 | 38 | fStyle.push(style); |
627 | 38 | using namespace property; |
628 | 38 | if (fStyle.has<SFTCellStylePropertyParagraphStyle>()) |
629 | 0 | text->pushBaseParagraphStyle(fStyle.get<SFTCellStylePropertyParagraphStyle>()); |
630 | 38 | else |
631 | 38 | text->pushBaseParagraphStyle(getDefaultParagraphStyle(column,row)); |
632 | 38 | if (fStyle.has<SFTCellStylePropertyLayoutStyle>()) |
633 | 0 | text->pushBaseLayoutStyle(fStyle.get<SFTCellStylePropertyLayoutStyle>()); |
634 | 38 | else |
635 | 38 | text->pushBaseLayoutStyle(getDefaultLayoutStyle(column,row)); |
636 | 38 | text->draw(cell.m_content); |
637 | 38 | } |
638 | 174 | cell.m_columnSpan = columnSpan; |
639 | 174 | cell.m_rowSpan = rowSpan; |
640 | 174 | cell.m_formula = formula; |
641 | 174 | cell.m_formulaHC = formulaHC; |
642 | 174 | cell.m_style = style; |
643 | 174 | cell.m_type = type; |
644 | 174 | cell.m_value = value; |
645 | 174 | cell.m_dateTime = dateTime; |
646 | 174 | m_table[row][column] = cell; |
647 | 174 | } |
648 | | |
649 | | void IWORKTable::insertCoveredCell(const unsigned column, const unsigned row) |
650 | 0 | { |
651 | 0 | if (bool(m_recorder)) |
652 | 0 | { |
653 | 0 | m_recorder->insertCoveredCell(column, row); |
654 | 0 | return; |
655 | 0 | } |
656 | | |
657 | 0 | if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column)) |
658 | 0 | return; |
659 | | |
660 | 0 | Cell cell; |
661 | 0 | cell.m_covered = true; |
662 | 0 | m_table[row][column] = cell; |
663 | 0 | } |
664 | | |
665 | | boost::optional<std::string> IWORKTable::writeFormat(IWORKOutputElements &elements, const IWORKStylePtr_t &style, const IWORKCellType type, boost::optional<std::string> &rvngValueType) |
666 | 0 | { |
667 | 0 | if (!style) return none; |
668 | 0 | librevenge::RVNGPropertyList props; |
669 | 0 | switch (type) |
670 | 0 | { |
671 | 0 | case IWORK_CELL_TYPE_NUMBER : |
672 | 0 | if (style->has<property::SFTCellStylePropertyNumberFormat>()) |
673 | 0 | { |
674 | 0 | const IWORKNumberFormat &format = style->get<property::SFTCellStylePropertyNumberFormat>(); |
675 | 0 | props.insert("librevenge:value-type", format.getRVNGValueType().c_str()); |
676 | 0 | if (format.m_decimalPlaces>=0 && format.m_decimalPlaces<100) props.insert("number:decimal-places", format.m_decimalPlaces); |
677 | 0 | if (format.m_thousandsSeparator) props.insert("number:grouping", true); |
678 | 0 | rvngValueType=format.m_type==IWORK_CELL_NUMBER_TYPE_FRACTION ? "double" : format.getRVNGValueType().c_str(); |
679 | 0 | switch (format.m_type) |
680 | 0 | { |
681 | 0 | case IWORK_CELL_NUMBER_TYPE_CURRENCY : |
682 | 0 | { |
683 | 0 | librevenge::RVNGPropertyListVector pVect; |
684 | 0 | librevenge::RVNGPropertyList currency; |
685 | 0 | currency.insert("librevenge:value-type", "currency-symbol"); |
686 | 0 | currency.insert("number:language","en"); |
687 | 0 | currency.insert("number:country","US"); |
688 | 0 | currency.insert("librevenge:currency",format.m_currencyCode.c_str()); |
689 | 0 | if (format.m_decimalPlaces>=0) currency.insert("number:decimal-places", format.m_decimalPlaces); |
690 | 0 | pVect.append(currency); |
691 | 0 | props.insert("librevenge:format", pVect); |
692 | 0 | break; |
693 | 0 | } |
694 | 0 | case IWORK_CELL_NUMBER_TYPE_PERCENTAGE : |
695 | 0 | case IWORK_CELL_NUMBER_TYPE_SCIENTIFIC : |
696 | 0 | case IWORK_CELL_NUMBER_TYPE_DOUBLE : |
697 | 0 | break; |
698 | 0 | case IWORK_CELL_NUMBER_TYPE_FRACTION : |
699 | 0 | props.insert("number:min-integer-digits", 0); |
700 | 0 | props.insert("number:min-numerator-digits",1); |
701 | 0 | props.insert("number:min-denominator-digits", 1); |
702 | 0 | props.remove("number:decimal-places"); |
703 | 0 | break; |
704 | 0 | default: |
705 | 0 | ETONYEK_DEBUG_MSG(("IWORKTable::writeFormat: unexpected number format\n")); |
706 | 0 | return none; |
707 | 0 | } |
708 | 0 | } |
709 | 0 | break; |
710 | 0 | case IWORK_CELL_TYPE_DATE_TIME : // todo |
711 | 0 | if (style->has<property::SFTCellStylePropertyDateTimeFormat>()) |
712 | 0 | { |
713 | 0 | const IWORKDateTimeFormat &format = style->get<property::SFTCellStylePropertyDateTimeFormat>(); |
714 | 0 | parseDateTimeFormat(format.m_format, props, rvngValueType); |
715 | 0 | } |
716 | 0 | break; |
717 | 0 | case IWORK_CELL_TYPE_DURATION : // todo |
718 | | // TODO: How to insert format and convert? |
719 | | // const IWORKDurationFormat &format = style->get<SFTCellStylePropertyDurationFormat>(); |
720 | | // props.insert("librevenge:format",format.m_format.c_str()); |
721 | |
|
722 | 0 | case IWORK_CELL_TYPE_BOOL : |
723 | 0 | case IWORK_CELL_TYPE_TEXT : |
724 | 0 | default: |
725 | 0 | break; |
726 | 0 | } |
727 | 0 | if (props.empty()) |
728 | 0 | return none; |
729 | 0 | std::string hash=props.getPropString().cstr(); |
730 | 0 | auto it=m_formatNameMap.find(hash); |
731 | 0 | if (it!=m_formatNameMap.end()) |
732 | 0 | return it->second; |
733 | 0 | std::stringstream name; |
734 | 0 | name << "Numbering" << m_formatNameMap.size(); |
735 | 0 | m_formatNameMap[hash]=name.str(); |
736 | 0 | props.insert("librevenge:name", name.str().c_str()); |
737 | 0 | elements.addDefineSheetNumberingStyle(props); |
738 | 0 | return name.str(); |
739 | 0 | } |
740 | | |
741 | | void IWORKTable::draw(const librevenge::RVNGPropertyList &tableProps, IWORKOutputElements &elements, bool drawAsSimpleTable) |
742 | 112 | { |
743 | 112 | assert(!m_recorder); |
744 | | |
745 | 112 | librevenge::RVNGPropertyList allTableProps(tableProps); |
746 | 112 | if (m_name) |
747 | 110 | allTableProps.insert("librevenge:sheet-name", get(m_name).c_str()); |
748 | | |
749 | 112 | librevenge::RVNGPropertyListVector columnSizes; |
750 | 560 | for (IWORKColumnSizes_t::const_iterator it = m_columnSizes.begin(); m_columnSizes.end() != it; ++it) |
751 | 448 | { |
752 | 448 | librevenge::RVNGPropertyList column; |
753 | 448 | if (!it->m_size) |
754 | 141 | ; |
755 | 307 | else if (it->m_exactSize) |
756 | 307 | column.insert("style:column-width", pt2in(get(it->m_size))); |
757 | 0 | else |
758 | 0 | column.insert("style:min-column-width", pt2in(get(it->m_size))); |
759 | 448 | columnSizes.append(column); |
760 | 448 | } |
761 | | |
762 | 112 | allTableProps.insert(drawAsSimpleTable ? "librevenge:table-columns" : "librevenge:columns", columnSizes); |
763 | | |
764 | 112 | elements.addOpenTable(allTableProps); |
765 | 112 | unsigned numColumns=unsigned(m_columnSizes.size()); |
766 | 112 | std::set<unsigned> colSet; |
767 | 112 | if (drawAsSimpleTable) |
768 | 112 | { |
769 | | // repeat does not work correctly in table, so draw always each cell |
770 | 560 | for (unsigned col=0; col<numColumns; ++col) |
771 | 448 | colSet.insert(col); |
772 | 112 | } |
773 | 832 | for (std::size_t r = 0; m_table.size() != r; ++r) |
774 | 720 | { |
775 | 720 | const Row_t &row = m_table[r]; |
776 | | |
777 | 720 | librevenge::RVNGPropertyList rowProps; |
778 | 720 | auto const &rSize=m_rowSizes[r]; |
779 | 720 | if (rSize.m_size && rSize.m_exactSize) |
780 | 717 | rowProps.insert("style:row-height", pt2in(get(rSize.m_size))); |
781 | 3 | else if (rSize.m_size) |
782 | 3 | rowProps.insert("style:min-row-height", pt2in(get(rSize.m_size))); |
783 | 720 | if (r < m_headerRows) |
784 | 109 | rowProps.insert("librevenge:is-header-row", true); |
785 | | |
786 | 720 | elements.addOpenTableRow(rowProps); |
787 | | |
788 | 720 | if (!drawAsSimpleTable) |
789 | 0 | { |
790 | | // first compute the list of column that we will need to display |
791 | 0 | colSet.clear(); |
792 | 0 | colSet.insert(0); |
793 | 0 | for (auto const &cIt : row) // cells |
794 | 0 | { |
795 | 0 | colSet.insert(cIt.first); |
796 | 0 | colSet.insert(cIt.first+1); |
797 | 0 | } |
798 | 0 | for (auto const &vIt : m_verticalLines) // vertical lines |
799 | 0 | { |
800 | 0 | colSet.insert(vIt.first); |
801 | 0 | colSet.insert(vIt.first+1); |
802 | 0 | } |
803 | 0 | for (auto const &vIt : m_verticalRightLines) |
804 | 0 | { |
805 | 0 | colSet.insert(vIt.first); |
806 | 0 | colSet.insert(vIt.first+1); |
807 | 0 | } |
808 | 0 | if (bool(m_defaultCellStyles[CELL_TYPE_COLUMN_HEADER]) || |
809 | 0 | bool(m_defaultLayoutStyles[CELL_TYPE_COLUMN_HEADER]) || |
810 | 0 | bool(m_defaultParaStyles[CELL_TYPE_COLUMN_HEADER])) // default style |
811 | 0 | colSet.insert(m_headerColumns); |
812 | 0 | auto commentIt=m_commentMap.lower_bound(std::make_pair(r,0)); |
813 | 0 | while (commentIt!=m_commentMap.end() && commentIt->first.first==r) // comments |
814 | 0 | { |
815 | 0 | colSet.insert(commentIt->first.second); |
816 | 0 | colSet.insert(commentIt->first.second+1); |
817 | 0 | ++commentIt; |
818 | 0 | } |
819 | 0 | } |
820 | 720 | Cell const emptyCell; |
821 | 3.60k | for (auto colIt=colSet.begin(); colIt!=colSet.end();) |
822 | 2.88k | { |
823 | 2.88k | unsigned col=*(colIt++); |
824 | 2.88k | if (col>=numColumns) |
825 | 0 | break; |
826 | 2.88k | auto const &cIt=row.find(col); |
827 | 2.88k | const Cell &cell = cIt==row.end() ? emptyCell : cIt->second; |
828 | 2.88k | librevenge::RVNGPropertyList cellProps; |
829 | 2.88k | cellProps.insert("librevenge:column", numeric_cast<int>(col)); |
830 | 2.88k | cellProps.insert("librevenge:row", numeric_cast<int>(r)); |
831 | 2.88k | unsigned numRepeat=colIt!=colSet.end() ? *colIt-col : numColumns-col; |
832 | 2.88k | if (numRepeat>1) |
833 | 0 | cellProps.insert("table:number-columns-repeated", numeric_cast<int>(numRepeat)); |
834 | | |
835 | 2.88k | using namespace property; |
836 | 2.88k | unsigned const rMax= unsigned(r+ std::max(unsigned(1),cell.m_rowSpan)); |
837 | 2.88k | unsigned const cMax= unsigned(col+std::max(unsigned(1),cell.m_columnSpan)); |
838 | 2.88k | if (m_horizontalLines.find(unsigned(r))!=m_horizontalLines.end()) |
839 | 316 | writeBorder(cellProps, "fo:border-top", m_horizontalLines.find(unsigned(r))->second, col); |
840 | 2.88k | if (!m_horizontalBottomLines.empty()) |
841 | 1.44k | { |
842 | 1.44k | if (m_horizontalBottomLines.find(rMax-1)!=m_horizontalBottomLines.end()) |
843 | 160 | writeBorder(cellProps, "fo:border-bottom", m_horizontalBottomLines.find(rMax-1)->second, col); |
844 | 1.44k | } |
845 | 1.44k | else if (m_horizontalLines.find(rMax)!=m_horizontalLines.end()) |
846 | 0 | writeBorder(cellProps, "fo:border-bottom", m_horizontalLines.find(rMax)->second, col); |
847 | 2.88k | if (m_verticalLines.find(col)!=m_verticalLines.end()) |
848 | 355 | writeBorder(cellProps, "fo:border-left", m_verticalLines.find(col)->second, unsigned(r)); |
849 | 2.88k | if (!m_verticalRightLines.empty()) |
850 | 1.42k | { |
851 | 1.42k | if (m_verticalRightLines.find(cMax-1)!=m_verticalRightLines.end()) |
852 | 355 | writeBorder(cellProps, "fo:border-right", m_verticalRightLines.find(cMax-1)->second, unsigned(r)); |
853 | 1.42k | } |
854 | 1.46k | else if (m_verticalLines.find(cMax)!=m_verticalLines.end()) |
855 | 5 | writeBorder(cellProps, "fo:border-right", m_verticalLines.find(cMax)->second, unsigned(r)); |
856 | | |
857 | 2.88k | if (cell.m_covered) |
858 | 0 | { |
859 | 0 | elements.addInsertCoveredTableCell(cellProps); |
860 | 0 | } |
861 | 2.88k | else |
862 | 2.88k | { |
863 | 2.88k | if (1 < cell.m_columnSpan) |
864 | 0 | cellProps.insert("table:number-columns-spanned", numeric_cast<int>(cell.m_columnSpan)); |
865 | 2.88k | if (1 < cell.m_rowSpan) |
866 | 0 | cellProps.insert("table:number-rows-spanned", numeric_cast<int>(cell.m_rowSpan)); |
867 | | |
868 | 2.88k | IWORKStyleStack style; |
869 | 2.88k | style.push(getDefaultCellStyle(col, unsigned(r))); |
870 | 2.88k | style.push(cell.m_style); |
871 | 2.88k | if (!drawAsSimpleTable) |
872 | 0 | { |
873 | 0 | optional<std::string> valueType; |
874 | 0 | auto formatName=writeFormat(elements, cell.m_style, cell.m_type, valueType); |
875 | 0 | if (formatName) cellProps.insert("librevenge:numbering-name", get(formatName).c_str()); |
876 | | // do not add a 0 value if the cell is empty |
877 | 0 | if (cell.m_type==IWORK_CELL_TYPE_NUMBER && !bool(cell.m_value)) |
878 | 0 | valueType.reset(); |
879 | 0 | writeCellValue(cellProps, cell.m_style ? cell.m_style->getIdent() : none, |
880 | 0 | cell.m_type, valueType, cell.m_value, cell.m_dateTime); |
881 | 0 | } |
882 | 2.88k | writeCellStyle(cellProps, style); |
883 | | |
884 | 2.88k | IWORKStyleStack pStyle; |
885 | 2.88k | pStyle.push(getDefaultParagraphStyle(col,unsigned(r))); |
886 | 2.88k | if (style.has<SFTCellStylePropertyParagraphStyle>()) |
887 | 0 | pStyle.push(style.get<SFTCellStylePropertyParagraphStyle>()); |
888 | 2.88k | IWORKText::fillCharPropList(pStyle, m_langManager, cellProps); |
889 | | |
890 | 2.88k | if (!drawAsSimpleTable && cell.m_formula) |
891 | 0 | elements.addOpenFormulaCell(cellProps, *cell.m_formula, cell.m_formulaHC, m_tableNameMap); |
892 | 2.88k | else |
893 | 2.88k | elements.addOpenTableCell(cellProps); |
894 | | |
895 | 2.88k | if (!drawAsSimpleTable && style.has<property::Fill>()) |
896 | 0 | { |
897 | | // look for a picture in a cell |
898 | | // FIXME: we must do the same for basic table, but the code |
899 | | // must be different in odp(no frame) and in odt(frame ok) |
900 | 0 | try |
901 | 0 | { |
902 | 0 | auto const &media=boost::get<IWORKMediaContent>(style.get<property::Fill>()); |
903 | 0 | if (media.m_data && media.m_data->m_stream) |
904 | 0 | { |
905 | 0 | auto input=media.m_data->m_stream; |
906 | 0 | string mimetype(media.m_data->m_mimeType); |
907 | 0 | if (mimetype.empty()) |
908 | 0 | mimetype = detectMimetype(input); |
909 | 0 | if (!mimetype.empty()) |
910 | 0 | { |
911 | 0 | input->seek(0, librevenge::RVNG_SEEK_END); |
912 | 0 | const auto size = (unsigned long) input->tell(); |
913 | 0 | input->seek(0, librevenge::RVNG_SEEK_SET); |
914 | |
|
915 | 0 | unsigned long readBytes = 0; |
916 | 0 | const unsigned char *const bytes = input->read(size, readBytes); |
917 | 0 | if (readBytes != size) |
918 | 0 | throw GenericException(); |
919 | | |
920 | 0 | librevenge::RVNGPropertyList frameProps; |
921 | 0 | for (int wh=0; wh<2; ++wh) |
922 | 0 | { |
923 | 0 | double dim=0; |
924 | 0 | bool ok=true; |
925 | 0 | auto const &sizes=wh==0 ? m_columnSizes : m_rowSizes; |
926 | 0 | for (size_t rr=(wh==0 ? col : r); ok && rr<std::min(size_t(wh==0 ? cMax : rMax),sizes.size()); ++rr) |
927 | 0 | { |
928 | 0 | if (sizes[rr].m_size && *sizes[rr].m_size>=0) |
929 | 0 | dim+=*sizes[rr].m_size; |
930 | 0 | else |
931 | 0 | ok=false; |
932 | 0 | } |
933 | 0 | if (ok) |
934 | 0 | frameProps.insert(wh==0 ? "svg:width" : "svg:height", pt2in(dim)); |
935 | 0 | } |
936 | 0 | unsigned col2=cMax; |
937 | 0 | std::string column(1, char(col2%26+'A')); |
938 | 0 | col2 /= 26; |
939 | 0 | while (col2>0) |
940 | 0 | { |
941 | 0 | --col2; |
942 | 0 | column.insert(0, std::string(1,char(col2%26+'A'))); |
943 | 0 | col2 /= 26; |
944 | 0 | } |
945 | 0 | librevenge::RVNGString endCellName; |
946 | 0 | endCellName.sprintf("%s%d",column.c_str(), int(rMax)); |
947 | 0 | frameProps.insert("table:end-cell-address", endCellName); |
948 | 0 | frameProps.insert("table:table-background", true); |
949 | 0 | elements.addOpenFrame(frameProps); |
950 | 0 | librevenge::RVNGPropertyList imageProps; |
951 | 0 | imageProps.insert("librevenge:mime-type", mimetype.c_str()); |
952 | 0 | imageProps.insert("office:binary-data", librevenge::RVNGBinaryData(bytes, size)); |
953 | 0 | elements.addInsertBinaryObject(imageProps); |
954 | 0 | elements.addCloseFrame(); |
955 | 0 | } |
956 | 0 | else |
957 | 0 | { |
958 | 0 | ETONYEK_DEBUG_MSG(("IWORKTable::draw: can not find mimetype for some image\n")); |
959 | 0 | } |
960 | 0 | } |
961 | 0 | } |
962 | 0 | catch (...) |
963 | 0 | { |
964 | 0 | } |
965 | 0 | } |
966 | | |
967 | 2.88k | if (!cell.m_content.empty() && cell.m_type!=IWORK_CELL_TYPE_DATE_TIME && cell.m_type!=IWORK_CELL_TYPE_DURATION) |
968 | 38 | elements.append(cell.m_content); |
969 | 2.84k | else if (drawAsSimpleTable) |
970 | 2.84k | { |
971 | 2.84k | librevenge::RVNGString value=convertCellValueInText(style, cell.m_type, cell.m_value, cell.m_dateTime); |
972 | 2.84k | if (!value.empty()) |
973 | 3 | { |
974 | 3 | librevenge::RVNGPropertyList const empty; |
975 | 3 | elements.addOpenParagraph(empty); |
976 | 3 | elements.addOpenSpan(empty); |
977 | 3 | elements.addInsertText(value); |
978 | 3 | elements.addCloseSpan(); |
979 | 3 | elements.addCloseParagraph(); |
980 | 3 | } |
981 | 2.84k | } |
982 | 2.88k | auto nIt=m_commentMap.find(std::make_pair(r,col)); |
983 | 2.88k | if (nIt!=m_commentMap.end()) |
984 | 0 | { |
985 | 0 | elements.addOpenComment(librevenge::RVNGPropertyList()); |
986 | 0 | elements.append(nIt->second); |
987 | 0 | elements.addCloseComment(); |
988 | 0 | } |
989 | 2.88k | elements.addCloseTableCell(); |
990 | 2.88k | } |
991 | 2.88k | } |
992 | 720 | elements.addCloseTableRow(); |
993 | 720 | } |
994 | 112 | elements.addCloseTable(); |
995 | 112 | } |
996 | | |
997 | | void IWORKTable::setDefaultCellStyle(const CellType type, const IWORKStylePtr_t &style) |
998 | 509 | { |
999 | 509 | if (bool(m_recorder)) |
1000 | 0 | { |
1001 | 0 | m_recorder->setDefaultCellStyle(type, style); |
1002 | 0 | return; |
1003 | 0 | } |
1004 | | |
1005 | 509 | assert(type < ETONYEK_NUM_ELEMENTS(m_defaultCellStyles)); |
1006 | 509 | m_defaultCellStyles[type] = style; |
1007 | 509 | } |
1008 | | |
1009 | | void IWORKTable::setDefaultLayoutStyle(const CellType type, const IWORKStylePtr_t &style) |
1010 | 0 | { |
1011 | 0 | if (bool(m_recorder)) |
1012 | 0 | { |
1013 | 0 | m_recorder->setDefaultLayoutStyle(type, style); |
1014 | 0 | return; |
1015 | 0 | } |
1016 | | |
1017 | 0 | assert(type < ETONYEK_NUM_ELEMENTS(m_defaultLayoutStyles)); |
1018 | 0 | m_defaultLayoutStyles[type] = style; |
1019 | 0 | } |
1020 | | |
1021 | | void IWORKTable::setDefaultParagraphStyle(const CellType type, const IWORKStylePtr_t &style) |
1022 | 452 | { |
1023 | 452 | if (bool(m_recorder)) |
1024 | 0 | { |
1025 | 0 | m_recorder->setDefaultParagraphStyle(type, style); |
1026 | 0 | return; |
1027 | 0 | } |
1028 | | |
1029 | 452 | assert(type < ETONYEK_NUM_ELEMENTS(m_defaultParaStyles)); |
1030 | 452 | m_defaultParaStyles[type] = style; |
1031 | 452 | } |
1032 | | |
1033 | | boost::optional<int> IWORKTable::getOrder() const |
1034 | 37 | { |
1035 | 37 | return m_order; |
1036 | 37 | } |
1037 | | |
1038 | | IWORKStylePtr_t IWORKTable::getStyle() const |
1039 | 149 | { |
1040 | 149 | return m_style; |
1041 | 149 | } |
1042 | | |
1043 | | IWORKStylePtr_t IWORKTable::getDefaultCellStyle(unsigned column, unsigned row) const |
1044 | 2.91k | { |
1045 | 2.91k | return getDefaultStyle(column, row, m_defaultCellStyles); |
1046 | 2.91k | } |
1047 | | |
1048 | | IWORKStylePtr_t IWORKTable::getDefaultLayoutStyle(unsigned column, unsigned row) const |
1049 | 79 | { |
1050 | 79 | return getDefaultStyle(column, row, m_defaultLayoutStyles); |
1051 | 79 | } |
1052 | | |
1053 | | IWORKStylePtr_t IWORKTable::getDefaultParagraphStyle(unsigned column, unsigned row) const |
1054 | 2.95k | { |
1055 | 2.95k | return getDefaultStyle(column, row, m_defaultParaStyles); |
1056 | 2.95k | } |
1057 | | |
1058 | | IWORKStylePtr_t IWORKTable::getDefaultStyle(const unsigned column, const unsigned row, const IWORKStylePtr_t *const group) const |
1059 | 5.95k | { |
1060 | 5.95k | if ((row < m_headerRows) && bool(group[CELL_TYPE_ROW_HEADER])) |
1061 | 395 | return group[CELL_TYPE_ROW_HEADER]; |
1062 | 5.56k | else if (m_footerRows>0 && ((m_rows - row) <= m_footerRows) && bool(group[CELL_TYPE_ROW_FOOTER])) |
1063 | 0 | return group[CELL_TYPE_ROW_FOOTER]; |
1064 | 5.56k | else if ((column < m_headerColumns) && bool(group[CELL_TYPE_COLUMN_HEADER])) |
1065 | 567 | return group[CELL_TYPE_COLUMN_HEADER]; |
1066 | 4.99k | else if (m_bandedRows && ((row-m_headerRows) % 2 == 1) && bool(group[CELL_TYPE_ALTERNATE_BODY])) |
1067 | 240 | return group[CELL_TYPE_ALTERNATE_BODY]; |
1068 | 4.75k | else |
1069 | 4.75k | return group[CELL_TYPE_BODY]; |
1070 | 5.95k | } |
1071 | | |
1072 | | } |
1073 | | |
1074 | | /* vim:set shiftwidth=2 softtabstop=2 expandtab: */ |