1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <boost/bind.hpp>
24 #include <com/sun/star/awt/Point.hpp>
25 #include <com/sun/star/awt/Size.hpp>
26 #include <com/sun/star/xml/dom/XDocument.hpp>
27 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
28 #include <rtl/ustrbuf.hxx>
29 #include "oox/drawingml/textbody.hxx"
30 #include "oox/drawingml/textparagraph.hxx"
31 #include "oox/drawingml/textrun.hxx"
32 #include "oox/drawingml/diagram/diagram.hxx"
33 #include "oox/drawingml/fillproperties.hxx"
34 #include "oox/ppt/pptshapegroupcontext.hxx"
35 #include "oox/ppt/pptshape.hxx"
37 #include "diagramlayoutatoms.hxx"
38 #include "diagramfragmenthandler.hxx"
43 using namespace ::com::sun::star
;
45 namespace oox
{ namespace drawingml
{
49 void Connection::dump()
51 OSL_TRACE("dgm: cnx modelId %s, srcId %s, dstId %s, parTransId %s, presId %s, sibTransId %s, srcOrd %d, dstOrd %d",
52 OUSTRING_TO_CSTR( msModelId
),
53 OUSTRING_TO_CSTR( msSourceId
),
54 OUSTRING_TO_CSTR( msDestId
),
55 OUSTRING_TO_CSTR( msParTransId
),
56 OUSTRING_TO_CSTR( msPresId
),
57 OUSTRING_TO_CSTR( msSibTransId
),
64 OSL_TRACE( "dgm: pt text %x, cnxId %s, modelId %s, type %d",
66 OUSTRING_TO_CSTR( msCnxId
),
67 OUSTRING_TO_CSTR( msModelId
),
73 DiagramData::DiagramData()
74 : mpFillProperties( new FillProperties
)
78 void DiagramData::dump()
80 OSL_TRACE("Dgm: DiagramData # of cnx: %d", maConnections
.size() );
81 std::for_each( maConnections
.begin(), maConnections
.end(),
82 boost::bind( &dgm::Connection::dump
, _1
) );
83 OSL_TRACE("Dgm: DiagramData # of pt: %d", maPoints
.size() );
84 std::for_each( maPoints
.begin(), maPoints
.end(),
85 boost::bind( &dgm::Point::dump
, _1
) );
89 void Diagram::setData( const DiagramDataPtr
& pData
)
95 void Diagram::setLayout( const DiagramLayoutPtr
& pLayout
)
100 #if OSL_DEBUG_LEVEL > 1
101 OString
normalizeDotName( const OUString
& rStr
)
104 aBuf
.append((sal_Unicode
)'N');
106 const sal_Int32
nLen(rStr
.getLength());
107 sal_Int32
nCurrIndex(0);
108 while( nCurrIndex
< nLen
)
110 const sal_Int32 aChar
=rStr
.iterateCodePoints(&nCurrIndex
);
111 if( aChar
!= '-' && aChar
!= '{' && aChar
!= '}' )
112 aBuf
.append((sal_Unicode
)aChar
);
115 return OUStringToOString(aBuf
.makeStringAndClear(),
116 RTL_TEXTENCODING_UTF8
);
120 static sal_Int32
calcDepth( const OUString
& rNodeName
,
121 const dgm::Connections
& rCnx
)
123 // find length of longest path in 'isChild' graph, ending with rNodeName
124 dgm::Connections::const_iterator
aCurrCxn( rCnx
.begin() );
125 const dgm::Connections::const_iterator
aEndCxn( rCnx
.end() );
126 while( aCurrCxn
!= aEndCxn
)
128 if( !aCurrCxn
->msParTransId
.isEmpty() &&
129 !aCurrCxn
->msSibTransId
.isEmpty() &&
130 !aCurrCxn
->msSourceId
.isEmpty() &&
131 !aCurrCxn
->msDestId
.isEmpty() &&
132 aCurrCxn
->mnType
!= XML_presOf
&&
133 aCurrCxn
->mnType
!= XML_presParOf
&&
134 rNodeName
== aCurrCxn
->msDestId
)
136 return calcDepth(aCurrCxn
->msSourceId
,
146 void Diagram::build( )
148 // build name-object maps
149 // ======================
151 #if OSL_DEBUG_LEVEL > 1
152 std::ofstream
output("/tmp/tree.dot");
154 output
<< "digraph datatree {" << std::endl
;
157 dgm::Points::iterator
aCurrPoint( getData()->getPoints( ).begin() );
158 const dgm::Points::iterator
aEndPoint( getData()->getPoints( ).end() );
159 while( aCurrPoint
!= aEndPoint
)
161 #if OSL_DEBUG_LEVEL > 1
163 << normalizeDotName(aCurrPoint
->msModelId
).getStr()
166 if( !aCurrPoint
->msPresentationLayoutName
.isEmpty() )
168 << OUStringToOString(
169 aCurrPoint
->msPresentationLayoutName
,
170 RTL_TEXTENCODING_UTF8
).getStr() << "\", ";
173 << OUStringToOString(
174 aCurrPoint
->msModelId
,
175 RTL_TEXTENCODING_UTF8
).getStr() << "\", ";
177 switch( aCurrPoint
->mnType
)
179 case XML_doc
: output
<< "style=filled, color=red"; break;
180 case XML_asst
: output
<< "style=filled, color=green"; break;
182 case XML_node
: output
<< "style=filled, color=blue"; break;
183 case XML_pres
: output
<< "style=filled, color=yellow"; break;
184 case XML_parTrans
: output
<< "color=grey"; break;
185 case XML_sibTrans
: output
<< " "; break;
188 output
<< "];" << std::endl
;
190 // does currpoint have any text set?
191 if( aCurrPoint
->mpShape
&&
192 aCurrPoint
->mpShape
->getTextBody() &&
193 !aCurrPoint
->mpShape
->getTextBody()->getParagraphs().empty() &&
194 !aCurrPoint
->mpShape
->getTextBody()->getParagraphs().front()->getRuns().empty() )
196 static sal_Int32 nCount
=0;
199 << "textNode" << nCount
202 << OUStringToOString(
203 aCurrPoint
->mpShape
->getTextBody()->getParagraphs().front()->getRuns().front()->getText(),
204 RTL_TEXTENCODING_UTF8
).getStr()
205 << "\"" << "];" << std::endl
;
207 << normalizeDotName(aCurrPoint
->msModelId
).getStr()
209 << "textNode" << nCount
++
214 const bool bInserted1
=getData()->getPointNameMap().insert(
215 std::make_pair(aCurrPoint
->msModelId
,&(*aCurrPoint
))).second
;
218 OSL_ENSURE(bInserted1
,"Diagram::build(): non-unique point model id");
220 if( !aCurrPoint
->msPresentationLayoutName
.isEmpty() )
222 DiagramData::PointsNameMap::value_type::second_type
& rVec
=
223 getData()->getPointsPresNameMap()[aCurrPoint
->msPresentationLayoutName
];
224 rVec
.push_back(&(*aCurrPoint
));
229 dgm::Connections::const_iterator
aCurrCxn( getData()->getConnections( ).begin() );
230 const dgm::Connections::const_iterator
aEndCxn( getData()->getConnections( ).end() );
231 while( aCurrCxn
!= aEndCxn
)
233 #if OSL_DEBUG_LEVEL > 1
234 if( !aCurrCxn
->msParTransId
.isEmpty() ||
235 !aCurrCxn
->msSibTransId
.isEmpty() )
237 if( !aCurrCxn
->msSourceId
.isEmpty() ||
238 !aCurrCxn
->msDestId
.isEmpty() )
241 << normalizeDotName(aCurrCxn
->msSourceId
).getStr()
243 << normalizeDotName(aCurrCxn
->msParTransId
).getStr()
245 << normalizeDotName(aCurrCxn
->msSibTransId
).getStr()
247 << normalizeDotName(aCurrCxn
->msDestId
).getStr()
249 << ((aCurrCxn
->mnType
== XML_presOf
) ? " color=red, " : ((aCurrCxn
->mnType
== XML_presParOf
) ? " color=green, " : " "))
251 << OUStringToOString(aCurrCxn
->msModelId
,
252 RTL_TEXTENCODING_UTF8
).getStr()
253 << "\"];" << std::endl
;
258 << normalizeDotName(aCurrCxn
->msParTransId
).getStr()
260 << normalizeDotName(aCurrCxn
->msSibTransId
).getStr()
262 << ((aCurrCxn
->mnType
== XML_presOf
) ? " color=red, " : ((aCurrCxn
->mnType
== XML_presParOf
) ? " color=green, " : " "))
264 << OUStringToOString(aCurrCxn
->msModelId
,
265 RTL_TEXTENCODING_UTF8
).getStr()
266 << "\"];" << std::endl
;
269 else if( !aCurrCxn
->msSourceId
.isEmpty() ||
270 !aCurrCxn
->msDestId
.isEmpty() )
272 << normalizeDotName(aCurrCxn
->msSourceId
).getStr()
274 << normalizeDotName(aCurrCxn
->msDestId
).getStr()
276 << OUStringToOString(aCurrCxn
->msModelId
,
277 RTL_TEXTENCODING_UTF8
).getStr()
278 << ((aCurrCxn
->mnType
== XML_presOf
) ? "\", color=red]" : ((aCurrCxn
->mnType
== XML_presParOf
) ? "\", color=green]" : "\"]"))
282 const bool bInserted1
=getData()->getConnectionNameMap().insert(
283 std::make_pair(aCurrCxn
->msModelId
,&(*aCurrCxn
))).second
;
286 OSL_ENSURE(bInserted1
,"Diagram::build(): non-unique connection model id");
288 if( aCurrCxn
->mnType
== XML_presOf
)
290 DiagramData::StringMap::value_type::second_type
& rVec
=getData()->getPresOfNameMap()[aCurrCxn
->msDestId
];
293 aCurrCxn
->msSourceId
,sal_Int32(0)));
299 // assign outline levels
300 DiagramData::StringMap::iterator aPresOfIter
=getData()->getPresOfNameMap().begin();
301 const DiagramData::StringMap::iterator aPresOfEnd
=getData()->getPresOfNameMap().end();
302 while( aPresOfIter
!= aPresOfEnd
)
304 DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeIterCalcLevel
=aPresOfIter
->second
.begin();
305 const DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeEnd
=aPresOfIter
->second
.end();
306 while(aPresOfNodeIterCalcLevel
!= aPresOfNodeEnd
)
308 const sal_Int32 nDepth
=calcDepth(aPresOfNodeIterCalcLevel
->first
,
309 getData()->getConnections());
310 aPresOfNodeIterCalcLevel
->second
= nDepth
!= 0 ? nDepth
: -1;
311 ++aPresOfNodeIterCalcLevel
;
317 #if OSL_DEBUG_LEVEL > 1
318 output
<< "}" << std::endl
;
323 void Diagram::addTo( const ShapePtr
& pParentShape
)
325 // collect data, init maps
328 // create Shape hierarchy
329 ShapeCreationVisitor
aCreationVisitor(pParentShape
, *this);
330 if( mpLayout
->getNode() )
331 mpLayout
->getNode()->accept( aCreationVisitor
);
334 uno::Reference
<xml::dom::XDocument
> loadFragment(
335 core::XmlFilterBase
& rFilter
,
336 const rtl::Reference
< core::FragmentHandler
>& rxHandler
)
338 // load diagramming fragments into DOM representation, that later
339 // gets serialized back to SAX events and parsed
340 return rFilter
.importFragment( rxHandler
->getFragmentPath() );
343 void importFragment( core::XmlFilterBase
& rFilter
,
344 const uno::Reference
<xml::dom::XDocument
>& rXDom
,
345 const char* /*pPropName*/,
346 const ShapePtr
& /*pShape*/,
347 const rtl::Reference
< core::FragmentHandler
>& rxHandler
)
349 uno::Reference
<xml::sax::XFastSAXSerializable
> xSerializer(
350 rXDom
, uno::UNO_QUERY_THROW
);
352 // now serialize DOM tree into internal data structures
353 rFilter
.importFragment( rxHandler
, xSerializer
);
356 void loadDiagram( ShapePtr
& pShape
,
357 core::XmlFilterBase
& rFilter
,
358 const OUString
& rDataModelPath
,
359 const OUString
& rLayoutPath
,
360 const OUString
& rQStylePath
,
361 const OUString
& rColorStylePath
)
363 DiagramPtr
pDiagram( new Diagram() );
365 DiagramDataPtr
pData( new DiagramData() );
366 pDiagram
->setData( pData
);
368 DiagramLayoutPtr
pLayout( new DiagramLayout() );
369 pDiagram
->setLayout( pLayout
);
372 if( !rDataModelPath
.isEmpty() )
374 rtl::Reference
< core::FragmentHandler
> xRef(
375 new DiagramDataFragmentHandler( rFilter
, rDataModelPath
, pData
));
377 importFragment(rFilter
,
378 loadFragment(rFilter
,xRef
),
382 // Pass the info to pShape
383 for( ::std::vector
<OUString
>::const_iterator aIt
= pData
->getExtDrawings().begin(), aEnd
= pData
->getExtDrawings().end();
385 pShape
->addExtDrawingRelId( *aIt
);
388 // extLst is present, lets bet on that and ignore the rest of the data from here
389 if( !pData
->getExtDrawings().size() )
392 if( !rLayoutPath
.isEmpty() )
394 rtl::Reference
< core::FragmentHandler
> xRef(
395 new DiagramLayoutFragmentHandler( rFilter
, rLayoutPath
, pLayout
));
396 importFragment(rFilter
,
397 loadFragment(rFilter
,xRef
),
404 if( !rQStylePath
.isEmpty() )
406 rtl::Reference
< core::FragmentHandler
> xRef(
407 new DiagramQStylesFragmentHandler( rFilter
, rQStylePath
, pDiagram
->getStyles() ));
408 importFragment(rFilter
,
409 loadFragment(rFilter
,xRef
),
416 if( !rColorStylePath
.isEmpty() )
418 rtl::Reference
< core::FragmentHandler
> xRef(
419 new ColorFragmentHandler( rFilter
, rColorStylePath
, pDiagram
->getColors() ));
420 importFragment(rFilter
,
421 loadFragment(rFilter
,xRef
),
428 // diagram loaded. now lump together & attach to shape
429 pDiagram
->addTo(pShape
);
432 void loadDiagram( const ShapePtr
& pShape
,
433 core::XmlFilterBase
& rFilter
,
434 const uno::Reference
<xml::dom::XDocument
>& rXDataModelDom
,
435 const uno::Reference
<xml::dom::XDocument
>& rXLayoutDom
,
436 const uno::Reference
<xml::dom::XDocument
>& rXQStyleDom
,
437 const uno::Reference
<xml::dom::XDocument
>& rXColorStyleDom
)
439 DiagramPtr
pDiagram( new Diagram() );
441 DiagramDataPtr
pData( new DiagramData() );
442 pDiagram
->setData( pData
);
444 DiagramLayoutPtr
pLayout( new DiagramLayout() );
445 pDiagram
->setLayout( pLayout
);
450 if( rXDataModelDom
.is() )
451 importFragment(rFilter
,
455 new DiagramDataFragmentHandler( rFilter
, aEmpty
, pData
));
458 if( rXLayoutDom
.is() )
459 importFragment(rFilter
,
463 new DiagramLayoutFragmentHandler( rFilter
, aEmpty
, pLayout
));
466 if( rXQStyleDom
.is() )
467 importFragment(rFilter
,
471 new DiagramQStylesFragmentHandler( rFilter
, aEmpty
, pDiagram
->getStyles() ));
474 if( rXColorStyleDom
.is() )
475 importFragment(rFilter
,
479 new ColorFragmentHandler( rFilter
, aEmpty
, pDiagram
->getColors() ));
481 // diagram loaded. now lump together & attach to shape
482 pDiagram
->addTo(pShape
);
487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */