/src/libmwaw/src/lib/MWAWCell.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | /** \file MWAWCell.cxx |
35 | | * Implements MWAWCell (cell content and format) |
36 | | */ |
37 | | #include <time.h> |
38 | | |
39 | | #include <cmath> |
40 | | #include <iomanip> |
41 | | #include <iostream> |
42 | | #include <sstream> |
43 | | |
44 | | #include <librevenge/librevenge.h> |
45 | | |
46 | | #include "MWAWFontConverter.hxx" |
47 | | #include "MWAWListener.hxx" |
48 | | |
49 | | #include "MWAWCell.hxx" |
50 | | |
51 | | //////////////////////////////////////////////////////////// |
52 | | // MWAWCell::Format |
53 | | //////////////////////////////////////////////////////////// |
54 | | MWAWCell::Format::~Format() |
55 | 439M | { |
56 | 439M | } |
57 | | |
58 | | std::string MWAWCell::Format::getValueType() const |
59 | 4.78M | { |
60 | 4.78M | switch (m_format) { |
61 | 4.39M | case F_NUMBER: |
62 | 4.39M | if (m_numberFormat==F_NUMBER_CURRENCY) return "currency"; |
63 | 3.91M | if (m_numberFormat==F_NUMBER_PERCENT) return "percent"; |
64 | 3.70M | if (m_numberFormat==F_NUMBER_SCIENTIFIC) return "scientific"; |
65 | 3.31M | return "float"; |
66 | 0 | case F_BOOLEAN: |
67 | 0 | return "boolean"; |
68 | 0 | case F_DATE: |
69 | 0 | return "date"; |
70 | 0 | case F_TIME: |
71 | 0 | return "time"; |
72 | 6.22k | case F_TEXT: |
73 | 390k | case F_UNKNOWN: |
74 | | #if !defined(__clang__) |
75 | | default: |
76 | | #endif |
77 | 390k | break; |
78 | 4.78M | } |
79 | 390k | return "float"; |
80 | 4.78M | } |
81 | | |
82 | | bool MWAWCell::Format::getNumberingProperties(librevenge::RVNGPropertyList &propList) const |
83 | 1.28M | { |
84 | 1.28M | librevenge::RVNGPropertyListVector pVect; |
85 | 1.28M | switch (m_format) { |
86 | 23.4k | case F_BOOLEAN: |
87 | 23.4k | propList.insert("librevenge:value-type", "boolean"); |
88 | 23.4k | break; |
89 | 729k | case F_NUMBER: |
90 | 729k | if (m_digits>-1000) |
91 | 635k | propList.insert("number:decimal-places", m_digits); |
92 | 729k | if (m_thousandHasSeparator) |
93 | 9.84k | propList.insert("number:grouping", true); |
94 | 729k | switch (m_numberFormat) { |
95 | 274k | case F_NUMBER_GENERIC: |
96 | 274k | propList.insert("librevenge:value-type", "number"); |
97 | 274k | propList.remove("number:decimal-places"); |
98 | 274k | break; |
99 | 88.8k | case F_NUMBER_SCIENTIFIC: |
100 | 88.8k | propList.insert("librevenge:value-type", "scientific"); |
101 | 88.8k | break; |
102 | 91.5k | case F_NUMBER_PERCENT: |
103 | 91.5k | propList.insert("librevenge:value-type", "percentage"); |
104 | 91.5k | break; |
105 | 99.3k | case F_NUMBER_DECIMAL: |
106 | 99.3k | propList.insert("librevenge:value-type", "number"); |
107 | 99.3k | if (m_integerDigits>=0) { |
108 | 0 | propList.insert("number:min-integer-digits", m_integerDigits+1); |
109 | 0 | propList.insert("number:decimal-places", 0); |
110 | 0 | } |
111 | 99.3k | break; |
112 | 306 | case F_NUMBER_FRACTION: |
113 | 306 | propList.insert("librevenge:value-type", "fraction"); |
114 | 306 | propList.insert("number:min-integer-digits", 0); |
115 | 306 | propList.insert("number:min-numerator-digits", m_numeratorDigits>0 ? m_numeratorDigits : 1); |
116 | 306 | propList.insert("number:min-denominator-digits", m_denominatorDigits>0 ? m_denominatorDigits : 1); |
117 | 306 | propList.remove("number:decimal-places"); |
118 | 306 | break; |
119 | 87.1k | case F_NUMBER_CURRENCY: { |
120 | 87.1k | propList.clear(); |
121 | 87.1k | propList.insert("librevenge:value-type", "currency"); |
122 | 87.1k | librevenge::RVNGPropertyList list; |
123 | 87.1k | list.insert("librevenge:value-type", "currency-symbol"); |
124 | 87.1k | list.insert("number:language","en"); |
125 | 87.1k | list.insert("number:country","US"); |
126 | 87.1k | list.insert("librevenge:currency",m_currencySymbol.c_str()); |
127 | 87.1k | pVect.append(list); |
128 | | |
129 | 87.1k | list.clear(); |
130 | 87.1k | list.insert("librevenge:value-type", "number"); |
131 | 87.1k | if (m_digits>-1000) |
132 | 86.4k | list.insert("number:decimal-places", m_digits); |
133 | 87.1k | pVect.append(list); |
134 | 87.1k | break; |
135 | 0 | } |
136 | 88.2k | case F_NUMBER_UNKNOWN: |
137 | | #if !defined(__clang__) |
138 | | default: |
139 | | #endif |
140 | 88.2k | return false; |
141 | 729k | } |
142 | 641k | break; |
143 | 641k | case F_DATE: |
144 | 270k | propList.insert("librevenge:value-type", "date"); |
145 | 270k | propList.insert("number:automatic-order", "true"); |
146 | 270k | if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%m/%d/%Y" : m_DTFormat, pVect)) |
147 | 0 | return false; |
148 | 270k | break; |
149 | 270k | case F_TIME: |
150 | 263k | propList.insert("librevenge:value-type", "time"); |
151 | 263k | propList.insert("number:automatic-order", "true"); |
152 | 263k | if (!libmwaw::convertDTFormat(m_DTFormat.empty() ? "%H:%M:%S" : m_DTFormat, pVect)) |
153 | 0 | return false; |
154 | 263k | break; |
155 | 263k | case F_TEXT: |
156 | 0 | case F_UNKNOWN: |
157 | | #if !defined(__clang__) |
158 | | default: |
159 | | #endif |
160 | 0 | return false; |
161 | 1.28M | } |
162 | 1.19M | if (pVect.count()) |
163 | 620k | propList.insert("librevenge:format", pVect); |
164 | 1.19M | return true; |
165 | 1.28M | } |
166 | | |
167 | | std::ostream &operator<<(std::ostream &o, MWAWCell::Format const &format) |
168 | 0 | { |
169 | 0 | switch (format.m_format) { |
170 | 0 | case MWAWCell::F_BOOLEAN: |
171 | 0 | o << "boolean"; |
172 | 0 | break; |
173 | 0 | case MWAWCell::F_TEXT: |
174 | 0 | o << "text"; |
175 | 0 | break; |
176 | 0 | case MWAWCell::F_NUMBER: |
177 | 0 | o << "number"; |
178 | 0 | switch (format.m_numberFormat) { |
179 | 0 | case MWAWCell::F_NUMBER_GENERIC: |
180 | 0 | break; |
181 | 0 | case MWAWCell::F_NUMBER_DECIMAL: |
182 | 0 | o << "[decimal]"; |
183 | 0 | break; |
184 | 0 | case MWAWCell::F_NUMBER_SCIENTIFIC: |
185 | 0 | o << "[exp]"; |
186 | 0 | break; |
187 | 0 | case MWAWCell::F_NUMBER_PERCENT: |
188 | 0 | o << "[percent]"; |
189 | 0 | break; |
190 | 0 | case MWAWCell::F_NUMBER_CURRENCY: |
191 | 0 | o << "[money=" << format.m_currencySymbol << "]"; |
192 | 0 | break; |
193 | 0 | case MWAWCell::F_NUMBER_FRACTION: |
194 | 0 | o << "[fraction]"; |
195 | 0 | break; |
196 | 0 | case MWAWCell::F_NUMBER_UNKNOWN: |
197 | | #if !defined(__clang__) |
198 | | default: |
199 | | #endif |
200 | 0 | MWAW_DEBUG_MSG(("MWAWCell::operator<<(Format): find unexpected type\n")); |
201 | 0 | o << "###format,"; |
202 | 0 | break; |
203 | 0 | } |
204 | 0 | if (format.m_thousandHasSeparator) |
205 | 0 | o << "[thousandSep]"; |
206 | 0 | if (format.m_parenthesesForNegative) |
207 | 0 | o << "[parenthesis<0]"; |
208 | 0 | break; |
209 | 0 | case MWAWCell::F_DATE: |
210 | 0 | o << "date[" << format.m_DTFormat << "]"; |
211 | 0 | break; |
212 | 0 | case MWAWCell::F_TIME: |
213 | 0 | o << "time[" << format.m_DTFormat << "]"; |
214 | 0 | break; |
215 | 0 | case MWAWCell::F_UNKNOWN: |
216 | | #if !defined(__clang__) |
217 | | default: |
218 | | #endif |
219 | 0 | break; // default |
220 | 0 | } |
221 | 0 | o << ","; |
222 | |
|
223 | 0 | if (format.m_digits > -1000) o << "digits=" << format.m_digits << ","; |
224 | 0 | if (format.m_integerDigits != -1) o << "digits[min]=" << format.m_integerDigits << ","; |
225 | 0 | if (format.m_numeratorDigits != -1) o << "digits[num]=" << format.m_numeratorDigits << ","; |
226 | 0 | if (format.m_denominatorDigits != -1) o << "digits[den]=" << format.m_denominatorDigits << ","; |
227 | 0 | return o; |
228 | 0 | } |
229 | | |
230 | | int MWAWCell::Format::compare(MWAWCell::Format const &cell) const |
231 | 82.4M | { |
232 | 82.4M | if (m_format<cell.m_format) return 1; |
233 | 76.5M | if (m_format>cell.m_format) return -1; |
234 | 65.7M | if (m_numberFormat<cell.m_numberFormat) return 1; |
235 | 60.3M | if (m_numberFormat>cell.m_numberFormat) return -1; |
236 | 47.0M | if (m_digits<cell.m_digits) return 1; |
237 | 43.3M | if (m_digits>cell.m_digits) return -1; |
238 | 36.6M | if (m_integerDigits<cell.m_integerDigits) return 1; |
239 | 36.6M | if (m_integerDigits>cell.m_integerDigits) return -1; |
240 | 36.6M | if (m_numeratorDigits<cell.m_numeratorDigits) return 1; |
241 | 36.6M | if (m_numeratorDigits>cell.m_numeratorDigits) return -1; |
242 | 36.6M | if (m_denominatorDigits<cell.m_denominatorDigits) return 1; |
243 | 36.6M | if (m_denominatorDigits>cell.m_denominatorDigits) return -1; |
244 | 36.6M | if (m_thousandHasSeparator!=cell.m_thousandHasSeparator) return m_thousandHasSeparator ? -1:1; |
245 | 36.5M | if (m_parenthesesForNegative!=cell.m_parenthesesForNegative) return m_parenthesesForNegative ? -1:1; |
246 | 36.5M | if (m_DTFormat<cell.m_DTFormat) return 1; |
247 | 36.2M | if (m_DTFormat>cell.m_DTFormat) return -1; |
248 | 35.6M | if (m_currencySymbol<cell.m_currencySymbol) return 1; |
249 | 35.6M | if (m_currencySymbol>cell.m_currencySymbol) return -1; |
250 | 35.6M | return 0; |
251 | 35.6M | } |
252 | | //////////////////////////////////////////////////////////// |
253 | | // MWAWCell |
254 | | //////////////////////////////////////////////////////////// |
255 | | void MWAWCell::addTo(librevenge::RVNGPropertyList &propList, std::shared_ptr<MWAWFontConverter> fontConverter) const |
256 | 19.2M | { |
257 | 19.2M | propList.insert("librevenge:column", position()[0]); |
258 | 19.2M | propList.insert("librevenge:row", position()[1]); |
259 | | |
260 | 19.2M | propList.insert("table:number-columns-spanned", numSpannedCells()[0]); |
261 | 19.2M | propList.insert("table:number-rows-spanned", numSpannedCells()[1]); |
262 | | |
263 | 19.2M | if (m_fontSet) |
264 | 11.6M | m_font.addTo(propList, fontConverter); |
265 | 25.8M | for (size_t c = 0; c < m_bordersList.size(); c++) { |
266 | 6.62M | switch (c) { |
267 | 1.65M | case libmwaw::Left: |
268 | 1.65M | m_bordersList[c].addTo(propList, "left"); |
269 | 1.65M | break; |
270 | 1.65M | case libmwaw::Right: |
271 | 1.65M | m_bordersList[c].addTo(propList, "right"); |
272 | 1.65M | break; |
273 | 1.65M | case libmwaw::Top: |
274 | 1.65M | m_bordersList[c].addTo(propList, "top"); |
275 | 1.65M | break; |
276 | 1.65M | case libmwaw::Bottom: |
277 | 1.65M | m_bordersList[c].addTo(propList, "bottom"); |
278 | 1.65M | break; |
279 | 0 | default: |
280 | 0 | MWAW_DEBUG_MSG(("MWAWCell::addTo: can not send %d border\n",int(c))); |
281 | 0 | break; |
282 | 6.62M | } |
283 | 6.62M | } |
284 | 19.2M | if (!backgroundColor().isWhite()) |
285 | 119k | propList.insert("fo:background-color", backgroundColor().str().c_str()); |
286 | 19.2M | if (isProtected()) |
287 | 212k | propList.insert("style:cell-protect","protected"); |
288 | | // alignment |
289 | 19.2M | switch (hAlignment()) { |
290 | 1.01M | case HALIGN_LEFT: |
291 | 1.01M | propList.insert("fo:text-align", "first"); |
292 | 1.01M | propList.insert("style:text-align-source", "fix"); |
293 | 1.01M | break; |
294 | 417k | case HALIGN_CENTER: |
295 | 417k | propList.insert("fo:text-align", "center"); |
296 | 417k | propList.insert("style:text-align-source", "fix"); |
297 | 417k | break; |
298 | 645k | case HALIGN_RIGHT: |
299 | 645k | propList.insert("fo:text-align", "end"); |
300 | 645k | propList.insert("style:text-align-source", "fix"); |
301 | 645k | break; |
302 | 17.1M | case HALIGN_DEFAULT: |
303 | 17.1M | break; // default |
304 | 0 | case HALIGN_FULL: |
305 | | #if !defined(__clang__) |
306 | | default: |
307 | | #endif |
308 | 0 | MWAW_DEBUG_MSG(("MWAWCell::addTo: called with unknown halign=%d\n", hAlignment())); |
309 | 19.2M | } |
310 | | // no padding |
311 | 19.2M | propList.insert("fo:padding", 0, librevenge::RVNG_POINT); |
312 | | // alignment |
313 | 19.2M | switch (vAlignment()) { |
314 | 0 | case VALIGN_TOP: |
315 | 0 | propList.insert("style:vertical-align", "top"); |
316 | 0 | break; |
317 | 251k | case VALIGN_CENTER: |
318 | 251k | propList.insert("style:vertical-align", "middle"); |
319 | 251k | break; |
320 | 5.32M | case VALIGN_BOTTOM: |
321 | 5.32M | propList.insert("style:vertical-align", "bottom"); |
322 | 5.32M | break; |
323 | 13.6M | case VALIGN_DEFAULT: |
324 | 13.6M | break; // default |
325 | | #if !defined(__clang__) |
326 | | default: |
327 | | #endif |
328 | 0 | MWAW_DEBUG_MSG(("MWAWCell::addTo: called with unknown valign=%d\n", vAlignment())); |
329 | 19.2M | } |
330 | 19.2M | int rot=int(m_rotation); // int seems better than double |
331 | 19.2M | if (rot) |
332 | 2.72k | propList.insert("style:rotation-angle", rot); |
333 | 19.2M | } |
334 | | |
335 | | std::string MWAWCell::getColumnName(int col) |
336 | 0 | { |
337 | 0 | std::stringstream f; |
338 | 0 | f << "[."; |
339 | 0 | if (col > 26) f << char('A'+col/26); |
340 | 0 | f << char('A'+(col%26)); |
341 | 0 | f << "]"; |
342 | 0 | return f.str(); |
343 | 0 | } |
344 | | |
345 | | std::string MWAWCell::getBasicCellName(MWAWVec2i const &pos) |
346 | 2.11k | { |
347 | 2.11k | std::stringstream f; |
348 | 2.11k | int col = pos[0]; |
349 | 2.11k | if (col > 26*26) { |
350 | 0 | f << char('A'+col/(26*26)); |
351 | 0 | col *= 26*26; |
352 | 0 | } |
353 | 2.11k | if (col > 26) { |
354 | 0 | f << char('A'+col/26); |
355 | 0 | col %= 26; |
356 | 0 | } |
357 | 2.11k | f << char('A'+col); |
358 | 2.11k | f << pos[1]+1; |
359 | 2.11k | return f.str(); |
360 | 2.11k | } |
361 | | |
362 | | std::string MWAWCell::getCellName(MWAWVec2i const &pos, MWAWVec2b const &absolute) |
363 | 0 | { |
364 | 0 | std::stringstream f; |
365 | 0 | f << "[."; |
366 | 0 | if (absolute[1]) f << "$"; |
367 | 0 | int col = pos[0]; |
368 | 0 | if (col > 26*26) { |
369 | 0 | f << char('A'+col/(26*26)); |
370 | 0 | col *= 26*26; |
371 | 0 | } |
372 | 0 | if (col > 26) { |
373 | 0 | f << char('A'+col/26); |
374 | 0 | col %= 26; |
375 | 0 | } |
376 | 0 | f << char('A'+col); |
377 | 0 | if (absolute[0]) f << "$"; |
378 | 0 | f << pos[1]+1 << ']'; |
379 | 0 | return f.str(); |
380 | 0 | } |
381 | | |
382 | | void MWAWCell::setBorders(int wh, MWAWBorder const &border) |
383 | 4.91M | { |
384 | 4.91M | int const allBits = libmwaw::LeftBit|libmwaw::RightBit|libmwaw::TopBit|libmwaw::BottomBit|libmwaw::HMiddleBit|libmwaw::VMiddleBit; |
385 | 4.91M | if (wh & (~allBits)) { |
386 | 0 | MWAW_DEBUG_MSG(("MWAWCell::setBorders: unknown borders\n")); |
387 | 0 | return; |
388 | 0 | } |
389 | 4.91M | size_t numData = 4; |
390 | 4.91M | if (wh & (libmwaw::HMiddleBit|libmwaw::VMiddleBit)) |
391 | 0 | numData=6; |
392 | 4.91M | if (m_bordersList.size() < numData) { |
393 | 4.24M | MWAWBorder emptyBorder; |
394 | 4.24M | emptyBorder.m_style = MWAWBorder::None; |
395 | 4.24M | m_bordersList.resize(numData, emptyBorder); |
396 | 4.24M | } |
397 | 4.91M | if (wh & libmwaw::LeftBit) m_bordersList[libmwaw::Left] = border; |
398 | 4.91M | if (wh & libmwaw::RightBit) m_bordersList[libmwaw::Right] = border; |
399 | 4.91M | if (wh & libmwaw::TopBit) m_bordersList[libmwaw::Top] = border; |
400 | 4.91M | if (wh & libmwaw::BottomBit) m_bordersList[libmwaw::Bottom] = border; |
401 | 4.91M | if (wh & libmwaw::HMiddleBit) m_bordersList[libmwaw::HMiddle] = border; |
402 | 4.91M | if (wh & libmwaw::VMiddleBit) m_bordersList[libmwaw::VMiddle] = border; |
403 | 4.91M | } |
404 | | |
405 | | std::ostream &operator<<(std::ostream &o, MWAWCell const &cell) |
406 | 0 | { |
407 | 0 | o << MWAWCell::getCellName(cell.m_position, MWAWVec2b(false,false)) << ":"; |
408 | 0 | if (cell.numSpannedCells()[0] != 1 || cell.numSpannedCells()[1] != 1) |
409 | 0 | o << "span=[" << cell.numSpannedCells()[0] << "," << cell.numSpannedCells()[1] << "],"; |
410 | |
|
411 | 0 | if (cell.m_protected) o << "protected,"; |
412 | 0 | if (cell.m_bdBox.size()[0]>0 || cell.m_bdBox.size()[1]>0) |
413 | 0 | o << "bdBox=" << cell.m_bdBox << ","; |
414 | 0 | if (cell.m_bdSize[0]>0 || cell.m_bdSize[1]>0) |
415 | 0 | o << "bdSize=" << cell.m_bdSize << ","; |
416 | 0 | o << cell.m_format; |
417 | 0 | if (cell.m_fontSet) o << "hasFont,"; |
418 | 0 | switch (cell.m_hAlign) { |
419 | 0 | case MWAWCell::HALIGN_LEFT: |
420 | 0 | o << "left,"; |
421 | 0 | break; |
422 | 0 | case MWAWCell::HALIGN_CENTER: |
423 | 0 | o << "centered,"; |
424 | 0 | break; |
425 | 0 | case MWAWCell::HALIGN_RIGHT: |
426 | 0 | o << "right,"; |
427 | 0 | break; |
428 | 0 | case MWAWCell::HALIGN_FULL: |
429 | 0 | o << "full,"; |
430 | 0 | break; |
431 | 0 | case MWAWCell::HALIGN_DEFAULT: |
432 | | #if !defined(__clang__) |
433 | | default: |
434 | | #endif |
435 | 0 | break; // default |
436 | 0 | } |
437 | 0 | switch (cell.m_vAlign) { |
438 | 0 | case MWAWCell::VALIGN_TOP: |
439 | 0 | o << "top,"; |
440 | 0 | break; |
441 | 0 | case MWAWCell::VALIGN_CENTER: |
442 | 0 | o << "centered[y],"; |
443 | 0 | break; |
444 | 0 | case MWAWCell::VALIGN_BOTTOM: |
445 | 0 | o << "bottom,"; |
446 | 0 | break; |
447 | 0 | case MWAWCell::VALIGN_DEFAULT: |
448 | | #if !defined(__clang__) |
449 | | default: |
450 | | #endif |
451 | 0 | break; // default |
452 | 0 | } |
453 | | |
454 | 0 | if (!cell.m_backgroundColor.isWhite()) |
455 | 0 | o << "backColor=" << cell.m_backgroundColor << ","; |
456 | 0 | for (size_t i = 0; i < cell.m_bordersList.size(); i++) { |
457 | 0 | if (cell.m_bordersList[i].m_style == MWAWBorder::None) |
458 | 0 | continue; |
459 | 0 | o << "bord"; |
460 | 0 | if (i < 6) { |
461 | 0 | static char const* const wh[] = { "L", "R", "T", "B", "MiddleH", "MiddleV" }; |
462 | 0 | o << wh[i]; |
463 | 0 | } |
464 | 0 | else o << "[#wh=" << i << "]"; |
465 | 0 | o << "=" << cell.m_bordersList[i] << ","; |
466 | 0 | } |
467 | 0 | switch (cell.m_extraLine) { |
468 | 0 | case MWAWCell::E_None: |
469 | 0 | break; |
470 | 0 | case MWAWCell::E_Line1: |
471 | 0 | o << "line[TL->RB],"; |
472 | 0 | break; |
473 | 0 | case MWAWCell::E_Line2: |
474 | 0 | o << "line[BL->RT],"; |
475 | 0 | break; |
476 | 0 | case MWAWCell::E_Cross: |
477 | 0 | o << "line[cross],"; |
478 | 0 | break; |
479 | | #if !defined(__clang__) |
480 | | default: |
481 | | break; |
482 | | #endif |
483 | 0 | } |
484 | 0 | if (cell.m_rotation<0 || cell.m_rotation>0) |
485 | 0 | o << "rot=" << cell.m_rotation << ","; |
486 | 0 | if (cell.m_extraLine!=MWAWCell::E_None) |
487 | 0 | o << cell.m_extraLineType << ","; |
488 | 0 | return o; |
489 | 0 | } |
490 | | |
491 | | // send data to listener |
492 | | bool MWAWCell::send(MWAWListenerPtr listener, MWAWTable &table) |
493 | 729k | { |
494 | 729k | if (!listener) return true; |
495 | 729k | listener->openTableCell(*this); |
496 | 729k | bool ok=sendContent(listener, table); |
497 | 729k | listener->closeTableCell(); |
498 | 729k | return ok; |
499 | 729k | } |
500 | | |
501 | | bool MWAWCell::sendContent(MWAWListenerPtr, MWAWTable &) |
502 | 0 | { |
503 | 0 | MWAW_DEBUG_MSG(("MWAWCell::sendContent: must not be called!!!\n")); |
504 | 0 | return false; |
505 | 0 | } |
506 | | |
507 | | //////////////////////////////////////////////////////////// |
508 | | // MWAWCellContent |
509 | | //////////////////////////////////////////////////////////// |
510 | | bool MWAWCellContent::double2Date(double val, int &Y, int &M, int &D) |
511 | 761k | { |
512 | | /* first convert the date in long*/ |
513 | 761k | auto numDaysSinceOrigin=long(val+0.4); |
514 | | // checkme: do we need to check before for isNan(val) ? |
515 | 761k | if (numDaysSinceOrigin<-10000*365 || numDaysSinceOrigin>10000*365) { |
516 | | /* normally, we can expect documents to contain date between 1904 |
517 | | and 2004. So even if such a date can make sense, storing it as |
518 | | a number of days is clearly abnormal */ |
519 | 194k | MWAW_DEBUG_MSG(("MWAWCellContent::double2Date: using a double to represent the date %ld seems odd\n", numDaysSinceOrigin)); |
520 | 194k | Y=1904; |
521 | 194k | M=D=1; |
522 | 194k | return false; |
523 | 194k | } |
524 | | // find the century |
525 | 567k | int century=19; |
526 | 932k | while (numDaysSinceOrigin>=36500+24) { |
527 | 365k | long numDaysInCentury=36500+24+((century%4)?0:1); |
528 | 365k | if (numDaysSinceOrigin<numDaysInCentury) break; |
529 | 365k | numDaysSinceOrigin-=numDaysInCentury; |
530 | 365k | ++century; |
531 | 365k | } |
532 | 666k | while (numDaysSinceOrigin<0) { |
533 | 99.3k | --century; |
534 | 99.3k | numDaysSinceOrigin+=36500+24+((century%4)?0:1); |
535 | 99.3k | } |
536 | | // now compute the year |
537 | 567k | Y=int(numDaysSinceOrigin/365); |
538 | 567k | long numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0); |
539 | 567k | if (numDaysToEndY1>numDaysSinceOrigin) { |
540 | 14.7k | --Y; |
541 | 14.7k | numDaysToEndY1=Y*365+(Y>0 ? (Y-1)/4+((century%4)?0:1) : 0); |
542 | 14.7k | } |
543 | | // finish to compute the date |
544 | 567k | auto numDaysFrom1Jan=int(numDaysSinceOrigin-numDaysToEndY1); |
545 | 567k | Y+=century*100; |
546 | 567k | bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0); |
547 | | |
548 | 2.38M | for (M=0; M<12; ++M) { |
549 | 2.38M | static const int days[2][12] = { |
550 | 2.38M | { 0,31,59,90,120,151,181,212,243,273,304,334}, |
551 | 2.38M | { 0,31,60,91,121,152,182,213,244,274,305,335} |
552 | 2.38M | }; |
553 | 2.38M | if (M<11 && days[isLeap ? 1 : 0][M+1]<=numDaysFrom1Jan) continue; |
554 | 567k | D=(numDaysFrom1Jan-days[isLeap ? 1 : 0][M++])+1; |
555 | 567k | break; |
556 | 2.38M | } |
557 | 567k | return true; |
558 | 761k | } |
559 | | |
560 | | bool MWAWCellContent::date2Double(int Y, int M, int D, double &val) |
561 | 9.14k | { |
562 | 9.14k | --M; |
563 | 9.14k | --D; |
564 | 9.14k | if (M>11) { |
565 | 2.81k | Y += M/12; |
566 | 2.81k | M %= 12; |
567 | 2.81k | } |
568 | 6.33k | else if (M<0) { |
569 | 1.99k | int yDiff = (-M + 11)/12; |
570 | 1.99k | Y -= yDiff; |
571 | 1.99k | M+=12*yDiff; |
572 | 1.99k | } |
573 | | // sanity check |
574 | 9.14k | if (M<0||M>11) { |
575 | 0 | MWAW_DEBUG_MSG(("MWAWCellContent::date2Double: something is bad\n")); |
576 | 0 | return false; |
577 | 0 | } |
578 | 9.14k | bool isLeap=(Y%4)==0 && ((Y%400)==0 || (Y%100)!=0); |
579 | 9.14k | int32_t const daysFrom0=365*Y+(Y/400)-(Y/100)+(Y/4); |
580 | 9.14k | int32_t const daysFrom1900=365*1900+(1900/400)-(1900/100)+(1900/4); |
581 | 9.14k | static const int32_t days[2][12] = { |
582 | 9.14k | { 0,31,59,90,120,151,181,212,243,273,304,334}, |
583 | 9.14k | { 0,31,60,91,121,152,182,213,244,274,305,335} |
584 | 9.14k | }; |
585 | 9.14k | int32_t daysFrom1Jan=days[isLeap ? 1 : 0][M] + D; |
586 | 9.14k | val=double(daysFrom0-daysFrom1900+daysFrom1Jan); |
587 | 9.14k | return true; |
588 | 9.14k | } |
589 | | |
590 | | bool MWAWCellContent::double2Time(double val, int &H, int &M, int &S) |
591 | 510k | { |
592 | 510k | if (val < 0.0 || val > 1.0) return false; |
593 | 508k | double time = 24.*3600.*val+0.5; |
594 | 508k | H=int(time/3600.); |
595 | 508k | time -= H*3600.; |
596 | 508k | M=int(time/60.); |
597 | 508k | time -= M*60.; |
598 | 508k | S=int(time); |
599 | 508k | return true; |
600 | 510k | } |
601 | | |
602 | | bool MWAWCellContent::double2String(double val, MWAWCell::Format const &format, std::string &str) |
603 | 0 | { |
604 | 0 | std::stringstream s; |
605 | 0 | switch (format.m_format) { |
606 | 0 | case MWAWCell::F_BOOLEAN: |
607 | 0 | if (val<0 || val >0) s << "true"; |
608 | 0 | else s << "false"; |
609 | 0 | break; |
610 | 0 | case MWAWCell::F_NUMBER: |
611 | 0 | if (format.m_digits>-1000 && format.m_numberFormat!=MWAWCell::F_NUMBER_GENERIC) |
612 | 0 | s << std::setprecision(format.m_digits); |
613 | 0 | switch (format.m_numberFormat) { |
614 | 0 | case MWAWCell::F_NUMBER_CURRENCY: |
615 | 0 | s << std::fixed << val << "$"; |
616 | 0 | break; |
617 | 0 | case MWAWCell::F_NUMBER_DECIMAL: |
618 | 0 | s << val; |
619 | 0 | break; |
620 | 0 | case MWAWCell::F_NUMBER_SCIENTIFIC: |
621 | 0 | s << std::scientific << val; |
622 | 0 | break; |
623 | 0 | case MWAWCell::F_NUMBER_PERCENT: |
624 | 0 | s << std::fixed << 100*val << "%"; |
625 | 0 | break; |
626 | 0 | case MWAWCell::F_NUMBER_FRACTION: |
627 | 0 | case MWAWCell::F_NUMBER_GENERIC: |
628 | 0 | case MWAWCell::F_NUMBER_UNKNOWN: |
629 | | #if !defined(__clang__) |
630 | | default: |
631 | | #endif |
632 | 0 | s << val; |
633 | 0 | break; |
634 | 0 | } |
635 | 0 | break; |
636 | 0 | case MWAWCell::F_DATE: { |
637 | 0 | int Y, M, D; |
638 | 0 | if (!double2Date(val, Y, M, D)) return false; |
639 | 0 | struct tm time; |
640 | 0 | time.tm_sec=time.tm_min=time.tm_hour=0; |
641 | 0 | time.tm_mday=D; |
642 | 0 | time.tm_mon=M; |
643 | 0 | time.tm_year=Y; |
644 | 0 | time.tm_wday=time.tm_yday=time.tm_isdst=-1; |
645 | 0 | #if HAVE_STRUCT_TM_TM_ZONE |
646 | 0 | time.tm_zone=nullptr; |
647 | 0 | #endif |
648 | 0 | char buf[256]; |
649 | 0 | #pragma GCC diagnostic ignored "-Wformat-y2k" |
650 | 0 | #pragma GCC diagnostic ignored "-Wformat-nonliteral" |
651 | 0 | if (mktime(&time)==-1 || |
652 | 0 | !strftime(buf, 256, format.m_DTFormat.empty() ? "%m/%d/%y" : format.m_DTFormat.c_str(), &time)) |
653 | 0 | return false; |
654 | 0 | s << buf; |
655 | 0 | break; |
656 | 0 | } |
657 | 0 | case MWAWCell::F_TIME: { |
658 | 0 | if (val<0 || val>=1) |
659 | 0 | val=std::fmod(val,1.); |
660 | 0 | int H, M, S; |
661 | 0 | if (!double2Time(val, H, M, S)) return false; |
662 | 0 | struct tm time; |
663 | 0 | time.tm_sec=S; |
664 | 0 | time.tm_min=M; |
665 | 0 | time.tm_hour=H; |
666 | 0 | time.tm_mday=time.tm_mon=1; |
667 | 0 | time.tm_year=100; |
668 | 0 | time.tm_wday=time.tm_yday=time.tm_isdst=-1; |
669 | 0 | #if HAVE_STRUCT_TM_TM_ZONE |
670 | 0 | time.tm_zone=nullptr; |
671 | 0 | #endif |
672 | 0 | char buf[256]; |
673 | 0 | if (mktime(&time)==-1 || |
674 | 0 | !strftime(buf, 256, format.m_DTFormat.empty() ? "%H:%M:%S" : format.m_DTFormat.c_str(), &time)) |
675 | 0 | return false; |
676 | 0 | s << buf; |
677 | 0 | break; |
678 | 0 | } |
679 | 0 | case MWAWCell::F_TEXT: |
680 | 0 | case MWAWCell::F_UNKNOWN: |
681 | | #if !defined(__clang__) |
682 | | default: |
683 | | #endif |
684 | 0 | MWAW_DEBUG_MSG(("MWAWCellContent::double2String: called with bad format\n")); |
685 | 0 | return false; |
686 | 0 | } |
687 | 0 | str=s.str(); |
688 | 0 | return true; |
689 | 0 | } |
690 | | |
691 | | std::ostream &operator<<(std::ostream &o, MWAWCellContent const &content) |
692 | 0 | { |
693 | 0 | switch (content.m_contentType) { |
694 | 0 | case MWAWCellContent::C_NONE: |
695 | 0 | break; |
696 | 0 | case MWAWCellContent::C_TEXT: |
697 | 0 | o << ",text=\"" << content.m_textEntry << "\""; |
698 | 0 | break; |
699 | 0 | case MWAWCellContent::C_NUMBER: { |
700 | 0 | o << ",val="; |
701 | 0 | bool textAndVal = false; |
702 | 0 | if (content.hasText()) { |
703 | 0 | o << "entry=" << content.m_textEntry; |
704 | 0 | textAndVal = content.isValueSet(); |
705 | 0 | } |
706 | 0 | if (textAndVal) o << "["; |
707 | 0 | if (content.isValueSet()) o << content.m_value; |
708 | 0 | if (textAndVal) o << "]"; |
709 | 0 | } |
710 | 0 | break; |
711 | 0 | case MWAWCellContent::C_FORMULA: |
712 | 0 | o << ",formula="; |
713 | 0 | for (auto const &form : content.m_formula) |
714 | 0 | o << form; |
715 | 0 | if (content.isValueSet()) o << "[" << content.m_value << "]"; |
716 | 0 | break; |
717 | 0 | case MWAWCellContent::C_UNKNOWN: |
718 | 0 | break; |
719 | | #if !defined(__clang__) |
720 | | default: |
721 | | o << "###unknown type,"; |
722 | | break; |
723 | | #endif |
724 | 0 | } |
725 | 0 | return o; |
726 | 0 | } |
727 | | |
728 | | // ---------- WKSContentListener::FormulaInstruction ------------------ |
729 | | librevenge::RVNGPropertyList MWAWCellContent::FormulaInstruction::getPropertyList(MWAWFontConverter &fontConverter, int fontId) const |
730 | 467k | { |
731 | 467k | librevenge::RVNGPropertyList pList; |
732 | 467k | switch (m_type) { |
733 | 198k | case F_Operator: |
734 | 198k | pList.insert("librevenge:type","librevenge-operator"); |
735 | 198k | pList.insert("librevenge:operator",m_content.c_str()); |
736 | 198k | break; |
737 | 78.3k | case F_Function: |
738 | 78.3k | pList.insert("librevenge:type","librevenge-function"); |
739 | 78.3k | pList.insert("librevenge:function",m_content.c_str()); |
740 | 78.3k | break; |
741 | 19.4k | case F_Text: { |
742 | | // we must use the font converter here to get the final string |
743 | 19.4k | pList.insert("librevenge:type","librevenge-text"); |
744 | 19.4k | librevenge::RVNGString finalStr(""); |
745 | 799k | for (auto c : m_content) { |
746 | 799k | int unicode=fontConverter.unicode(fontId,static_cast<unsigned char>(c)); |
747 | 799k | if (unicode==-1) { |
748 | 295k | if (c < 0x20 && c!=9) { |
749 | 280k | MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction: Find odd char %x\n", static_cast<unsigned int>(c))); |
750 | 280k | } |
751 | 15.2k | else |
752 | 15.2k | finalStr.append(char(c)); |
753 | 295k | } |
754 | 503k | else if (unicode != 0xfffd) |
755 | 503k | libmwaw::appendUnicode(static_cast<uint32_t>(unicode), finalStr); |
756 | 799k | } |
757 | 19.4k | pList.insert("librevenge:text",finalStr); |
758 | 19.4k | break; |
759 | 0 | } |
760 | 0 | case F_Unicode: |
761 | 0 | pList.insert("librevenge:type","librevenge-text"); |
762 | 0 | if (m_content.c_str()) |
763 | 0 | pList.insert("librevenge:text",librevenge::RVNGString(m_content.c_str())); |
764 | 0 | else |
765 | 0 | pList.insert("librevenge:text",""); |
766 | 0 | break; |
767 | 22.4k | case F_Double: |
768 | 22.4k | pList.insert("librevenge:type","librevenge-number"); |
769 | 22.4k | pList.insert("librevenge:number",m_doubleValue, librevenge::RVNG_GENERIC); |
770 | 22.4k | break; |
771 | 47.0k | case F_Long: |
772 | 47.0k | pList.insert("librevenge:type","librevenge-number"); |
773 | 47.0k | pList.insert("librevenge:number",m_longValue, librevenge::RVNG_GENERIC); |
774 | 47.0k | break; |
775 | 72.2k | case F_Cell: |
776 | 72.2k | pList.insert("librevenge:type","librevenge-cell"); |
777 | 72.2k | if (m_position[0][0]>=0) { |
778 | 72.1k | pList.insert("librevenge:column",m_position[0][0]); |
779 | 72.1k | pList.insert("librevenge:column-absolute", !m_positionRelative[0][0]); |
780 | 72.1k | } |
781 | 72.2k | if (m_position[0][1]>=0) { |
782 | 70.2k | pList.insert("librevenge:row",m_position[0][1]); |
783 | 70.2k | pList.insert("librevenge:row-absolute", !m_positionRelative[0][1]); |
784 | 70.2k | } |
785 | 72.2k | if (!m_sheet[0].empty()) |
786 | 192 | pList.insert("librevenge:sheet-name",m_sheet[0]); |
787 | 72.2k | if (!m_fileName.empty()) |
788 | 169 | pList.insert("librevenge:file-name",m_fileName.cstr()); |
789 | 72.2k | break; |
790 | 29.0k | case F_CellList: |
791 | 29.0k | pList.insert("librevenge:type","librevenge-cells"); |
792 | 29.0k | if (m_position[0][0]>=0) { |
793 | 22.6k | pList.insert("librevenge:start-column",m_position[0][0]); |
794 | 22.6k | pList.insert("librevenge:start-column-absolute", !m_positionRelative[0][0]); |
795 | 22.6k | } |
796 | 29.0k | if (m_position[0][1]>=0) { |
797 | 28.9k | pList.insert("librevenge:start-row",m_position[0][1]); |
798 | 28.9k | pList.insert("librevenge:start-row-absolute", !m_positionRelative[0][1]); |
799 | 28.9k | } |
800 | 29.0k | if (m_position[1][0]>=0) { |
801 | 22.6k | pList.insert("librevenge:end-column",m_position[1][0]); |
802 | 22.6k | pList.insert("librevenge:end-column-absolute", !m_positionRelative[1][0]); |
803 | 22.6k | } |
804 | 29.0k | if (m_position[1][1]>=0) { |
805 | 29.0k | pList.insert("librevenge:end-row",m_position[1][1]); |
806 | 29.0k | pList.insert("librevenge:end-row-absolute", !m_positionRelative[1][1]); |
807 | 29.0k | } |
808 | 29.0k | if (!m_sheet[0].empty()) |
809 | 491 | pList.insert("librevenge:sheet-name",m_sheet[0]); |
810 | 29.0k | if (!m_sheet[1].empty()) |
811 | 0 | pList.insert("librevenge:end-sheet-name",m_sheet[1]); |
812 | 29.0k | if (!m_fileName.empty()) |
813 | 306 | pList.insert("librevenge:file-name",m_fileName.cstr()); |
814 | 29.0k | break; |
815 | | #if !defined(__clang__) |
816 | | default: |
817 | | MWAW_DEBUG_MSG(("MWAWCellContent::FormulaInstruction::getPropertyList: unexpected type\n")); |
818 | | #endif |
819 | 467k | } |
820 | 467k | return pList; |
821 | 467k | } |
822 | | |
823 | | std::ostream &operator<<(std::ostream &o, MWAWCellContent::FormulaInstruction const &inst) |
824 | 2.03M | { |
825 | 2.03M | if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Double) |
826 | 15.9k | o << inst.m_doubleValue; |
827 | 2.01M | else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Long) |
828 | 31.0k | o << inst.m_longValue; |
829 | 1.98M | else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Cell) { |
830 | 364k | if (!inst.m_sheet[0].empty()) o << "\"" << inst.m_sheet[0].cstr() << "\""; |
831 | 364k | if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]"; |
832 | 364k | if (!inst.m_positionRelative[0][0]) o << "$"; |
833 | 364k | if (inst.m_position[0][0]<0) o << "C" << inst.m_position[0][0]; |
834 | 364k | else { |
835 | 364k | if (inst.m_position[0][0]>=26) o << char(inst.m_position[0][0]/26-1 + 'A'); |
836 | 364k | o << char(inst.m_position[0][0]%26+'A'); |
837 | 364k | } |
838 | 364k | if (!inst.m_positionRelative[0][1]) o << "$"; |
839 | 364k | if (inst.m_position[0][1]<0) o << "R" << inst.m_position[0][1]; |
840 | 364k | else o << inst.m_position[0][1]; |
841 | 364k | } |
842 | 1.62M | else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_CellList) { |
843 | 1.14M | if (!inst.m_fileName.empty()) o << "[" << inst.m_fileName.cstr() << "]"; |
844 | 3.44M | for (int l=0; l<2; ++l) { |
845 | 2.29M | if (!inst.m_sheet[l].empty() && (l==0 || inst.m_sheet[0]!=inst.m_sheet[1])) |
846 | 2.14k | o << "\"" << inst.m_sheet[l].cstr() << "\""; |
847 | 2.29M | if (!inst.m_positionRelative[l][0]) o << "$"; |
848 | 2.29M | if (inst.m_position[l][0]<0) o << "C" << inst.m_position[l][0]; |
849 | 2.29M | else { |
850 | 2.29M | if (inst.m_position[l][0]>=26) o << char(inst.m_position[l][0]/26-1 + 'A'); |
851 | 2.29M | o << char(inst.m_position[l][0]%26+'A'); |
852 | 2.29M | } |
853 | 2.29M | if (!inst.m_positionRelative[l][1]) o << "$"; |
854 | 2.29M | if (inst.m_position[l][1]<0) o << "R" << inst.m_position[l][1]; |
855 | 2.29M | else o << inst.m_position[l][1]; |
856 | 2.29M | if (l==0) o << ":"; |
857 | 2.29M | } |
858 | 1.14M | } |
859 | 472k | else if (inst.m_type==MWAWCellContent::FormulaInstruction::F_Text || |
860 | 154k | inst.m_type==MWAWCellContent::FormulaInstruction::F_Unicode) |
861 | 317k | o << "\"" << inst.m_content << "\""; |
862 | 154k | else |
863 | 154k | o << inst.m_content; |
864 | 2.03M | return o; |
865 | 2.03M | } |
866 | | |
867 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |