fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / oox / source / drawingml / diagram / diagram.cxx
blob5618be859e851940ce7fc2ef1ee9cbd394dec335
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <functional>
21 #include <boost/bind.hpp>
23 #include <com/sun/star/awt/Point.hpp>
24 #include <com/sun/star/awt/Size.hpp>
25 #include <com/sun/star/xml/dom/XDocument.hpp>
26 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
27 #include <rtl/ustrbuf.hxx>
28 #include <osl/diagnose.h>
29 #include <editeng/unoprnms.hxx>
30 #include "drawingml/textbody.hxx"
31 #include "drawingml/textparagraph.hxx"
32 #include "drawingml/textrun.hxx"
33 #include "drawingml/diagram/diagram.hxx"
34 #include "oox/drawingml/fillproperties.hxx"
35 #include "oox/ppt/pptshapegroupcontext.hxx"
36 #include "oox/ppt/pptshape.hxx"
38 #include "diagramlayoutatoms.hxx"
39 #include "diagramfragmenthandler.hxx"
41 #include <iostream>
42 #include <fstream>
44 using namespace ::com::sun::star;
46 namespace oox { namespace drawingml {
48 namespace dgm {
50 void Connection::dump()
52 SAL_INFO(
53 "oox.drawingml",
54 "cnx modelId " << msModelId << ", srcId " << msSourceId << ", dstId "
55 << msDestId << ", parTransId " << msParTransId << ", presId "
56 << msPresId << ", sibTransId " << msSibTransId << ", srcOrd "
57 << mnSourceOrder << ", dstOrd " << mnDestOrder);
60 void Point::dump()
62 SAL_INFO(
63 "oox.drawingml",
64 "pt text " << mpShape.get() << ", cnxId " << msCnxId << ", modelId "
65 << msModelId << ", type " << mnType);
68 } // dgm namespace
70 DiagramData::DiagramData()
71 : mpFillProperties( new FillProperties )
75 void DiagramData::dump()
77 OSL_TRACE("Dgm: DiagramData # of cnx: %zu", maConnections.size() );
78 std::for_each( maConnections.begin(), maConnections.end(),
79 boost::bind( &dgm::Connection::dump, _1 ) );
80 OSL_TRACE("Dgm: DiagramData # of pt: %zu", maPoints.size() );
81 std::for_each( maPoints.begin(), maPoints.end(),
82 boost::bind( &dgm::Point::dump, _1 ) );
85 void Diagram::setData( const DiagramDataPtr & pData)
87 mpData = pData;
90 void Diagram::setLayout( const DiagramLayoutPtr & pLayout)
92 mpLayout = pLayout;
95 #if OSL_DEBUG_LEVEL > 1
96 OString normalizeDotName( const OUString& rStr )
98 OUStringBuffer aBuf;
99 aBuf.append('N');
101 const sal_Int32 nLen(rStr.getLength());
102 sal_Int32 nCurrIndex(0);
103 while( nCurrIndex < nLen )
105 const sal_Int32 aChar=rStr.iterateCodePoints(&nCurrIndex);
106 if( aChar != '-' && aChar != '{' && aChar != '}' )
107 aBuf.append((sal_Unicode)aChar);
110 return OUStringToOString(aBuf.makeStringAndClear(),
111 RTL_TEXTENCODING_UTF8);
113 #endif
115 static sal_Int32 calcDepth( const OUString& rNodeName,
116 const dgm::Connections& rCnx )
118 // find length of longest path in 'isChild' graph, ending with rNodeName
119 dgm::Connections::const_iterator aCurrCxn( rCnx.begin() );
120 const dgm::Connections::const_iterator aEndCxn( rCnx.end() );
121 while( aCurrCxn != aEndCxn )
123 if( !aCurrCxn->msParTransId.isEmpty() &&
124 !aCurrCxn->msSibTransId.isEmpty() &&
125 !aCurrCxn->msSourceId.isEmpty() &&
126 !aCurrCxn->msDestId.isEmpty() &&
127 aCurrCxn->mnType != XML_presOf &&
128 aCurrCxn->mnType != XML_presParOf &&
129 rNodeName == aCurrCxn->msDestId )
131 return calcDepth(aCurrCxn->msSourceId,
132 rCnx) + 1;
134 ++aCurrCxn;
137 return 0;
140 void Diagram::build( )
142 // build name-object maps
144 #if OSL_DEBUG_LEVEL > 1
145 std::ofstream output("/tmp/tree.dot");
147 output << "digraph datatree {" << std::endl;
148 #endif
150 dgm::Points& rPoints = getData()->getPoints();
151 dgm::Points::iterator aCurrPoint(rPoints.begin());
152 dgm::Points::iterator aEndPoint(rPoints.end());
153 while( aCurrPoint != aEndPoint )
155 #if OSL_DEBUG_LEVEL > 1
156 output << "\t"
157 << normalizeDotName(aCurrPoint->msModelId).getStr()
158 << "[";
160 if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
161 output << "label=\""
162 << OUStringToOString(
163 aCurrPoint->msPresentationLayoutName,
164 RTL_TEXTENCODING_UTF8).getStr() << "\", ";
165 else
166 output << "label=\""
167 << OUStringToOString(
168 aCurrPoint->msModelId,
169 RTL_TEXTENCODING_UTF8).getStr() << "\", ";
171 switch( aCurrPoint->mnType )
173 case XML_doc: output << "style=filled, color=red"; break;
174 case XML_asst: output << "style=filled, color=green"; break;
175 default:
176 case XML_node: output << "style=filled, color=blue"; break;
177 case XML_pres: output << "style=filled, color=yellow"; break;
178 case XML_parTrans: output << "color=grey"; break;
179 case XML_sibTrans: output << " "; break;
182 output << "];" << std::endl;
184 // does currpoint have any text set?
185 if( aCurrPoint->mpShape &&
186 aCurrPoint->mpShape->getTextBody() &&
187 !aCurrPoint->mpShape->getTextBody()->getParagraphs().empty() &&
188 !aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().empty() )
190 static sal_Int32 nCount=0;
192 output << "\t"
193 << "textNode" << nCount
194 << " ["
195 << "label=\""
196 << OUStringToOString(
197 aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()->getText(),
198 RTL_TEXTENCODING_UTF8).getStr()
199 << "\"" << "];" << std::endl;
200 output << "\t"
201 << normalizeDotName(aCurrPoint->msModelId).getStr()
202 << " -> "
203 << "textNode" << nCount++
204 << ";" << std::endl;
206 #endif
208 const bool bInserted1=getData()->getPointNameMap().insert(
209 std::make_pair(aCurrPoint->msModelId,&(*aCurrPoint))).second;
210 (void)bInserted1;
212 OSL_ENSURE(bInserted1,"Diagram::build(): non-unique point model id");
214 if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
216 DiagramData::PointsNameMap::value_type::second_type& rVec=
217 getData()->getPointsPresNameMap()[aCurrPoint->msPresentationLayoutName];
218 rVec.push_back(&(*aCurrPoint));
220 ++aCurrPoint;
223 const dgm::Connections& rConnections = getData()->getConnections();
224 dgm::Connections::const_iterator aCurrCxn(rConnections.begin());
225 const dgm::Connections::const_iterator aEndCxn(rConnections.end());
226 while( aCurrCxn != aEndCxn )
228 #if OSL_DEBUG_LEVEL > 1
229 if( !aCurrCxn->msParTransId.isEmpty() ||
230 !aCurrCxn->msSibTransId.isEmpty() )
232 if( !aCurrCxn->msSourceId.isEmpty() ||
233 !aCurrCxn->msDestId.isEmpty() )
235 output << "\t"
236 << normalizeDotName(aCurrCxn->msSourceId).getStr()
237 << " -> "
238 << normalizeDotName(aCurrCxn->msParTransId).getStr()
239 << " -> "
240 << normalizeDotName(aCurrCxn->msSibTransId).getStr()
241 << " -> "
242 << normalizeDotName(aCurrCxn->msDestId).getStr()
243 << " [style=dotted,"
244 << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
245 << "label=\""
246 << OUStringToOString(aCurrCxn->msModelId,
247 RTL_TEXTENCODING_UTF8 ).getStr()
248 << "\"];" << std::endl;
250 else
252 output << "\t"
253 << normalizeDotName(aCurrCxn->msParTransId).getStr()
254 << " -> "
255 << normalizeDotName(aCurrCxn->msSibTransId).getStr()
256 << " ["
257 << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
258 << "label=\""
259 << OUStringToOString(aCurrCxn->msModelId,
260 RTL_TEXTENCODING_UTF8 ).getStr()
261 << "\"];" << std::endl;
264 else if( !aCurrCxn->msSourceId.isEmpty() ||
265 !aCurrCxn->msDestId.isEmpty() )
266 output << "\t"
267 << normalizeDotName(aCurrCxn->msSourceId).getStr()
268 << " -> "
269 << normalizeDotName(aCurrCxn->msDestId).getStr()
270 << " [label=\""
271 << OUStringToOString(aCurrCxn->msModelId,
272 RTL_TEXTENCODING_UTF8 ).getStr()
273 << ((aCurrCxn->mnType == XML_presOf) ? "\", color=red]" : ((aCurrCxn->mnType == XML_presParOf) ? "\", color=green]" : "\"]"))
274 << ";" << std::endl;
275 #endif
277 const bool bInserted1=getData()->getConnectionNameMap().insert(
278 std::make_pair(aCurrCxn->msModelId,&(*aCurrCxn))).second;
279 (void)bInserted1;
281 OSL_ENSURE(bInserted1,"Diagram::build(): non-unique connection model id");
283 if( aCurrCxn->mnType == XML_presOf )
285 DiagramData::StringMap::value_type::second_type& rVec=getData()->getPresOfNameMap()[aCurrCxn->msDestId];
286 rVec.push_back(
287 std::make_pair(
288 aCurrCxn->msSourceId,sal_Int32(0)));
291 ++aCurrCxn;
294 // assign outline levels
295 DiagramData::StringMap& rStringMap = getData()->getPresOfNameMap();
296 DiagramData::StringMap::iterator aPresOfIter=rStringMap.begin();
297 const DiagramData::StringMap::iterator aPresOfEnd=rStringMap.end();
298 while( aPresOfIter != aPresOfEnd )
300 DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeIterCalcLevel=aPresOfIter->second.begin();
301 const DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeEnd=aPresOfIter->second.end();
302 while(aPresOfNodeIterCalcLevel != aPresOfNodeEnd)
304 const sal_Int32 nDepth=calcDepth(aPresOfNodeIterCalcLevel->first,
305 getData()->getConnections());
306 aPresOfNodeIterCalcLevel->second = nDepth != 0 ? nDepth : -1;
307 ++aPresOfNodeIterCalcLevel;
310 ++aPresOfIter;
313 #if OSL_DEBUG_LEVEL > 1
314 output << "}" << std::endl;
315 #endif
318 void Diagram::addTo( const ShapePtr & pParentShape )
320 // collect data, init maps
321 build( );
323 // create Shape hierarchy
324 ShapeCreationVisitor aCreationVisitor(pParentShape, *this);
325 if( mpLayout->getNode() )
326 mpLayout->getNode()->accept( aCreationVisitor );
328 pParentShape->setDiagramDoms( getDomsAsPropertyValues() );
331 uno::Sequence<beans::PropertyValue> Diagram::getDomsAsPropertyValues() const
333 sal_Int32 length = maMainDomMap.size();
335 if ( 0 < maDataRelsMap.getLength() )
336 ++length;
338 uno::Sequence<beans::PropertyValue> aValue(length);
339 beans::PropertyValue* pValue = aValue.getArray();
340 for (DiagramDomMap::const_iterator i = maMainDomMap.begin();
341 i != maMainDomMap.end();
342 ++i)
344 pValue[0].Name = i->first;
345 pValue[0].Value = uno::makeAny(i->second);
346 ++pValue;
349 if ( 0 < maDataRelsMap.getLength() )
351 pValue[0].Name = "OOXDiagramDataRels";
352 pValue[0].Value = uno::makeAny ( maDataRelsMap );
353 ++pValue;
356 return aValue;
359 uno::Reference<xml::dom::XDocument> loadFragment(
360 core::XmlFilterBase& rFilter,
361 const OUString& rFragmentPath )
363 // load diagramming fragments into DOM representation, that later
364 // gets serialized back to SAX events and parsed
365 return rFilter.importFragment( rFragmentPath );
368 uno::Reference<xml::dom::XDocument> loadFragment(
369 core::XmlFilterBase& rFilter,
370 const rtl::Reference< core::FragmentHandler >& rxHandler )
372 return loadFragment( rFilter, rxHandler->getFragmentPath() );
375 void importFragment( core::XmlFilterBase& rFilter,
376 const uno::Reference<xml::dom::XDocument>& rXDom,
377 const char* pDocName,
378 const DiagramPtr& pDiagram,
379 const rtl::Reference< core::FragmentHandler >& rxHandler )
381 DiagramDomMap& rMainDomMap = pDiagram->getDomMap();
382 rMainDomMap[OUString::createFromAscii(pDocName)] = rXDom;
384 uno::Reference<xml::sax::XFastSAXSerializable> xSerializer(
385 rXDom, uno::UNO_QUERY_THROW);
387 // now serialize DOM tree into internal data structures
388 rFilter.importFragment( rxHandler, xSerializer );
391 void loadDiagram( ShapePtr& pShape,
392 core::XmlFilterBase& rFilter,
393 const OUString& rDataModelPath,
394 const OUString& rLayoutPath,
395 const OUString& rQStylePath,
396 const OUString& rColorStylePath )
398 DiagramPtr pDiagram( new Diagram() );
400 DiagramDataPtr pData( new DiagramData() );
401 pDiagram->setData( pData );
403 DiagramLayoutPtr pLayout( new DiagramLayout() );
404 pDiagram->setLayout( pLayout );
406 // data
407 if( !rDataModelPath.isEmpty() )
409 rtl::Reference< core::FragmentHandler > xRefDataModel(
410 new DiagramDataFragmentHandler( rFilter, rDataModelPath, pData ));
412 importFragment(rFilter,
413 loadFragment(rFilter,xRefDataModel),
414 "OOXData",
415 pDiagram,
416 xRefDataModel);
418 pDiagram->getDataRelsMap() = pShape->resolveRelationshipsOfTypeFromOfficeDoc( rFilter,
419 xRefDataModel->getFragmentPath(), "image" );
421 // Pass the info to pShape
422 for( ::std::vector<OUString>::const_iterator aIt = pData->getExtDrawings().begin(), aEnd = pData->getExtDrawings().end();
423 aIt != aEnd; ++aIt )
424 pShape->addExtDrawingRelId( *aIt );
427 // extLst is present, lets bet on that and ignore the rest of the data from here
428 if( pData->getExtDrawings().empty() )
430 // layout
431 if( !rLayoutPath.isEmpty() )
433 rtl::Reference< core::FragmentHandler > xRefLayout(
434 new DiagramLayoutFragmentHandler( rFilter, rLayoutPath, pLayout ));
436 importFragment(rFilter,
437 loadFragment(rFilter,xRefLayout),
438 "OOXLayout",
439 pDiagram,
440 xRefLayout);
443 // style
444 if( !rQStylePath.isEmpty() )
446 rtl::Reference< core::FragmentHandler > xRefQStyle(
447 new DiagramQStylesFragmentHandler( rFilter, rQStylePath, pDiagram->getStyles() ));
449 importFragment(rFilter,
450 loadFragment(rFilter,xRefQStyle),
451 "OOXStyle",
452 pDiagram,
453 xRefQStyle);
455 } else {
456 // We still want to add the XDocuments to the DiagramDomMap
457 DiagramDomMap& rMainDomMap = pDiagram->getDomMap();
458 rMainDomMap[OUString("OOXLayout")] = loadFragment(rFilter,rLayoutPath);
459 rMainDomMap[OUString("OOXStyle")] = loadFragment(rFilter,rQStylePath);
462 // colors
463 if( !rColorStylePath.isEmpty() )
465 rtl::Reference< core::FragmentHandler > xRefColorStyle(
466 new ColorFragmentHandler( rFilter, rColorStylePath, pDiagram->getColors() ));
468 importFragment(rFilter,
469 loadFragment(rFilter,xRefColorStyle),
470 "OOXColor",
471 pDiagram,
472 xRefColorStyle);
475 if( !pData->getExtDrawings().empty() )
477 const DiagramColorMap::const_iterator aColor = pDiagram->getColors().find("node0");
478 if( aColor != pDiagram->getColors().end() )
480 pShape->setFontRefColorForNodes(aColor->second.maTextFillColor);
484 // diagram loaded. now lump together & attach to shape
485 pDiagram->addTo(pShape);
488 void loadDiagram( const ShapePtr& pShape,
489 core::XmlFilterBase& rFilter,
490 const uno::Reference<xml::dom::XDocument>& rXDataModelDom,
491 const uno::Reference<xml::dom::XDocument>& rXLayoutDom,
492 const uno::Reference<xml::dom::XDocument>& rXQStyleDom,
493 const uno::Reference<xml::dom::XDocument>& rXColorStyleDom )
495 DiagramPtr pDiagram( new Diagram() );
497 DiagramDataPtr pData( new DiagramData() );
498 pDiagram->setData( pData );
500 DiagramLayoutPtr pLayout( new DiagramLayout() );
501 pDiagram->setLayout( pLayout );
503 OUString aEmpty;
505 // data
506 if( rXDataModelDom.is() )
507 importFragment(rFilter,
508 rXDataModelDom,
509 "OOXData",
510 pDiagram,
511 new DiagramDataFragmentHandler( rFilter, aEmpty, pData ));
513 // layout
514 if( rXLayoutDom.is() )
515 importFragment(rFilter,
516 rXLayoutDom,
517 "OOXLayout",
518 pDiagram,
519 new DiagramLayoutFragmentHandler( rFilter, aEmpty, pLayout ));
521 // style
522 if( rXQStyleDom.is() )
523 importFragment(rFilter,
524 rXQStyleDom,
525 "OOXStyle",
526 pDiagram,
527 new DiagramQStylesFragmentHandler( rFilter, aEmpty, pDiagram->getStyles() ));
529 // colors
530 if( rXColorStyleDom.is() )
531 importFragment(rFilter,
532 rXColorStyleDom,
533 "OOXColor",
534 pDiagram,
535 new ColorFragmentHandler( rFilter, aEmpty, pDiagram->getColors() ));
537 // diagram loaded. now lump together & attach to shape
538 pDiagram->addTo(pShape);
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */