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 :
21 : #include <functional>
22 : #include <boost/bind.hpp>
23 :
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"
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 14 : 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 14 : }
61 :
62 18 : 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 18 : }
70 :
71 : } // dgm namespace
72 :
73 1 : DiagramData::DiagramData()
74 1 : : mpFillProperties( new FillProperties )
75 : {
76 1 : }
77 :
78 1 : void DiagramData::dump()
79 : {
80 : OSL_TRACE("Dgm: DiagramData # of cnx: %d", maConnections.size() );
81 : std::for_each( maConnections.begin(), maConnections.end(),
82 1 : 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 1 : boost::bind( &dgm::Point::dump, _1 ) );
86 1 : }
87 :
88 :
89 1 : void Diagram::setData( const DiagramDataPtr & pData)
90 : {
91 1 : mpData = pData;
92 1 : }
93 :
94 :
95 1 : void Diagram::setLayout( const DiagramLayoutPtr & pLayout)
96 : {
97 1 : mpLayout = pLayout;
98 1 : }
99 :
100 : #if OSL_DEBUG_LEVEL > 1
101 : OString normalizeDotName( const OUString& rStr )
102 : {
103 : OUStringBuffer aBuf;
104 : aBuf.append((sal_Unicode)'N');
105 :
106 : const sal_Int32 nLen(rStr.getLength());
107 : sal_Int32 nCurrIndex(0);
108 : while( nCurrIndex < nLen )
109 : {
110 : const sal_Int32 aChar=rStr.iterateCodePoints(&nCurrIndex);
111 : if( aChar != '-' && aChar != '{' && aChar != '}' )
112 : aBuf.append((sal_Unicode)aChar);
113 : }
114 :
115 : return OUStringToOString(aBuf.makeStringAndClear(),
116 : RTL_TEXTENCODING_UTF8);
117 : }
118 : #endif
119 :
120 7 : static sal_Int32 calcDepth( const OUString& rNodeName,
121 : const dgm::Connections& rCnx )
122 : {
123 : // find length of longest path in 'isChild' graph, ending with rNodeName
124 7 : dgm::Connections::const_iterator aCurrCxn( rCnx.begin() );
125 7 : const dgm::Connections::const_iterator aEndCxn( rCnx.end() );
126 83 : while( aCurrCxn != aEndCxn )
127 : {
128 180 : if( !aCurrCxn->msParTransId.isEmpty() &&
129 18 : !aCurrCxn->msSibTransId.isEmpty() &&
130 18 : !aCurrCxn->msSourceId.isEmpty() &&
131 18 : !aCurrCxn->msDestId.isEmpty() &&
132 18 : aCurrCxn->mnType != XML_presOf &&
133 18 : aCurrCxn->mnType != XML_presParOf &&
134 18 : rNodeName == aCurrCxn->msDestId )
135 : {
136 3 : return calcDepth(aCurrCxn->msSourceId,
137 3 : rCnx) + 1;
138 : }
139 69 : ++aCurrCxn;
140 : }
141 :
142 4 : return 0;
143 : }
144 :
145 :
146 1 : void Diagram::build( )
147 : {
148 : // build name-object maps
149 : // ======================
150 :
151 : #if OSL_DEBUG_LEVEL > 1
152 : std::ofstream output("/tmp/tree.dot");
153 :
154 : output << "digraph datatree {" << std::endl;
155 : #endif
156 :
157 1 : dgm::Points::iterator aCurrPoint( getData()->getPoints( ).begin() );
158 1 : const dgm::Points::iterator aEndPoint( getData()->getPoints( ).end() );
159 20 : while( aCurrPoint != aEndPoint )
160 : {
161 : #if OSL_DEBUG_LEVEL > 1
162 : output << "\t"
163 : << normalizeDotName(aCurrPoint->msModelId).getStr()
164 : << "[";
165 :
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() << "\", ";
176 :
177 : switch( aCurrPoint->mnType )
178 : {
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;
186 : }
187 :
188 : output << "];" << std::endl;
189 :
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() )
195 : {
196 : static sal_Int32 nCount=0;
197 :
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;
211 : }
212 : #endif
213 :
214 36 : const bool bInserted1=getData()->getPointNameMap().insert(
215 54 : std::make_pair(aCurrPoint->msModelId,&(*aCurrPoint))).second;
216 : (void)bInserted1;
217 :
218 : OSL_ENSURE(bInserted1,"Diagram::build(): non-unique point model id");
219 :
220 18 : if( !aCurrPoint->msPresentationLayoutName.isEmpty() )
221 : {
222 : DiagramData::PointsNameMap::value_type::second_type& rVec=
223 8 : getData()->getPointsPresNameMap()[aCurrPoint->msPresentationLayoutName];
224 8 : rVec.push_back(&(*aCurrPoint));
225 : }
226 18 : ++aCurrPoint;
227 : }
228 :
229 1 : dgm::Connections::const_iterator aCurrCxn( getData()->getConnections( ).begin() );
230 1 : const dgm::Connections::const_iterator aEndCxn( getData()->getConnections( ).end() );
231 16 : while( aCurrCxn != aEndCxn )
232 : {
233 : #if OSL_DEBUG_LEVEL > 1
234 : if( !aCurrCxn->msParTransId.isEmpty() ||
235 : !aCurrCxn->msSibTransId.isEmpty() )
236 : {
237 : if( !aCurrCxn->msSourceId.isEmpty() ||
238 : !aCurrCxn->msDestId.isEmpty() )
239 : {
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;
254 : }
255 : else
256 : {
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;
267 : }
268 : }
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
281 :
282 28 : const bool bInserted1=getData()->getConnectionNameMap().insert(
283 42 : std::make_pair(aCurrCxn->msModelId,&(*aCurrCxn))).second;
284 : (void)bInserted1;
285 :
286 : OSL_ENSURE(bInserted1,"Diagram::build(): non-unique connection model id");
287 :
288 14 : if( aCurrCxn->mnType == XML_presOf )
289 : {
290 4 : DiagramData::StringMap::value_type::second_type& rVec=getData()->getPresOfNameMap()[aCurrCxn->msDestId];
291 : rVec.push_back(
292 : std::make_pair(
293 4 : aCurrCxn->msSourceId,sal_Int32(0)));
294 : }
295 :
296 14 : ++aCurrCxn;
297 : }
298 :
299 : // assign outline levels
300 1 : DiagramData::StringMap::iterator aPresOfIter=getData()->getPresOfNameMap().begin();
301 1 : const DiagramData::StringMap::iterator aPresOfEnd=getData()->getPresOfNameMap().end();
302 6 : while( aPresOfIter != aPresOfEnd )
303 : {
304 4 : DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeIterCalcLevel=aPresOfIter->second.begin();
305 4 : const DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeEnd=aPresOfIter->second.end();
306 12 : while(aPresOfNodeIterCalcLevel != aPresOfNodeEnd)
307 : {
308 4 : const sal_Int32 nDepth=calcDepth(aPresOfNodeIterCalcLevel->first,
309 8 : getData()->getConnections());
310 4 : aPresOfNodeIterCalcLevel->second = nDepth != 0 ? nDepth : -1;
311 4 : ++aPresOfNodeIterCalcLevel;
312 : }
313 :
314 4 : ++aPresOfIter;
315 : }
316 :
317 : #if OSL_DEBUG_LEVEL > 1
318 : output << "}" << std::endl;
319 : #endif
320 1 : }
321 :
322 :
323 1 : void Diagram::addTo( const ShapePtr & pParentShape )
324 : {
325 : // collect data, init maps
326 1 : build( );
327 :
328 : // create Shape hierarchy
329 1 : ShapeCreationVisitor aCreationVisitor(pParentShape, *this);
330 1 : if( mpLayout->getNode() )
331 0 : mpLayout->getNode()->accept( aCreationVisitor );
332 1 : }
333 :
334 1 : uno::Reference<xml::dom::XDocument> loadFragment(
335 : core::XmlFilterBase& rFilter,
336 : const rtl::Reference< core::FragmentHandler >& rxHandler )
337 : {
338 : // load diagramming fragments into DOM representation, that later
339 : // gets serialized back to SAX events and parsed
340 1 : return rFilter.importFragment( rxHandler->getFragmentPath() );
341 : }
342 :
343 1 : 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 )
348 : {
349 : uno::Reference<xml::sax::XFastSAXSerializable> xSerializer(
350 1 : rXDom, uno::UNO_QUERY_THROW);
351 :
352 : // now serialize DOM tree into internal data structures
353 1 : rFilter.importFragment( rxHandler, xSerializer );
354 1 : }
355 :
356 1 : void loadDiagram( ShapePtr& pShape,
357 : core::XmlFilterBase& rFilter,
358 : const OUString& rDataModelPath,
359 : const OUString& rLayoutPath,
360 : const OUString& rQStylePath,
361 : const OUString& rColorStylePath )
362 : {
363 1 : DiagramPtr pDiagram( new Diagram() );
364 :
365 1 : DiagramDataPtr pData( new DiagramData() );
366 1 : pDiagram->setData( pData );
367 :
368 1 : DiagramLayoutPtr pLayout( new DiagramLayout() );
369 1 : pDiagram->setLayout( pLayout );
370 :
371 : // data
372 1 : if( !rDataModelPath.isEmpty() )
373 : {
374 : rtl::Reference< core::FragmentHandler > xRef(
375 1 : new DiagramDataFragmentHandler( rFilter, rDataModelPath, pData ));
376 :
377 : importFragment(rFilter,
378 : loadFragment(rFilter,xRef),
379 : "DiagramData",
380 : pShape,
381 1 : xRef);
382 : // Pass the info to pShape
383 2 : for( ::std::vector<OUString>::const_iterator aIt = pData->getExtDrawings().begin(), aEnd = pData->getExtDrawings().end();
384 : aIt != aEnd; ++aIt )
385 2 : pShape->addExtDrawingRelId( *aIt );
386 : }
387 :
388 : // extLst is present, lets bet on that and ignore the rest of the data from here
389 1 : if( !pData->getExtDrawings().size() )
390 : {
391 : // layout
392 0 : if( !rLayoutPath.isEmpty() )
393 : {
394 : rtl::Reference< core::FragmentHandler > xRef(
395 0 : new DiagramLayoutFragmentHandler( rFilter, rLayoutPath, pLayout ));
396 : importFragment(rFilter,
397 : loadFragment(rFilter,xRef),
398 : "DiagramLayout",
399 : pShape,
400 0 : xRef);
401 : }
402 :
403 : // style
404 0 : if( !rQStylePath.isEmpty() )
405 : {
406 : rtl::Reference< core::FragmentHandler > xRef(
407 0 : new DiagramQStylesFragmentHandler( rFilter, rQStylePath, pDiagram->getStyles() ));
408 : importFragment(rFilter,
409 : loadFragment(rFilter,xRef),
410 : "DiagramQStyle",
411 : pShape,
412 0 : xRef);
413 : }
414 :
415 : // colors
416 0 : if( !rColorStylePath.isEmpty() )
417 : {
418 : rtl::Reference< core::FragmentHandler > xRef(
419 0 : new ColorFragmentHandler( rFilter, rColorStylePath, pDiagram->getColors() ));
420 : importFragment(rFilter,
421 : loadFragment(rFilter,xRef),
422 : "DiagramColorStyle",
423 : pShape,
424 0 : xRef);
425 : }
426 : }
427 :
428 : // diagram loaded. now lump together & attach to shape
429 1 : pDiagram->addTo(pShape);
430 1 : }
431 :
432 0 : 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 )
438 : {
439 0 : DiagramPtr pDiagram( new Diagram() );
440 :
441 0 : DiagramDataPtr pData( new DiagramData() );
442 0 : pDiagram->setData( pData );
443 :
444 0 : DiagramLayoutPtr pLayout( new DiagramLayout() );
445 0 : pDiagram->setLayout( pLayout );
446 :
447 0 : OUString aEmpty;
448 :
449 : // data
450 0 : if( rXDataModelDom.is() )
451 : importFragment(rFilter,
452 : rXDataModelDom,
453 : "DiagramData",
454 : pShape,
455 0 : new DiagramDataFragmentHandler( rFilter, aEmpty, pData ));
456 :
457 : // layout
458 0 : if( rXLayoutDom.is() )
459 : importFragment(rFilter,
460 : rXLayoutDom,
461 : "DiagramLayout",
462 : pShape,
463 0 : new DiagramLayoutFragmentHandler( rFilter, aEmpty, pLayout ));
464 :
465 : // style
466 0 : if( rXQStyleDom.is() )
467 : importFragment(rFilter,
468 : rXQStyleDom,
469 : "DiagramQStyle",
470 : pShape,
471 0 : new DiagramQStylesFragmentHandler( rFilter, aEmpty, pDiagram->getStyles() ));
472 :
473 : // colors
474 0 : if( rXColorStyleDom.is() )
475 : importFragment(rFilter,
476 : rXColorStyleDom,
477 : "DiagramColorStyle",
478 : pShape,
479 0 : new ColorFragmentHandler( rFilter, aEmpty, pDiagram->getColors() ));
480 :
481 : // diagram loaded. now lump together & attach to shape
482 0 : pDiagram->addTo(pShape);
483 0 : }
484 :
485 51 : } }
486 :
487 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|