fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / oox / source / drawingml / diagram / diagram.cxx
blob0b7ab560696e0ef4c45400bebd4931b1d333aaff
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 .
21 #include <functional>
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"
40 #include <iostream>
41 #include <fstream>
43 using namespace ::com::sun::star;
45 namespace oox { namespace drawingml {
47 namespace dgm {
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 ),
58 mnSourceOrder,
59 mnDestOrder );
62 void Point::dump()
64 OSL_TRACE( "dgm: pt text %x, cnxId %s, modelId %s, type %d",
65 mpShape.get(),
66 OUSTRING_TO_CSTR( msCnxId ),
67 OUSTRING_TO_CSTR( msModelId ),
68 mnType );
71 } // dgm namespace
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)
91 mpData = pData;
95 void Diagram::setLayout( const DiagramLayoutPtr & pLayout)
97 mpLayout = pLayout;
100 #if OSL_DEBUG_LEVEL > 1
101 OString normalizeDotName( const OUString& rStr )
103 OUStringBuffer aBuf;
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);
118 #endif
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,
137 rCnx) + 1;
139 ++aCurrCxn;
142 return 0;
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;
155 #endif
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
162 output << "\t"
163 << normalizeDotName(aCurrPoint->msModelId).getStr()
164 << "[";
166 if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
167 output << "label=\""
168 << OUStringToOString(
169 aCurrPoint->msPresentationLayoutName,
170 RTL_TEXTENCODING_UTF8).getStr() << "\", ";
171 else
172 output << "label=\""
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;
181 default:
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;
198 output << "\t"
199 << "textNode" << nCount
200 << " ["
201 << "label=\""
202 << OUStringToOString(
203 aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()->getText(),
204 RTL_TEXTENCODING_UTF8).getStr()
205 << "\"" << "];" << std::endl;
206 output << "\t"
207 << normalizeDotName(aCurrPoint->msModelId).getStr()
208 << " -> "
209 << "textNode" << nCount++
210 << ";" << std::endl;
212 #endif
214 const bool bInserted1=getData()->getPointNameMap().insert(
215 std::make_pair(aCurrPoint->msModelId,&(*aCurrPoint))).second;
216 (void)bInserted1;
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));
226 ++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() )
240 output << "\t"
241 << normalizeDotName(aCurrCxn->msSourceId).getStr()
242 << " -> "
243 << normalizeDotName(aCurrCxn->msParTransId).getStr()
244 << " -> "
245 << normalizeDotName(aCurrCxn->msSibTransId).getStr()
246 << " -> "
247 << normalizeDotName(aCurrCxn->msDestId).getStr()
248 << " [style=dotted,"
249 << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
250 << "label=\""
251 << OUStringToOString(aCurrCxn->msModelId,
252 RTL_TEXTENCODING_UTF8 ).getStr()
253 << "\"];" << std::endl;
255 else
257 output << "\t"
258 << normalizeDotName(aCurrCxn->msParTransId).getStr()
259 << " -> "
260 << normalizeDotName(aCurrCxn->msSibTransId).getStr()
261 << " ["
262 << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
263 << "label=\""
264 << OUStringToOString(aCurrCxn->msModelId,
265 RTL_TEXTENCODING_UTF8 ).getStr()
266 << "\"];" << std::endl;
269 else if( !aCurrCxn->msSourceId.isEmpty() ||
270 !aCurrCxn->msDestId.isEmpty() )
271 output << "\t"
272 << normalizeDotName(aCurrCxn->msSourceId).getStr()
273 << " -> "
274 << normalizeDotName(aCurrCxn->msDestId).getStr()
275 << " [label=\""
276 << OUStringToOString(aCurrCxn->msModelId,
277 RTL_TEXTENCODING_UTF8 ).getStr()
278 << ((aCurrCxn->mnType == XML_presOf) ? "\", color=red]" : ((aCurrCxn->mnType == XML_presParOf) ? "\", color=green]" : "\"]"))
279 << ";" << std::endl;
280 #endif
282 const bool bInserted1=getData()->getConnectionNameMap().insert(
283 std::make_pair(aCurrCxn->msModelId,&(*aCurrCxn))).second;
284 (void)bInserted1;
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];
291 rVec.push_back(
292 std::make_pair(
293 aCurrCxn->msSourceId,sal_Int32(0)));
296 ++aCurrCxn;
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;
314 ++aPresOfIter;
317 #if OSL_DEBUG_LEVEL > 1
318 output << "}" << std::endl;
319 #endif
323 void Diagram::addTo( const ShapePtr & pParentShape )
325 // collect data, init maps
326 build( );
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 );
371 // data
372 if( !rDataModelPath.isEmpty() )
374 rtl::Reference< core::FragmentHandler > xRef(
375 new DiagramDataFragmentHandler( rFilter, rDataModelPath, pData ));
377 importFragment(rFilter,
378 loadFragment(rFilter,xRef),
379 "DiagramData",
380 pShape,
381 xRef);
382 // Pass the info to pShape
383 for( ::std::vector<OUString>::const_iterator aIt = pData->getExtDrawings().begin(), aEnd = pData->getExtDrawings().end();
384 aIt != aEnd; ++aIt )
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() )
391 // layout
392 if( !rLayoutPath.isEmpty() )
394 rtl::Reference< core::FragmentHandler > xRef(
395 new DiagramLayoutFragmentHandler( rFilter, rLayoutPath, pLayout ));
396 importFragment(rFilter,
397 loadFragment(rFilter,xRef),
398 "DiagramLayout",
399 pShape,
400 xRef);
403 // style
404 if( !rQStylePath.isEmpty() )
406 rtl::Reference< core::FragmentHandler > xRef(
407 new DiagramQStylesFragmentHandler( rFilter, rQStylePath, pDiagram->getStyles() ));
408 importFragment(rFilter,
409 loadFragment(rFilter,xRef),
410 "DiagramQStyle",
411 pShape,
412 xRef);
415 // colors
416 if( !rColorStylePath.isEmpty() )
418 rtl::Reference< core::FragmentHandler > xRef(
419 new ColorFragmentHandler( rFilter, rColorStylePath, pDiagram->getColors() ));
420 importFragment(rFilter,
421 loadFragment(rFilter,xRef),
422 "DiagramColorStyle",
423 pShape,
424 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 );
447 OUString aEmpty;
449 // data
450 if( rXDataModelDom.is() )
451 importFragment(rFilter,
452 rXDataModelDom,
453 "DiagramData",
454 pShape,
455 new DiagramDataFragmentHandler( rFilter, aEmpty, pData ));
457 // layout
458 if( rXLayoutDom.is() )
459 importFragment(rFilter,
460 rXLayoutDom,
461 "DiagramLayout",
462 pShape,
463 new DiagramLayoutFragmentHandler( rFilter, aEmpty, pLayout ));
465 // style
466 if( rXQStyleDom.is() )
467 importFragment(rFilter,
468 rXQStyleDom,
469 "DiagramQStyle",
470 pShape,
471 new DiagramQStylesFragmentHandler( rFilter, aEmpty, pDiagram->getStyles() ));
473 // colors
474 if( rXColorStyleDom.is() )
475 importFragment(rFilter,
476 rXColorStyleDom,
477 "DiagramColorStyle",
478 pShape,
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: */