Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
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 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <functional>
21 : #include <boost/bind.hpp>
22 :
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 <editeng/unoprnms.hxx>
29 : #include "drawingml/textbody.hxx"
30 : #include "drawingml/textparagraph.hxx"
31 : #include "drawingml/textrun.hxx"
32 : #include "drawingml/diagram/diagram.hxx"
33 : #include "oox/drawingml/fillproperties.hxx"
34 : #include "oox/ppt/pptshapegroupcontext.hxx"
35 : #include "oox/ppt/pptshape.hxx"
36 :
37 : #include "diagramlayoutatoms.hxx"
38 : #include "diagramfragmenthandler.hxx"
39 :
40 : #include <iostream>
41 : #include <fstream>
42 :
43 : using namespace ::com::sun::star;
44 :
45 : namespace oox { namespace drawingml {
46 :
47 : namespace dgm {
48 :
49 3336 : void Connection::dump()
50 : {
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 );
60 3336 : }
61 :
62 3626 : void Point::dump()
63 : {
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 );
69 3626 : }
70 :
71 : } // dgm namespace
72 :
73 128 : DiagramData::DiagramData()
74 128 : : mpFillProperties( new FillProperties )
75 : {
76 128 : }
77 :
78 128 : void DiagramData::dump()
79 : {
80 : OSL_TRACE("Dgm: DiagramData # of cnx: %zu", maConnections.size() );
81 : std::for_each( maConnections.begin(), maConnections.end(),
82 128 : boost::bind( &dgm::Connection::dump, _1 ) );
83 : OSL_TRACE("Dgm: DiagramData # of pt: %zu", maPoints.size() );
84 : std::for_each( maPoints.begin(), maPoints.end(),
85 128 : boost::bind( &dgm::Point::dump, _1 ) );
86 128 : }
87 :
88 88 : void Diagram::setData( const DiagramDataPtr & pData)
89 : {
90 88 : mpData = pData;
91 88 : }
92 :
93 88 : void Diagram::setLayout( const DiagramLayoutPtr & pLayout)
94 : {
95 88 : mpLayout = pLayout;
96 88 : }
97 :
98 : #if OSL_DEBUG_LEVEL > 1
99 : OString normalizeDotName( const OUString& rStr )
100 : {
101 : OUStringBuffer aBuf;
102 : aBuf.append('N');
103 :
104 : const sal_Int32 nLen(rStr.getLength());
105 : sal_Int32 nCurrIndex(0);
106 : while( nCurrIndex < nLen )
107 : {
108 : const sal_Int32 aChar=rStr.iterateCodePoints(&nCurrIndex);
109 : if( aChar != '-' && aChar != '{' && aChar != '}' )
110 : aBuf.append((sal_Unicode)aChar);
111 : }
112 :
113 : return OUStringToOString(aBuf.makeStringAndClear(),
114 : RTL_TEXTENCODING_UTF8);
115 : }
116 : #endif
117 :
118 1964 : static sal_Int32 calcDepth( const OUString& rNodeName,
119 : const dgm::Connections& rCnx )
120 : {
121 : // find length of longest path in 'isChild' graph, ending with rNodeName
122 1964 : dgm::Connections::const_iterator aCurrCxn( rCnx.begin() );
123 1964 : const dgm::Connections::const_iterator aEndCxn( rCnx.end() );
124 288426 : while( aCurrCxn != aEndCxn )
125 : {
126 608536 : if( !aCurrCxn->msParTransId.isEmpty() &&
127 74680 : !aCurrCxn->msSibTransId.isEmpty() &&
128 74680 : !aCurrCxn->msSourceId.isEmpty() &&
129 74680 : !aCurrCxn->msDestId.isEmpty() &&
130 74680 : aCurrCxn->mnType != XML_presOf &&
131 360278 : aCurrCxn->mnType != XML_presParOf &&
132 37340 : rNodeName == aCurrCxn->msDestId )
133 : {
134 1100 : return calcDepth(aCurrCxn->msSourceId,
135 1100 : rCnx) + 1;
136 : }
137 284498 : ++aCurrCxn;
138 : }
139 :
140 864 : return 0;
141 : }
142 :
143 88 : void Diagram::build( )
144 : {
145 : // build name-object maps
146 :
147 : #if OSL_DEBUG_LEVEL > 1
148 : std::ofstream output("/tmp/tree.dot");
149 :
150 : output << "digraph datatree {" << std::endl;
151 : #endif
152 :
153 88 : dgm::Points& rPoints = getData()->getPoints();
154 88 : dgm::Points::iterator aCurrPoint(rPoints.begin());
155 88 : dgm::Points::iterator aEndPoint(rPoints.end());
156 3658 : while( aCurrPoint != aEndPoint )
157 : {
158 : #if OSL_DEBUG_LEVEL > 1
159 : output << "\t"
160 : << normalizeDotName(aCurrPoint->msModelId).getStr()
161 : << "[";
162 :
163 : if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
164 : output << "label=\""
165 : << OUStringToOString(
166 : aCurrPoint->msPresentationLayoutName,
167 : RTL_TEXTENCODING_UTF8).getStr() << "\", ";
168 : else
169 : output << "label=\""
170 : << OUStringToOString(
171 : aCurrPoint->msModelId,
172 : RTL_TEXTENCODING_UTF8).getStr() << "\", ";
173 :
174 : switch( aCurrPoint->mnType )
175 : {
176 : case XML_doc: output << "style=filled, color=red"; break;
177 : case XML_asst: output << "style=filled, color=green"; break;
178 : default:
179 : case XML_node: output << "style=filled, color=blue"; break;
180 : case XML_pres: output << "style=filled, color=yellow"; break;
181 : case XML_parTrans: output << "color=grey"; break;
182 : case XML_sibTrans: output << " "; break;
183 : }
184 :
185 : output << "];" << std::endl;
186 :
187 : // does currpoint have any text set?
188 : if( aCurrPoint->mpShape &&
189 : aCurrPoint->mpShape->getTextBody() &&
190 : !aCurrPoint->mpShape->getTextBody()->getParagraphs().empty() &&
191 : !aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().empty() )
192 : {
193 : static sal_Int32 nCount=0;
194 :
195 : output << "\t"
196 : << "textNode" << nCount
197 : << " ["
198 : << "label=\""
199 : << OUStringToOString(
200 : aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()->getText(),
201 : RTL_TEXTENCODING_UTF8).getStr()
202 : << "\"" << "];" << std::endl;
203 : output << "\t"
204 : << normalizeDotName(aCurrPoint->msModelId).getStr()
205 : << " -> "
206 : << "textNode" << nCount++
207 : << ";" << std::endl;
208 : }
209 : #endif
210 :
211 6964 : const bool bInserted1=getData()->getPointNameMap().insert(
212 10446 : std::make_pair(aCurrPoint->msModelId,&(*aCurrPoint))).second;
213 : (void)bInserted1;
214 :
215 : OSL_ENSURE(bInserted1,"Diagram::build(): non-unique point model id");
216 :
217 3482 : if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
218 : {
219 : DiagramData::PointsNameMap::value_type::second_type& rVec=
220 1978 : getData()->getPointsPresNameMap()[aCurrPoint->msPresentationLayoutName];
221 1978 : rVec.push_back(&(*aCurrPoint));
222 : }
223 3482 : ++aCurrPoint;
224 : }
225 :
226 88 : const dgm::Connections& rConnections = getData()->getConnections();
227 88 : dgm::Connections::const_iterator aCurrCxn(rConnections.begin());
228 88 : const dgm::Connections::const_iterator aEndCxn(rConnections.end());
229 3402 : while( aCurrCxn != aEndCxn )
230 : {
231 : #if OSL_DEBUG_LEVEL > 1
232 : if( !aCurrCxn->msParTransId.isEmpty() ||
233 : !aCurrCxn->msSibTransId.isEmpty() )
234 : {
235 : if( !aCurrCxn->msSourceId.isEmpty() ||
236 : !aCurrCxn->msDestId.isEmpty() )
237 : {
238 : output << "\t"
239 : << normalizeDotName(aCurrCxn->msSourceId).getStr()
240 : << " -> "
241 : << normalizeDotName(aCurrCxn->msParTransId).getStr()
242 : << " -> "
243 : << normalizeDotName(aCurrCxn->msSibTransId).getStr()
244 : << " -> "
245 : << normalizeDotName(aCurrCxn->msDestId).getStr()
246 : << " [style=dotted,"
247 : << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
248 : << "label=\""
249 : << OUStringToOString(aCurrCxn->msModelId,
250 : RTL_TEXTENCODING_UTF8 ).getStr()
251 : << "\"];" << std::endl;
252 : }
253 : else
254 : {
255 : output << "\t"
256 : << normalizeDotName(aCurrCxn->msParTransId).getStr()
257 : << " -> "
258 : << normalizeDotName(aCurrCxn->msSibTransId).getStr()
259 : << " ["
260 : << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " "))
261 : << "label=\""
262 : << OUStringToOString(aCurrCxn->msModelId,
263 : RTL_TEXTENCODING_UTF8 ).getStr()
264 : << "\"];" << std::endl;
265 : }
266 : }
267 : else if( !aCurrCxn->msSourceId.isEmpty() ||
268 : !aCurrCxn->msDestId.isEmpty() )
269 : output << "\t"
270 : << normalizeDotName(aCurrCxn->msSourceId).getStr()
271 : << " -> "
272 : << normalizeDotName(aCurrCxn->msDestId).getStr()
273 : << " [label=\""
274 : << OUStringToOString(aCurrCxn->msModelId,
275 : RTL_TEXTENCODING_UTF8 ).getStr()
276 : << ((aCurrCxn->mnType == XML_presOf) ? "\", color=red]" : ((aCurrCxn->mnType == XML_presParOf) ? "\", color=green]" : "\"]"))
277 : << ";" << std::endl;
278 : #endif
279 :
280 6452 : const bool bInserted1=getData()->getConnectionNameMap().insert(
281 9678 : std::make_pair(aCurrCxn->msModelId,&(*aCurrCxn))).second;
282 : (void)bInserted1;
283 :
284 : OSL_ENSURE(bInserted1,"Diagram::build(): non-unique connection model id");
285 :
286 3226 : if( aCurrCxn->mnType == XML_presOf )
287 : {
288 864 : DiagramData::StringMap::value_type::second_type& rVec=getData()->getPresOfNameMap()[aCurrCxn->msDestId];
289 : rVec.push_back(
290 : std::make_pair(
291 864 : aCurrCxn->msSourceId,sal_Int32(0)));
292 : }
293 :
294 3226 : ++aCurrCxn;
295 : }
296 :
297 : // assign outline levels
298 88 : DiagramData::StringMap& rStringMap = getData()->getPresOfNameMap();
299 88 : DiagramData::StringMap::iterator aPresOfIter=rStringMap.begin();
300 88 : const DiagramData::StringMap::iterator aPresOfEnd=rStringMap.end();
301 1018 : while( aPresOfIter != aPresOfEnd )
302 : {
303 842 : DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeIterCalcLevel=aPresOfIter->second.begin();
304 842 : const DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeEnd=aPresOfIter->second.end();
305 2548 : while(aPresOfNodeIterCalcLevel != aPresOfNodeEnd)
306 : {
307 864 : const sal_Int32 nDepth=calcDepth(aPresOfNodeIterCalcLevel->first,
308 1728 : getData()->getConnections());
309 864 : aPresOfNodeIterCalcLevel->second = nDepth != 0 ? nDepth : -1;
310 864 : ++aPresOfNodeIterCalcLevel;
311 : }
312 :
313 842 : ++aPresOfIter;
314 : }
315 :
316 : #if OSL_DEBUG_LEVEL > 1
317 : output << "}" << std::endl;
318 : #endif
319 88 : }
320 :
321 88 : void Diagram::addTo( const ShapePtr & pParentShape )
322 : {
323 : // collect data, init maps
324 88 : build( );
325 :
326 : // create Shape hierarchy
327 88 : ShapeCreationVisitor aCreationVisitor(pParentShape, *this);
328 88 : if( mpLayout->getNode() )
329 20 : mpLayout->getNode()->accept( aCreationVisitor );
330 :
331 88 : pParentShape->setDiagramDoms( getDomsAsPropertyValues() );
332 88 : }
333 :
334 88 : uno::Sequence<beans::PropertyValue> Diagram::getDomsAsPropertyValues() const
335 : {
336 88 : sal_Int32 length = maMainDomMap.size();
337 :
338 88 : if ( 0 < maDataRelsMap.getLength() )
339 24 : ++length;
340 :
341 88 : uno::Sequence<beans::PropertyValue> aValue(length);
342 88 : beans::PropertyValue* pValue = aValue.getArray();
343 1320 : for (DiagramDomMap::const_iterator i = maMainDomMap.begin();
344 880 : i != maMainDomMap.end();
345 : ++i)
346 : {
347 352 : pValue[0].Name = i->first;
348 352 : pValue[0].Value = uno::makeAny(i->second);
349 352 : ++pValue;
350 : }
351 :
352 88 : if ( 0 < maDataRelsMap.getLength() )
353 : {
354 24 : pValue[0].Name = OUString("OOXDiagramDataRels");
355 24 : pValue[0].Value = uno::makeAny ( maDataRelsMap );
356 24 : ++pValue;
357 : }
358 :
359 88 : return aValue;
360 : }
361 :
362 352 : uno::Reference<xml::dom::XDocument> loadFragment(
363 : core::XmlFilterBase& rFilter,
364 : const OUString& rFragmentPath )
365 : {
366 : // load diagramming fragments into DOM representation, that later
367 : // gets serialized back to SAX events and parsed
368 352 : return rFilter.importFragment( rFragmentPath );
369 : }
370 :
371 216 : uno::Reference<xml::dom::XDocument> loadFragment(
372 : core::XmlFilterBase& rFilter,
373 : const rtl::Reference< core::FragmentHandler >& rxHandler )
374 : {
375 216 : return loadFragment( rFilter, rxHandler->getFragmentPath() );
376 : }
377 :
378 216 : void importFragment( core::XmlFilterBase& rFilter,
379 : const uno::Reference<xml::dom::XDocument>& rXDom,
380 : const char* pDocName,
381 : const DiagramPtr& pDiagram,
382 : const rtl::Reference< core::FragmentHandler >& rxHandler )
383 : {
384 216 : DiagramDomMap& rMainDomMap = pDiagram->getDomMap();
385 216 : rMainDomMap[OUString::createFromAscii(pDocName)] = rXDom;
386 :
387 : uno::Reference<xml::sax::XFastSAXSerializable> xSerializer(
388 216 : rXDom, uno::UNO_QUERY_THROW);
389 :
390 : // now serialize DOM tree into internal data structures
391 216 : rFilter.importFragment( rxHandler, xSerializer );
392 216 : }
393 :
394 88 : void loadDiagram( ShapePtr& pShape,
395 : core::XmlFilterBase& rFilter,
396 : const OUString& rDataModelPath,
397 : const OUString& rLayoutPath,
398 : const OUString& rQStylePath,
399 : const OUString& rColorStylePath )
400 : {
401 88 : DiagramPtr pDiagram( new Diagram() );
402 :
403 176 : DiagramDataPtr pData( new DiagramData() );
404 88 : pDiagram->setData( pData );
405 :
406 176 : DiagramLayoutPtr pLayout( new DiagramLayout() );
407 88 : pDiagram->setLayout( pLayout );
408 :
409 : // data
410 88 : if( !rDataModelPath.isEmpty() )
411 : {
412 : rtl::Reference< core::FragmentHandler > xRefDataModel(
413 88 : new DiagramDataFragmentHandler( rFilter, rDataModelPath, pData ));
414 :
415 : importFragment(rFilter,
416 : loadFragment(rFilter,xRefDataModel),
417 : "OOXData",
418 : pDiagram,
419 88 : xRefDataModel);
420 :
421 264 : pDiagram->getDataRelsMap() = pShape->resolveRelationshipsOfTypeFromOfficeDoc( rFilter,
422 176 : xRefDataModel->getFragmentPath(), "image" );
423 :
424 : // Pass the info to pShape
425 156 : for( ::std::vector<OUString>::const_iterator aIt = pData->getExtDrawings().begin(), aEnd = pData->getExtDrawings().end();
426 : aIt != aEnd; ++aIt )
427 156 : pShape->addExtDrawingRelId( *aIt );
428 : }
429 :
430 : // extLst is present, lets bet on that and ignore the rest of the data from here
431 88 : if( pData->getExtDrawings().empty() )
432 : {
433 : // layout
434 20 : if( !rLayoutPath.isEmpty() )
435 : {
436 : rtl::Reference< core::FragmentHandler > xRefLayout(
437 20 : new DiagramLayoutFragmentHandler( rFilter, rLayoutPath, pLayout ));
438 :
439 : importFragment(rFilter,
440 : loadFragment(rFilter,xRefLayout),
441 : "OOXLayout",
442 : pDiagram,
443 20 : xRefLayout);
444 : }
445 :
446 : // style
447 20 : if( !rQStylePath.isEmpty() )
448 : {
449 : rtl::Reference< core::FragmentHandler > xRefQStyle(
450 20 : new DiagramQStylesFragmentHandler( rFilter, rQStylePath, pDiagram->getStyles() ));
451 :
452 : importFragment(rFilter,
453 : loadFragment(rFilter,xRefQStyle),
454 : "OOXStyle",
455 : pDiagram,
456 20 : xRefQStyle);
457 : }
458 : } else {
459 : // We still want to add the XDocuments to the DiagramDomMap
460 68 : DiagramDomMap& rMainDomMap = pDiagram->getDomMap();
461 68 : rMainDomMap[OUString("OOXLayout")] = loadFragment(rFilter,rLayoutPath);
462 68 : rMainDomMap[OUString("OOXStyle")] = loadFragment(rFilter,rQStylePath);
463 : }
464 :
465 : // colors
466 88 : if( !rColorStylePath.isEmpty() )
467 : {
468 : rtl::Reference< core::FragmentHandler > xRefColorStyle(
469 88 : new ColorFragmentHandler( rFilter, rColorStylePath, pDiagram->getColors() ));
470 :
471 : importFragment(rFilter,
472 : loadFragment(rFilter,xRefColorStyle),
473 : "OOXColor",
474 : pDiagram,
475 88 : xRefColorStyle);
476 : }
477 :
478 88 : if( !pData->getExtDrawings().empty() )
479 : {
480 68 : const DiagramColorMap::const_iterator aColor = pDiagram->getColors().find("node0");
481 68 : if( aColor != pDiagram->getColors().end() )
482 : {
483 68 : pShape->setFontRefColorForNodes(aColor->second.maTextFillColor);
484 : }
485 : }
486 :
487 : // diagram loaded. now lump together & attach to shape
488 176 : pDiagram->addTo(pShape);
489 88 : }
490 :
491 0 : void loadDiagram( const ShapePtr& pShape,
492 : core::XmlFilterBase& rFilter,
493 : const uno::Reference<xml::dom::XDocument>& rXDataModelDom,
494 : const uno::Reference<xml::dom::XDocument>& rXLayoutDom,
495 : const uno::Reference<xml::dom::XDocument>& rXQStyleDom,
496 : const uno::Reference<xml::dom::XDocument>& rXColorStyleDom )
497 : {
498 0 : DiagramPtr pDiagram( new Diagram() );
499 :
500 0 : DiagramDataPtr pData( new DiagramData() );
501 0 : pDiagram->setData( pData );
502 :
503 0 : DiagramLayoutPtr pLayout( new DiagramLayout() );
504 0 : pDiagram->setLayout( pLayout );
505 :
506 0 : OUString aEmpty;
507 :
508 : // data
509 0 : if( rXDataModelDom.is() )
510 : importFragment(rFilter,
511 : rXDataModelDom,
512 : "OOXData",
513 : pDiagram,
514 0 : new DiagramDataFragmentHandler( rFilter, aEmpty, pData ));
515 :
516 : // layout
517 0 : if( rXLayoutDom.is() )
518 : importFragment(rFilter,
519 : rXLayoutDom,
520 : "OOXLayout",
521 : pDiagram,
522 0 : new DiagramLayoutFragmentHandler( rFilter, aEmpty, pLayout ));
523 :
524 : // style
525 0 : if( rXQStyleDom.is() )
526 : importFragment(rFilter,
527 : rXQStyleDom,
528 : "OOXStyle",
529 : pDiagram,
530 0 : new DiagramQStylesFragmentHandler( rFilter, aEmpty, pDiagram->getStyles() ));
531 :
532 : // colors
533 0 : if( rXColorStyleDom.is() )
534 : importFragment(rFilter,
535 : rXColorStyleDom,
536 : "OOXColor",
537 : pDiagram,
538 0 : new ColorFragmentHandler( rFilter, aEmpty, pDiagram->getColors() ));
539 :
540 : // diagram loaded. now lump together & attach to shape
541 0 : pDiagram->addTo(pShape);
542 0 : }
543 :
544 408 : } }
545 :
546 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|