1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* libwps
3  * Version: MPL 2.0 / LGPLv2.1+
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  * Major Contributor(s):
10  * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr)
11  * Copyright (C) 2006, 2007 Andrew Ziem
12  * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13  * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
14  * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
15  *
16  * For minor contributions see the git repository.
17  *
18  * Alternatively, the contents of this file may be used under the terms
19  * of the GNU Lesser General Public License Version 2.1 or later
20  * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
21  * applicable instead of those above.
22  *
23  * For further information visit http://libwps.sourceforge.net
24  */
25 
26 #include <stdio.h>
27 #include <time.h>
28 
29 #include <sstream>
30 
31 #include <librevenge/librevenge.h>
32 
33 #include "WPSCell.h"
34 
~WPSCellFormat()35 WPSCellFormat::~WPSCellFormat()
36 {
37 }
38 
convertDTFormat(std::string const & dtFormat,librevenge::RVNGPropertyListVector & propVect)39 bool WPSCellFormat::convertDTFormat(std::string const &dtFormat, librevenge::RVNGPropertyListVector &propVect)
40 {
41 	propVect.clear();
42 	size_t len=dtFormat.size();
43 	std::string text("");
44 	librevenge::RVNGPropertyList list;
45 	for (size_t c=0; c < len; ++c)
46 	{
47 		if (dtFormat[c]!='%' || c+1==len)
48 		{
49 			text+=dtFormat[c];
50 			continue;
51 		}
52 		char ch=dtFormat[++c];
53 		if (ch=='%')
54 		{
55 			text += '%';
56 			continue;
57 		}
58 		if (!text.empty())
59 		{
60 			list.clear();
61 			list.insert("librevenge:value-type", "text");
62 			list.insert("librevenge:text", text.c_str());
63 			propVect.append(list);
64 			text.clear();
65 		}
66 		list.clear();
67 		switch (ch)
68 		{
69 		case 'Y':
70 			list.insert("number:style", "long");
71 			WPS_FALLTHROUGH;
72 		case 'y':
73 			list.insert("librevenge:value-type", "year");
74 			propVect.append(list);
75 			break;
76 		case 'B':
77 			list.insert("number:style", "long");
78 			WPS_FALLTHROUGH;
79 		case 'b':
80 		case 'h':
81 			list.insert("librevenge:value-type", "month");
82 			list.insert("number:textual", true);
83 			propVect.append(list);
84 			break;
85 		case 'm':
86 			list.insert("librevenge:value-type", "month");
87 			propVect.append(list);
88 			break;
89 		case 'e':
90 			list.insert("number:style", "long");
91 			WPS_FALLTHROUGH;
92 		case 'd':
93 			list.insert("librevenge:value-type", "day");
94 			propVect.append(list);
95 			break;
96 		case 'A':
97 			list.insert("number:style", "long");
98 			WPS_FALLTHROUGH;
99 		case 'a':
100 			list.insert("librevenge:value-type", "day-of-week");
101 			propVect.append(list);
102 			break;
103 
104 		case 'H':
105 			list.insert("number:style", "long");
106 			WPS_FALLTHROUGH;
107 		case 'I':
108 			list.insert("librevenge:value-type", "hours");
109 			propVect.append(list);
110 			break;
111 		case 'M':
112 			list.insert("librevenge:value-type", "minutes");
113 			list.insert("number:style", "long");
114 			propVect.append(list);
115 			break;
116 		case 'S':
117 			list.insert("librevenge:value-type", "seconds");
118 			list.insert("number:style", "long");
119 			propVect.append(list);
120 			break;
121 		case 'p':
122 			list.insert("librevenge:value-type", "text");
123 			list.insert("librevenge:text", " ");
124 			propVect.append(list);
125 			list.clear();
126 			list.insert("librevenge:value-type", "am-pm");
127 			propVect.append(list);
128 			break;
129 		default:
130 			WPS_DEBUG_MSG(("WPSCellFormat::convertDTFormat: find unimplement command %c(ignored)\n", ch));
131 		}
132 	}
133 	if (!text.empty())
134 	{
135 		list.clear();
136 		list.insert("librevenge:value-type", "text");
137 		list.insert("librevenge:text", text.c_str());
138 		propVect.append(list);
139 	}
140 	return propVect.count()!=0;
141 }
142 
setBorders(int wh,WPSBorder const & border)143 void WPSCellFormat::setBorders(int wh, WPSBorder const &border)
144 {
145 	int const allBits = WPSBorder::LeftBit|WPSBorder::RightBit|WPSBorder::TopBit|WPSBorder::BottomBit;
146 	if (wh & (~allBits))
147 	{
148 		WPS_DEBUG_MSG(("WPSCellFormat::setBorders: unknown borders\n"));
149 		return;
150 	}
151 	if (m_bordersList.size() < 4)
152 	{
153 		WPSBorder emptyBorder;
154 		emptyBorder.m_style = WPSBorder::None;
155 		m_bordersList.resize(4, emptyBorder);
156 	}
157 	if (wh & WPSBorder::LeftBit) m_bordersList[WPSBorder::Left] = border;
158 	if (wh & WPSBorder::RightBit) m_bordersList[WPSBorder::Right] = border;
159 	if (wh & WPSBorder::TopBit) m_bordersList[WPSBorder::Top] = border;
160 	if (wh & WPSBorder::BottomBit) m_bordersList[WPSBorder::Bottom] = border;
161 }
162 
addTo(librevenge::RVNGPropertyList & propList) const163 void WPSCellFormat::addTo(librevenge::RVNGPropertyList &propList) const
164 {
165 
166 	switch (m_hAlign)
167 	{
168 	case HALIGN_LEFT:
169 		propList.insert("fo:text-align", "start");
170 		propList.insert("style:text-align-source", "fix");
171 		break;
172 	case HALIGN_CENTER:
173 		propList.insert("fo:text-align", "center");
174 		propList.insert("style:text-align-source", "fix");
175 		break;
176 	case HALIGN_RIGHT:
177 		propList.insert("fo:text-align", "end");
178 		propList.insert("style:text-align-source", "fix");
179 		break;
180 	case HALIGN_FULL:
181 	case HALIGN_DEFAULT:
182 	default:
183 		break;
184 	}
185 	switch (vAlignment())
186 	{
187 	case VALIGN_TOP:
188 		propList.insert("style:vertical-align", "top");
189 		break;
190 	case VALIGN_CENTER:
191 		propList.insert("style:vertical-align", "middle");
192 		break;
193 	case VALIGN_BOTTOM:
194 		propList.insert("style:vertical-align", "bottom");
195 		break;
196 	case VALIGN_DEFAULT:
197 		break; // default
198 	default:
199 		WPS_DEBUG_MSG(("WPSCellFormat::addTo: called with unknown valign=%d\n", vAlignment()));
200 	}
201 	switch (wrapping())
202 	{
203 	case WRAP_WRAP:
204 		propList.insert("fo:wrap-option", "wrap");
205 		break;
206 	case WRAP_NO_WRAP:
207 		propList.insert("fo:wrap-option", "no-wrap");
208 		break;
209 	case WRAP_DEFAULT:
210 		break;
211 	default:
212 		WPS_DEBUG_MSG(("WPSCellFormat::addTo: called with unknown wrapping=%d\n", wrapping()));
213 	}
214 	if (m_rotation)
215 		propList.insert("style:rotation-angle",m_rotation);
216 
217 	for (size_t c = 0; c < m_bordersList.size(); c++)
218 	{
219 		if (m_bordersList[c].isEmpty()) continue;
220 		switch (c)
221 		{
222 		case WPSBorder::Left:
223 			m_bordersList[c].addTo(propList, "left");
224 			break;
225 		case WPSBorder::Right:
226 			m_bordersList[c].addTo(propList, "right");
227 			break;
228 		case WPSBorder::Top:
229 			m_bordersList[c].addTo(propList, "top");
230 			break;
231 		case WPSBorder::Bottom:
232 			m_bordersList[c].addTo(propList, "bottom");
233 			break;
234 		default:
235 			WPS_DEBUG_MSG(("WPSContentListener::openTableCell: can not send %d border\n",int(c)));
236 			break;
237 		}
238 	}
239 	if (!backgroundColor().isWhite())
240 		propList.insert("fo:background-color", backgroundColor().str().c_str());
241 	if (m_protected)
242 		propList.insert("style:cell-protect","protected");
243 	propList.insert("fo:padding",0,librevenge::RVNG_POINT); // changme
244 }
245 
getValueType() const246 std::string WPSCellFormat::getValueType() const
247 {
248 	switch (m_format)
249 	{
250 	case F_NUMBER:
251 		switch (m_subFormat)
252 		{
253 		case 0: // default
254 		case 1: // decimal
255 		case 5: // thousand
256 		case 6: // fixed
257 		case 7: // fraction
258 		default:
259 			return "float";
260 		case 2:
261 			return "scientific";
262 		case 3:
263 			return "percentage";
264 		case 4:
265 			return "currency";
266 		}
267 	case F_BOOLEAN:
268 		return "boolean";
269 	case F_DATE:
270 		return "date";
271 	case F_TIME:
272 		return "time";
273 	case F_TEXT:
274 	case F_UNKNOWN:
275 	default:
276 		break;
277 	}
278 	return "float";
279 }
280 
getNumberingProperties(librevenge::RVNGPropertyList & propList) const281 bool WPSCellFormat::getNumberingProperties(librevenge::RVNGPropertyList &propList) const
282 {
283 	librevenge::RVNGPropertyListVector pVect;
284 	switch (m_format)
285 	{
286 	case F_BOOLEAN:
287 		propList.insert("librevenge:value-type", "boolean");
288 		break;
289 	case F_NUMBER:
290 		if (m_digits>-1000)
291 			propList.insert("number:decimal-places", m_digits);
292 		switch (m_subFormat)
293 		{
294 		case 5: // thousand
295 			propList.insert("number:grouping", true);
296 			WPS_FALLTHROUGH;
297 		case 0: // default
298 			if (m_subFormat==0)
299 				propList.remove("number:decimal-places");
300 			WPS_FALLTHROUGH;
301 		case 1: // decimal
302 			propList.insert("librevenge:value-type", "number");
303 			break;
304 		case 2:
305 			propList.insert("librevenge:value-type", "scientific");
306 			break;
307 		case 3:
308 			propList.insert("librevenge:value-type", "percentage");
309 			break;
310 		case 6: // fixed
311 			propList.insert("librevenge:value-type", "number");
312 			propList.insert("number:min-integer-digits", m_digits+1);
313 			propList.insert("number:decimal-places", 0);
314 			break;
315 		case 7:
316 			propList.insert("librevenge:value-type", "fraction");
317 			propList.insert("number:min-integer-digits", 0);
318 			propList.insert("number:min-numerator-digits", 1);
319 			propList.insert("number:min-denominator-digits", 1);
320 			propList.remove("number:decimal-places");
321 			break;
322 		case 4:
323 		{
324 			// DOME: implement non us currency
325 			propList.clear();
326 			propList.insert("librevenge:value-type", "currency");
327 			librevenge::RVNGPropertyList list;
328 			list.insert("librevenge:value-type", "currency-symbol");
329 			list.insert("number:language","en");
330 			list.insert("number:country","US");
331 			list.insert("librevenge:currency","$");
332 			pVect.append(list);
333 
334 			list.clear();
335 			list.insert("librevenge:value-type", "number");
336 			if (m_digits>-1000)
337 				list.insert("number:decimal-places", m_digits);
338 			pVect.append(list);
339 			break;
340 		}
341 		default:
342 			return false;
343 		}
344 		break;
345 	case F_DATE:
346 		propList.insert("librevenge:value-type", "date");
347 		propList.insert("number:automatic-order", "true");
348 		if (!convertDTFormat(m_DTFormat.empty() ? "%m/%d/%Y" : m_DTFormat, pVect))
349 			return false;
350 		break;
351 	case F_TIME:
352 		propList.insert("librevenge:value-type", "time");
353 		propList.insert("number:automatic-order", "true");
354 		if (!convertDTFormat(m_DTFormat.empty() ? "%H:%M:%S" : m_DTFormat, pVect))
355 			return false;
356 		break;
357 	case F_TEXT:
358 	case F_UNKNOWN:
359 	default:
360 		return false;
361 	}
362 	propList.insert("librevenge:format", pVect);
363 	return true;
364 }
365 
compare(WPSCellFormat const & cell,bool onlyNumbering) const366 int WPSCellFormat::compare(WPSCellFormat const &cell, bool onlyNumbering) const
367 {
368 	if (m_format<cell.m_format) return 1;
369 	if (m_format>cell.m_format) return -1;
370 	if (m_subFormat<cell.m_subFormat) return 1;
371 	if (m_subFormat>cell.m_subFormat) return -1;
372 	if (m_DTFormat<cell.m_DTFormat) return 1;
373 	if (m_DTFormat>cell.m_DTFormat) return -1;
374 	if (m_digits<cell.m_digits) return 1;
375 	if (m_digits>cell.m_digits) return -1;
376 	if (onlyNumbering) return 0;
377 	int diff = int(m_hAlign) - int(cell.m_hAlign);
378 	if (diff) return diff;
379 	diff = int(m_vAlign) - int(cell.m_vAlign);
380 	if (diff) return diff;
381 	diff = int(m_wrapping) - int(cell.m_wrapping);
382 	if (diff) return diff;
383 	if (m_rotation<cell.m_rotation) return 1;
384 	if (m_rotation>cell.m_rotation) return -1;
385 	if (m_backgroundColor<cell.m_backgroundColor) return 1;
386 	if (m_backgroundColor>cell.m_backgroundColor) return -1;
387 	if (m_protected !=cell.m_protected) return m_protected ? 1 : -1;
388 	diff = int(m_bordersList.size()) - int(cell.m_bordersList.size());
389 	if (diff) return diff;
390 	for (size_t c = 0; c < m_bordersList.size(); c++)
391 	{
392 		diff = m_bordersList[c].compare(cell.m_bordersList[c]);
393 		if (diff) return diff;
394 	}
395 	return 0;
396 }
397 
operator <<(std::ostream & o,WPSCellFormat const & cell)398 std::ostream &operator<<(std::ostream &o, WPSCellFormat const &cell)
399 {
400 	o << "font=[" << cell.m_font << "],";
401 	switch (cell.m_hAlign)
402 	{
403 	case WPSCellFormat::HALIGN_LEFT:
404 		o << "left,";
405 		break;
406 	case WPSCellFormat::HALIGN_CENTER:
407 		o << "centered,";
408 		break;
409 	case WPSCellFormat::HALIGN_RIGHT:
410 		o << "right,";
411 		break;
412 	case WPSCellFormat::HALIGN_FULL:
413 		o << "full,";
414 		break;
415 	case WPSCellFormat::HALIGN_DEFAULT:
416 	default:
417 		break; // default
418 	}
419 	switch (cell.m_vAlign)
420 	{
421 	case WPSCellFormat::VALIGN_TOP:
422 		o << "yTop,";
423 		break;
424 	case WPSCellFormat::VALIGN_CENTER:
425 		o << "yCenter,";
426 		break;
427 	case WPSCellFormat::VALIGN_BOTTOM:
428 		o << "yBottom,";
429 		break;
430 	case WPSCellFormat::VALIGN_DEFAULT:
431 	default:
432 		break; // default
433 	}
434 	switch (cell.m_wrapping)
435 	{
436 	case WPSCellFormat::WRAP_WRAP:
437 		o << "wrap,";
438 		break;
439 	case WPSCellFormat::WRAP_NO_WRAP:
440 		o << "wrap[no],";
441 		break;
442 	case WPSCellFormat::WRAP_DEFAULT:
443 	default:
444 		break;
445 	}
446 	if (cell.m_rotation)
447 		o << "rotation=" << cell.m_rotation << ",";
448 	int subForm = cell.m_subFormat;
449 	switch (cell.m_format)
450 	{
451 	case WPSCellFormat::F_BOOLEAN:
452 		o << "boolean";
453 		break;
454 	case WPSCellFormat::F_TEXT:
455 		o << "text";
456 		if (subForm)
457 		{
458 			o << "[Fo" << subForm << "]";
459 			subForm = 0;
460 		}
461 		break;
462 	case WPSCellFormat::F_NUMBER:
463 		o << "number";
464 		switch (subForm)
465 		{
466 		case 1:
467 			o << "[decimal]";
468 			break;
469 		case 2:
470 			o << "[exp]";
471 			break;
472 		case 3:
473 			o << "[percent]";
474 			break;
475 		case 4:
476 			o << "[money]";
477 			break;
478 		case 5:
479 			o << "[thousand]";
480 			break;
481 		case 6:
482 			o << "[fixed]";
483 			break;
484 		case 7:
485 			o << "[fraction]";
486 			break;
487 		default:
488 			o << "[Fo" << subForm << "]";
489 			break;
490 		case 0:
491 			break;
492 		}
493 		subForm=0;
494 		break;
495 	case WPSCellFormat::F_DATE:
496 		o << "date[" << cell.getDTFormat() << "]";
497 		break;
498 	case WPSCellFormat::F_TIME:
499 		o << "time[" << cell.getDTFormat() << "]";
500 		break;
501 	case WPSCellFormat::F_UNKNOWN:
502 	default:
503 		break; // default
504 	}
505 	if (subForm) o << "[format=#" << subForm << "]";
506 	o << ",";
507 
508 	if (cell.m_digits>-1000) o << "digits=" << cell.m_digits << ",";
509 	if (cell.m_protected) o << "protected,";
510 	if (!cell.m_backgroundColor.isWhite())
511 		o << "backColor=" << cell.m_backgroundColor << ",";
512 	for (size_t i = 0; i < cell.m_bordersList.size(); i++)
513 	{
514 		if (cell.m_bordersList[i].m_style == WPSBorder::None)
515 			continue;
516 		o << "bord";
517 		if (i < 6)
518 		{
519 			char const *wh[] = { "L", "R", "T", "B", "MiddleH", "MiddleV" };
520 			o << wh[i];
521 		}
522 		else o << "[#wh=" << i << "]";
523 		o << "=" << cell.m_bordersList[i] << ",";
524 	}
525 	return o;
526 }
527 
528 ////////////////////////////////////////////////////////////
529 ////////////////////////////////////////////////////////////
~WPSCell()530 WPSCell::~WPSCell()
531 {
532 }
533 
addTo(librevenge::RVNGPropertyList & propList) const534 void WPSCell::addTo(librevenge::RVNGPropertyList &propList) const
535 {
536 	propList.insert("librevenge:column", position()[0]);
537 	propList.insert("librevenge:row", position()[1]);
538 
539 	propList.insert("table:number-columns-spanned", numSpannedCells()[0]);
540 	propList.insert("table:number-rows-spanned", numSpannedCells()[1]);
541 
542 	WPSCellFormat::addTo(propList);
543 }
544 
operator <<(std::ostream & o,WPSCell const & cell)545 std::ostream &operator<<(std::ostream &o, WPSCell const &cell)
546 {
547 	o << "C" << cell.m_position << ":";
548 	if (cell.numSpannedCells()[0] != 1 || cell.numSpannedCells()[1] != 1)
549 		o << "span=[" << cell.numSpannedCells()[0] << "," << cell.numSpannedCells()[1] << "],";
550 	if (cell.m_box!=WPSBox2f())
551 		o << "box=" << cell.m_box << ",";
552 	if (cell.m_verticalSet) o << "ySet,";
553 	o << static_cast<WPSCellFormat const &>(cell);
554 
555 	return o;
556 }
557 
558 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
559