1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* libodfgen
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) 2002-2004 William Lachance (wrlach@gmail.com)
11  * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
12  *
13  * For minor contributions see the git repository.
14  *
15  * Alternatively, the contents of this file may be used under the terms
16  * of the GNU Lesser General Public License Version 2.1 or later
17  * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
18  * applicable instead of those above.
19  *
20  * For further information visit http://libwpd.sourceforge.net
21  */
22 
23 #include "SheetStyle.hxx"
24 
25 #include <math.h>
26 #ifdef _MSC_VER
27 # include <minmax.h>
28 #endif
29 #include <string.h>
30 
31 #include <sstream>
32 #include <string>
33 
34 #include "DocumentElement.hxx"
35 #include "FilterInternal.hxx"
36 #include "NumberingStyle.hxx"
37 #include "TextRunStyle.hxx"
38 
39 namespace libodfgen
40 {
getColumnName(int col)41 static std::string getColumnName(int col)
42 {
43 	// note: we can also limit the maximal number of column. However,
44 	// in this case, the current code must generate a valid string ;
45 	// of course, the resulting formula will be invalid when col is
46 	// too big (which seems ok and the best that we can do)
47 	if (col<0)
48 	{
49 		ODFGEN_DEBUG_MSG(("libodfgen::getColumnName[SheetStyle.cxx]: called with invalid column %d\n", col));
50 		return "ZZZZ"; // we must return something, ZZZZ must make the formula invalid...
51 	}
52 	std::string name(1, char(col%26+'A'));
53 	col /= 26;
54 	while (col>0)
55 	{
56 		--col;
57 		name.insert(0, std::string(1,char(col%26+'A')));
58 		col /= 26;
59 	}
60 	return name;
61 }
62 }
SheetCellStyle(const librevenge::RVNGPropertyList & xPropList,const char * psName)63 SheetCellStyle::SheetCellStyle(const librevenge::RVNGPropertyList &xPropList, const char *psName) :
64 	Style(psName),
65 	mPropList(xPropList)
66 {
67 }
68 
writeStyle(OdfDocumentHandler * pHandler,SheetManager const & manager) const69 void SheetCellStyle::writeStyle(OdfDocumentHandler *pHandler, SheetManager const &manager) const
70 {
71 	TagOpenElement styleOpen("style:style");
72 	styleOpen.addAttribute("style:name", getName());
73 	if (mPropList["style:parent-style-name"])
74 		styleOpen.addAttribute("style:parent-style-name", mPropList["style:parent-style-name"]->getStr());
75 	styleOpen.addAttribute("style:family", "table-cell");
76 	if (mPropList["librevenge:numbering-name"])
77 	{
78 		librevenge::RVNGString numberingName=
79 		    manager.getNumberingManager().getStyleName(mPropList["librevenge:numbering-name"]->getStr());
80 		if (numberingName.empty())
81 		{
82 			ODFGEN_DEBUG_MSG(("SheetCellStyle::writeStyle can not find numbering style %s\n", mPropList["librevenge:numbering-name"]->getStr().cstr()));
83 		}
84 		else
85 			styleOpen.addAttribute("style:data-style-name", numberingName.cstr());
86 	}
87 	styleOpen.write(pHandler);
88 
89 	librevenge::RVNGPropertyList textProp;
90 	SpanStyleManager::addSpanProperties(mPropList, textProp);
91 	if (!textProp.empty())
92 	{
93 		pHandler->startElement("style:text-properties", textProp);
94 		pHandler->endElement("style:text-properties");
95 	}
96 	// WLACH_REFACTORING: Only temporary.. a much better solution is to
97 	// generalize this sort of thing into the "Style" superclass
98 	librevenge::RVNGPropertyList stylePropList;
99 	librevenge::RVNGPropertyList paragPropList;
100 	librevenge::RVNGPropertyList::Iter i(mPropList);
101 	bool paddingSet=false;
102 	for (i.rewind(); i.next();)
103 	{
104 		auto len = (int) strlen(i.key());
105 		if (i.child())
106 			continue;
107 		if (len > 3 && strncmp(i.key(), "fo:", 3)==0)
108 		{
109 			if (len==13 && !strcmp(i.key(), "fo:text-align"))
110 			{
111 				paragPropList.insert("fo:text-align", mPropList["fo:text-align"]->clone());
112 				if (!mPropList["fo:margin-left"])
113 					paragPropList.insert("fo:margin-left", "0cm");
114 			}
115 			else if (len==14 && !strcmp(i.key(), "fo:margin-left"))
116 				paragPropList.insert("fo:margin-left", mPropList["fo:margin-left"]->clone());
117 			else
118 			{
119 				if (len>=9 && strncmp(i.key(), "fo:padding", 9)==0)
120 					paddingSet=true;
121 				stylePropList.insert(i.key(), i()->clone());
122 			}
123 		}
124 		else if (len>6 && strncmp(i.key(), "style:", 6)==0)
125 		{
126 			if (len > 22  && !strncmp(i.key(), "style:border-line-width", 23))
127 			{
128 				if (!strcmp(i.key(), "style:border-line-width") ||
129 				        !strcmp(i.key(), "style:border-line-width-left") ||
130 				        !strcmp(i.key(), "style:border-line-width-right") ||
131 				        !strcmp(i.key(), "style:border-line-width-top")||
132 				        !strcmp(i.key(), "style:border-line-width-bottom"))
133 					stylePropList.insert(i.key(), i()->clone());
134 			}
135 			else if (len == 23 && !strcmp(i.key(), "style:text-align-source"))
136 				stylePropList.insert(i.key(), i()->clone());
137 			else if (len == 18 && !strcmp(i.key(), "style:cell-protect"))
138 				stylePropList.insert(i.key(), i()->clone());
139 			else if (len == 15 && !strcmp(i.key(), "style:direction"))
140 				stylePropList.insert(i.key(), i()->clone());
141 			else if (len == 18 && !strcmp(i.key(), "style:print-content"))
142 				stylePropList.insert(i.key(), i()->clone());
143 			else if (len == 20 && !strcmp(i.key(), "style:repeat-content"))
144 				stylePropList.insert(i.key(), i()->clone());
145 			else if (len == 20 && !strcmp(i.key(), "style:rotation-align"))
146 				stylePropList.insert(i.key(), i()->clone());
147 			else if (len == 20 && !strcmp(i.key(), "style:rotation-angle"))
148 				stylePropList.insert(i.key(), i()->clone());
149 			else if (len == 12 && !strcmp(i.key(), "style:shadow"))
150 				stylePropList.insert(i.key(), i()->clone());
151 			else if (len == 20 && !strcmp(i.key(), "style:vertical-align"))
152 				stylePropList.insert(i.key(), i()->clone());
153 			else if (len == 18 && !strcmp(i.key(), "style:writing-mode"))
154 				stylePropList.insert(i.key(), i()->clone());
155 		}
156 	}
157 	if (!paddingSet)
158 		stylePropList.insert("fo:padding", "0.0382in");
159 	pHandler->startElement("style:table-cell-properties", stylePropList);
160 	pHandler->endElement("style:table-cell-properties");
161 	if (!paragPropList.empty())
162 	{
163 		pHandler->startElement("style:paragraph-properties", paragPropList);
164 		pHandler->endElement("style:paragraph-properties");
165 	}
166 	pHandler->endElement("style:style");
167 }
168 
SheetRowStyle(const librevenge::RVNGPropertyList & propList,const char * psName)169 SheetRowStyle::SheetRowStyle(const librevenge::RVNGPropertyList &propList, const char *psName) :
170 	Style(psName),
171 	mPropList(propList)
172 {
173 }
174 
writeStyle(OdfDocumentHandler * pHandler,SheetManager const &) const175 void SheetRowStyle::writeStyle(OdfDocumentHandler *pHandler, SheetManager const &) const
176 {
177 	TagOpenElement styleOpen("style:style");
178 	styleOpen.addAttribute("style:name", getName());
179 	styleOpen.addAttribute("style:family", "table-row");
180 	styleOpen.write(pHandler);
181 
182 	TagOpenElement stylePropertiesOpen("style:table-row-properties");
183 	if (mPropList["style:row-height"])
184 		stylePropertiesOpen.addAttribute("style:row-height", mPropList["style:row-height"]->getStr());
185 	else if (mPropList["style:min-row-height"]) // min-row does not seem to work
186 		stylePropertiesOpen.addAttribute("style:row-height", mPropList["style:min-row-height"]->getStr());
187 	if (mPropList["style:use-optimal-row-height"])
188 		stylePropertiesOpen.addAttribute("style:use-optimal-row-height", mPropList["style:use-optimal-row-height"]->getStr());
189 	stylePropertiesOpen.addAttribute("fo:keep-together", "auto");
190 	stylePropertiesOpen.write(pHandler);
191 	pHandler->endElement("style:table-row-properties");
192 
193 	pHandler->endElement("style:style");
194 }
195 
196 
SheetStyle(const librevenge::RVNGPropertyList & xPropList,const char * psName,Style::Zone zone)197 SheetStyle::SheetStyle(const librevenge::RVNGPropertyList &xPropList, const char *psName, Style::Zone zone) :
198 	Style(psName, zone), mPropList(xPropList), mColumns(nullptr),
199 	mRowNameHash(), mRowStyleHash(), mCellNameHash(), mCellStyleHash()
200 {
201 	mColumns = mPropList.child("librevenge:columns");
202 }
203 
~SheetStyle()204 SheetStyle::~SheetStyle()
205 {
206 }
207 
addColumnDefinitions(libodfgen::DocumentElementVector & storage) const208 void SheetStyle::addColumnDefinitions(libodfgen::DocumentElementVector &storage) const
209 {
210 	if (!mColumns) return;
211 	int col=1;
212 	librevenge::RVNGPropertyListVector::Iter j(*mColumns);
213 	for (j.rewind(); j.next(); ++col)
214 	{
215 		auto pTableColumnOpenElement = std::make_shared<TagOpenElement>("table:table-column");
216 		librevenge::RVNGString sColumnStyleName;
217 		sColumnStyleName.sprintf("%s_col%i", getName().cstr(), col);
218 		pTableColumnOpenElement->addAttribute("table:style-name", sColumnStyleName);
219 		if (j()["table:number-columns-repeated"] && j()["table:number-columns-repeated"]->getInt()>1)
220 			pTableColumnOpenElement->addAttribute("table:number-columns-repeated",
221 			                                      j()["table:number-columns-repeated"]->getStr());
222 
223 		storage.push_back(pTableColumnOpenElement);
224 
225 		storage.push_back(std::make_shared<TagCloseElement>("table:table-column"));
226 	}
227 }
228 
writeStyle(OdfDocumentHandler * pHandler,SheetManager const & manager) const229 void SheetStyle::writeStyle(OdfDocumentHandler *pHandler, SheetManager const &manager) const
230 {
231 	TagOpenElement styleOpen("style:style");
232 	styleOpen.addAttribute("style:name", getName());
233 	styleOpen.addAttribute("style:family", "table");
234 	if (mPropList["style:master-page-name"])
235 		styleOpen.addAttribute("style:master-page-name", mPropList["style:master-page-name"]->getStr());
236 	styleOpen.write(pHandler);
237 
238 	TagOpenElement stylePropertiesOpen("style:table-properties");
239 	stylePropertiesOpen.addAttribute("table:display", "true");
240 	if (mPropList["table:align"])
241 		stylePropertiesOpen.addAttribute("table:align", mPropList["table:align"]->getStr());
242 	if (mPropList["fo:margin-left"])
243 		stylePropertiesOpen.addAttribute("fo:margin-left", mPropList["fo:margin-left"]->getStr());
244 	if (mPropList["fo:margin-right"])
245 		stylePropertiesOpen.addAttribute("fo:margin-right", mPropList["fo:margin-right"]->getStr());
246 	if (mPropList["style:width"])
247 		stylePropertiesOpen.addAttribute("style:width", mPropList["style:width"]->getStr());
248 	if (mPropList["fo:break-before"])
249 		stylePropertiesOpen.addAttribute("fo:break-before", mPropList["fo:break-before"]->getStr());
250 	if (mPropList["table:border-model"])
251 		stylePropertiesOpen.addAttribute("table:border-model", mPropList["table:border-model"]->getStr());
252 	stylePropertiesOpen.write(pHandler);
253 
254 	pHandler->endElement("style:table-properties");
255 
256 	pHandler->endElement("style:style");
257 
258 	if (mColumns)
259 	{
260 		librevenge::RVNGPropertyListVector::Iter j(*mColumns);
261 		int col=1;
262 		for (j.rewind(); j.next(); ++col)
263 		{
264 			TagOpenElement columnStyleOpen("style:style");
265 			librevenge::RVNGString sColumnName;
266 			sColumnName.sprintf("%s_col%i", getName().cstr(), col);
267 			columnStyleOpen.addAttribute("style:name", sColumnName);
268 			columnStyleOpen.addAttribute("style:family", "table-column");
269 			columnStyleOpen.write(pHandler);
270 
271 			librevenge::RVNGPropertyList columnProperties(j());
272 			if (columnProperties["table:number-columns-repeated"])
273 				columnProperties.remove("table:number-columns-repeated");
274 			pHandler->startElement("style:table-column-properties", columnProperties);
275 			pHandler->endElement("style:table-column-properties");
276 
277 			pHandler->endElement("style:style");
278 		}
279 	}
280 
281 	std::map<librevenge::RVNGString, std::shared_ptr<SheetRowStyle> >::const_iterator rIt;
282 	for (rIt=mRowStyleHash.begin(); rIt!=mRowStyleHash.end(); ++rIt)
283 	{
284 		if (!rIt->second) continue;
285 		rIt->second->writeStyle(pHandler, manager);
286 	}
287 
288 	std::map<librevenge::RVNGString, std::shared_ptr<SheetCellStyle> >::const_iterator cIt;
289 	for (cIt=mCellStyleHash.begin(); cIt!=mCellStyleHash.end(); ++cIt)
290 	{
291 		if (!cIt->second) continue;
292 		cIt->second->writeStyle(pHandler, manager);
293 	}
294 }
295 
addRow(const librevenge::RVNGPropertyList & propList)296 librevenge::RVNGString SheetStyle::addRow(const librevenge::RVNGPropertyList &propList)
297 {
298 	// first remove unused data
299 	librevenge::RVNGPropertyList pList;
300 	librevenge::RVNGPropertyList::Iter i(propList);
301 	for (i.rewind(); i.next();)
302 	{
303 		if (strncmp(i.key(), "librevenge:", 11)==0 ||
304 		        strcmp(i.key(), "table:number-rows-repeated")==0 || i.child())
305 			continue;
306 		pList.insert(i.key(),i()->clone());
307 	}
308 	librevenge::RVNGString hashKey = pList.getPropString();
309 	std::map<librevenge::RVNGString, librevenge::RVNGString>::const_iterator iter =
310 	    mRowNameHash.find(hashKey);
311 	if (iter!=mRowNameHash.end()) return iter->second;
312 
313 	librevenge::RVNGString name;
314 	name.sprintf("%s_row%i", getName().cstr(), (int) mRowStyleHash.size());
315 	mRowNameHash[hashKey]=name;
316 	mRowStyleHash[name]=std::shared_ptr<SheetRowStyle>(new SheetRowStyle(propList, name.cstr()));
317 	return name;
318 }
319 
addCell(const librevenge::RVNGPropertyList & propList)320 librevenge::RVNGString SheetStyle::addCell(const librevenge::RVNGPropertyList &propList)
321 {
322 	// first remove unused data
323 	librevenge::RVNGPropertyList pList;
324 	librevenge::RVNGPropertyList::Iter i(propList);
325 	for (i.rewind(); i.next();)
326 	{
327 		if (strncmp(i.key(), "librevenge:", 11)==0 &&
328 		        strncmp(i.key(), "librevenge:numbering-name", 24)!=0)
329 			continue;
330 		if (strncmp(i.key(), "table:number-", 13)==0 &&
331 		        (strcmp(i.key(), "table:number-columns-repeated")==0 ||
332 		         strcmp(i.key(), "table:number-columns-spanned")==0 ||
333 		         strcmp(i.key(), "table:number-rows-spanned")==0 ||
334 		         strcmp(i.key(), "table:number-matrix-columns-spanned")==0 ||
335 		         strcmp(i.key(), "table:number-matrix-rows-spanned")==0))
336 			continue;
337 		if (i.child())
338 			continue;
339 
340 		pList.insert(i.key(),i()->clone());
341 	}
342 	librevenge::RVNGString hashKey = pList.getPropString();
343 	std::map<librevenge::RVNGString, librevenge::RVNGString>::const_iterator iter =
344 	    mCellNameHash.find(hashKey);
345 	if (iter!=mCellNameHash.end()) return iter->second;
346 
347 	librevenge::RVNGString name;
348 	name.sprintf("%s_cell%i", getName().cstr(), (int) mCellStyleHash.size());
349 	mCellNameHash[hashKey]=name;
350 	mCellStyleHash[name]=std::shared_ptr<SheetCellStyle>(new SheetCellStyle(propList, name.cstr()));
351 	return name;
352 }
353 
SheetManager(NumberingManager & numberingManager)354 SheetManager::SheetManager(NumberingManager &numberingManager) :
355 	mpNumberingManager(numberingManager), mbSheetOpened(false), mSheetStyles()
356 {
357 }
358 
~SheetManager()359 SheetManager::~SheetManager()
360 {
361 }
362 
clean()363 void SheetManager::clean()
364 {
365 	mSheetStyles.clear();
366 }
367 
openSheet(const librevenge::RVNGPropertyList & xPropList,Style::Zone zone)368 bool SheetManager::openSheet(const librevenge::RVNGPropertyList &xPropList, Style::Zone zone)
369 {
370 	if (mbSheetOpened)
371 	{
372 		ODFGEN_DEBUG_MSG(("SheetManager::oops: a sheet is already open\n"));
373 		return false;
374 	}
375 	mbSheetOpened=true;
376 	if (zone==Style::Z_Unknown)
377 		zone=Style::Z_ContentAutomatic;
378 
379 	librevenge::RVNGString sTableName;
380 	if (zone==Style::Z_StyleAutomatic)
381 		sTableName.sprintf("Sheet_M%i", (int) mSheetStyles.size());
382 	else
383 		sTableName.sprintf("Sheet%i", (int) mSheetStyles.size());
384 	std::shared_ptr<SheetStyle> sheet(new SheetStyle(xPropList, sTableName.cstr(), zone));
385 	mSheetStyles.push_back(sheet);
386 	return true;
387 }
388 
closeSheet()389 bool SheetManager::closeSheet()
390 {
391 	if (!mbSheetOpened)
392 	{
393 		ODFGEN_DEBUG_MSG(("SheetManager::oops: no sheet are opened\n"));
394 		return false;
395 	}
396 	mbSheetOpened=false;
397 	return true;
398 }
399 
convertFormula(const librevenge::RVNGPropertyListVector & formula)400 librevenge::RVNGString SheetManager::convertFormula(const librevenge::RVNGPropertyListVector &formula)
401 {
402 	char const *operators[] =
403 	{
404 		"(", ")", "+", "-", "*", "/", "=", "<>",  ";", "<", ">", "<=", ">=", "^", "&", "!", "~", ":", "%", "{", "}", "|"
405 	};
406 	librevenge::RVNGString res("");
407 	std::stringstream s;
408 	s << "of:=";
409 	for (unsigned long i=0; i<formula.count(); ++i)
410 	{
411 		librevenge::RVNGPropertyList const &list=formula[i];
412 		if (!list["librevenge:type"])
413 		{
414 			ODFGEN_DEBUG_MSG(("SheetManager::convertFormula can not find %s formula type !!!\n", s.str().c_str()));
415 			return res;
416 		}
417 		std::string type(list["librevenge:type"]->getStr().cstr());
418 		if (type=="librevenge-operator")
419 		{
420 			if (!list["librevenge:operator"])
421 			{
422 				ODFGEN_DEBUG_MSG(("SheetManager::convertFormula can not find operator for formula[%s]!!!\n", s.str().c_str()));
423 				return res;
424 			}
425 			std::string oper(list["librevenge:operator"]->getStr().cstr());
426 			bool find=false;
427 			for (auto &w : operators)
428 			{
429 				if (oper!=w) continue;
430 				s << oper;
431 				find=true;
432 				break;
433 			}
434 			if (!find)
435 			{
436 				ODFGEN_DEBUG_MSG(("SheetManager::convertFormula find unknown operator for formula[%s]!!!\n", s.str().c_str()));
437 				return res;
438 			}
439 		}
440 		else if (type=="librevenge-function")
441 		{
442 			if (!list["librevenge:function"])
443 			{
444 				ODFGEN_DEBUG_MSG(("SheetManager::convertFormula can not find value for formula[%s]!!!\n", s.str().c_str()));
445 				return res;
446 			}
447 			s << list["librevenge:function"]->getStr().cstr();
448 		}
449 		else if (type=="librevenge-number")
450 		{
451 			if (!list["librevenge:number"])
452 			{
453 				ODFGEN_DEBUG_MSG(("SheetManager::convertFormula can not find value for formula[%s]!!!\n", s.str().c_str()));
454 				return res;
455 			}
456 			s << list["librevenge:number"]->getStr().cstr();
457 		}
458 		else if (type=="librevenge-text")
459 		{
460 			if (!list["librevenge:text"])
461 			{
462 				ODFGEN_DEBUG_MSG(("SheetManager::convertFormula can not find text for formula[%s]!!!\n", s.str().c_str()));
463 				return res;
464 			}
465 			librevenge::RVNGString escaped;
466 			escaped.appendEscapedXML(list["librevenge:text"]->getStr());
467 			s << "\"" << escaped.cstr() << "\"";
468 		}
469 		else if (type=="librevenge-cell")
470 		{
471 			librevenge::RVNGString range=convertCellRange(list);
472 			if (range.empty())
473 			{
474 				// look for special case: a complete row or column
475 				if ((list["librevenge:column"] && list["librevenge:row"]) ||
476 				        (!list["librevenge:column"] && !list["librevenge:row"]))
477 					return res;
478 				if (i+2<formula.count() &&
479 				        formula[i+1]["librevenge:operator"] && formula[i+1]["librevenge:operator"]->getStr()==":" &&
480 				        formula[i+2]["librevenge:type"] && formula[i+2]["librevenge:type"]->getStr()=="librevenge-cell")
481 				{
482 					// cell followed by a range's operator and a cell, recreate the range cells...
483 					auto rList(list);
484 					if (list["librevenge:column"]) rList.insert("librevenge:start-column", list["librevenge:column"]->getStr());
485 					if (list["librevenge:column-absolute"]) rList.insert("librevenge:start-column-absolute", list["librevenge:column-absolute"]->getStr());
486 					if (list["librevenge:row"]) rList.insert("librevenge:start-row", list["librevenge:row"]->getStr());
487 					if (list["librevenge:row-absolute"]) rList.insert("librevenge:start-row-absolute", list["librevenge:row-absolute"]->getStr());
488 					if (formula[i+2]["librevenge:column"]) rList.insert("librevenge:end-column", formula[i+2]["librevenge:column"]->getStr());
489 					if (formula[i+2]["librevenge:column-absolute"]) rList.insert("librevenge:end-column-absolute", formula[i+2]["librevenge:column-absolute"]->getStr());
490 					if (formula[i+2]["librevenge:row"]) rList.insert("librevenge:end-row", formula[i+2]["librevenge:row"]->getStr());
491 					if (formula[i+2]["librevenge:row-absolute"]) rList.insert("librevenge:end-row-absolute", formula[i+2]["librevenge:row-absolute"]->getStr());
492 					i += 2;
493 					range=convertRowOrColumnCellsRange(rList);
494 				}
495 				else
496 				{
497 					// isolated cell, recreate a range cells
498 					auto rList(list);
499 					if (list["librevenge:column"])
500 					{
501 						rList.insert("librevenge:start-column", list["librevenge:column"]->getStr());
502 						rList.insert("librevenge:end-column", list["librevenge:column"]->getStr());
503 					}
504 					if (list["librevenge:column-absolute"])
505 					{
506 						rList.insert("librevenge:start-column-absolute", list["librevenge:column-absolute"]->getStr());
507 						rList.insert("librevenge:end-column-absolute", list["librevenge:column-absolute"]->getStr());
508 					}
509 					if (list["librevenge:row"])
510 					{
511 						rList.insert("librevenge:start-row", list["librevenge:row"]->getStr());
512 						rList.insert("librevenge:end-row", list["librevenge:row"]->getStr());
513 					}
514 					if (list["librevenge:row-absolute"])
515 					{
516 						rList.insert("librevenge:start-row-absolute", list["librevenge:row-absolute"]->getStr());
517 						rList.insert("librevenge:end-row-absolute", list["librevenge:row-absolute"]->getStr());
518 					}
519 					range=convertRowOrColumnCellsRange(rList);
520 				}
521 				if (range.empty()) return res;
522 			}
523 			s << "[" << range.cstr() << "]";
524 		}
525 		else if (type=="librevenge-cells")
526 		{
527 			librevenge::RVNGString ranges=convertCellsRange(list);
528 			if (ranges.empty()) ranges=convertRowOrColumnCellsRange(list); // check for columns or rows ranges
529 			if (ranges.empty()) return res;
530 			s << "[" << ranges.cstr() << "]";
531 		}
532 		else
533 		{
534 			ODFGEN_DEBUG_MSG(("SheetManager::convertFormula find unknown type %s!!!\n", type.c_str()));
535 			return res;
536 		}
537 	}
538 	return librevenge::RVNGString::escapeXML(s.str().c_str());
539 }
540 
convertCellRange(const librevenge::RVNGPropertyList & list)541 librevenge::RVNGString SheetManager::convertCellRange(const librevenge::RVNGPropertyList &list)
542 {
543 	std::stringstream s;
544 	librevenge::RVNGString res("");
545 	if (!list["librevenge:row"]||!list["librevenge:column"])
546 	{
547 		ODFGEN_DEBUG_MSG(("SheetManager::convertCellRange can not find cordinate!!!\n"));
548 		return res;
549 	}
550 	int column=list["librevenge:column"]->getInt();
551 	int row=list["librevenge:row"]->getInt();
552 	if (column<0 || row<0)
553 	{
554 		ODFGEN_DEBUG_MSG(("SheetManager::convertCellRange: find bad coordinate!!!\n"));
555 		return res;
556 	}
557 	if (list["librevenge:sheet-name"] || list["librevenge:sheet"])
558 	{
559 		if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
560 		if (list["librevenge:sheet-name"])
561 			s << list["librevenge:sheet-name"]->getStr().cstr();
562 		else
563 			s << list["librevenge:sheet"]->getStr().cstr();
564 	}
565 	s << ".";
566 	if (list["librevenge:column-absolute"] && list["librevenge:column-absolute"]->getInt()) s << "$";
567 	s << libodfgen::getColumnName(column);
568 	if (list["librevenge:row-absolute"] && list["librevenge:row-absolute"]->getInt()) s << "$";
569 	s << row+1;
570 	return s.str().c_str();
571 }
572 
convertRowOrColumnCellsRange(const librevenge::RVNGPropertyList & list)573 librevenge::RVNGString SheetManager::convertRowOrColumnCellsRange(const librevenge::RVNGPropertyList &list)
574 {
575 	std::stringstream s;
576 	librevenge::RVNGString res("");
577 	bool isColumn=true;
578 	if (list["librevenge:start-row"]) // check if this is a row ranges
579 	{
580 		if (!list["librevenge:end-row"] || list["librevenge:start-column"]) return res;
581 		isColumn=false;
582 	}
583 	else if (!list["librevenge:start-column"] || !list["librevenge:end-column"])
584 		return res;
585 	int dim1=list[isColumn ? "librevenge:start-column" : "librevenge:start-row"]->getInt();
586 	int dim2=list[isColumn ? "librevenge:end-column" : "librevenge:end-row"]->getInt();
587 	if (dim1<0 || dim2<dim1)
588 	{
589 		ODFGEN_DEBUG_MSG(("SheetManager::convertRowOrColumnCellsRange: find bad coordinates!!!\n"));
590 		return res;
591 	}
592 	if (list["librevenge:sheet-name"] || list["librevenge:start-sheet-name"])
593 	{
594 		if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
595 		if (list["librevenge:sheet-name"])
596 			s << list["librevenge:sheet-name"]->getStr().cstr();
597 		else
598 			s << list["librevenge:start-sheet-name"]->getStr().cstr();
599 	}
600 	s << ".";
601 	if (isColumn)
602 	{
603 		if (list["librevenge:start-column-absolute"] && list["librevenge:start-column-absolute"]->getInt()) s << "$";
604 		s << libodfgen::getColumnName(dim1);
605 		s << ":";
606 		if (list["librevenge:end-sheet-name"])
607 		{
608 			if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
609 			s << list["librevenge:end-sheet-name"]->getStr().cstr();
610 		}
611 		s << ".";
612 		if (list["librevenge:end-column-absolute"] && list["librevenge:end-column-absolute"]->getInt()) s << "$";
613 		s << libodfgen::getColumnName(dim2);
614 	}
615 	else
616 	{
617 		if (list["librevenge:start-row-absolute"] && list["librevenge:start-row-absolute"]->getInt()) s << "$";
618 		s << dim1+1 << ":";
619 		if (list["librevenge:end-sheet-name"])
620 		{
621 			if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
622 			s << list["librevenge:end-sheet-name"]->getStr().cstr();
623 		}
624 		s << ".";
625 		if (list["librevenge:end-row-absolute"] && list["librevenge:end-row-absolute"]->getInt()) s << "$";
626 		s << dim2+1;
627 	}
628 	return s.str().c_str();
629 }
630 
convertCellsRange(const librevenge::RVNGPropertyList & list)631 librevenge::RVNGString SheetManager::convertCellsRange(const librevenge::RVNGPropertyList &list)
632 {
633 	std::stringstream s;
634 	librevenge::RVNGString res("");
635 	if (!list["librevenge:start-row"]||!list["librevenge:start-column"])
636 	{
637 		ODFGEN_DEBUG_MSG(("SheetManager::convertCellsRange can not find cordinate!!!\n"));
638 		return res;
639 	}
640 	int column=list["librevenge:start-column"]->getInt();
641 	int row=list["librevenge:start-row"]->getInt();
642 	if (column<0 || row<0)
643 	{
644 		ODFGEN_DEBUG_MSG(("SheetManager::convertCellsRange: find bad coordinate1!!!\n"));
645 		return res;
646 	}
647 	if (list["librevenge:sheet-name"] || list["librevenge:start-sheet-name"])
648 	{
649 		if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
650 		if (list["librevenge:sheet-name"])
651 			s << list["librevenge:sheet-name"]->getStr().cstr();
652 		else
653 			s << list["librevenge:start-sheet-name"]->getStr().cstr();
654 	}
655 	s << ".";
656 	if (list["librevenge:start-column-absolute"] && list["librevenge:start-column-absolute"]->getInt()) s << "$";
657 	s << libodfgen::getColumnName(column);
658 	if (list["librevenge:start-row-absolute"] && list["librevenge:start-row-absolute"]->getInt()) s << "$";
659 	s << row+1 << ":";
660 	if (list["librevenge:end-sheet-name"])
661 	{
662 		if (list["librevenge:file-name"]) s << "'" << list["librevenge:file-name"]->getStr().cstr() << "'#";
663 		s << list["librevenge:end-sheet-name"]->getStr().cstr();
664 	}
665 	s << ".";
666 	if (list["librevenge:end-column"])
667 		column=list["librevenge:end-column"]->getInt();
668 	if (list["librevenge:end-row"])
669 		row=list["librevenge:end-row"]->getInt();
670 	if (column<0 || row<0)
671 	{
672 		ODFGEN_DEBUG_MSG(("SheetManager::convertCellsRange: find bad coordinate2!!!\n"));
673 		return res;
674 	}
675 	if (list["librevenge:end-column-absolute"] && list["librevenge:end-column-absolute"]->getInt()) s << "$";
676 	s << libodfgen::getColumnName(column);
677 	if (list["librevenge:end-row-absolute"] && list["librevenge:end-row-absolute"]->getInt()) s << "$";
678 	s << row+1;
679 	return s.str().c_str();
680 }
681 
write(OdfDocumentHandler * pHandler,Style::Zone zone) const682 void SheetManager::write(OdfDocumentHandler *pHandler, Style::Zone zone) const
683 {
684 	for (const auto &sheetStyle : mSheetStyles)
685 	{
686 		if (sheetStyle && sheetStyle->getZone()==zone)
687 			sheetStyle->writeStyle(pHandler, *this);
688 	}
689 }
690 
691 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
692