diff options
Diffstat (limited to 'oox/source/drawingml/diagram/diagram.cxx')
-rw-r--r-- | oox/source/drawingml/diagram/diagram.cxx | 518 |
1 files changed, 359 insertions, 159 deletions
diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index 30c6e5b78134..5c0e079ba456 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -32,9 +32,21 @@ #include <com/sun/star/awt/Point.hpp> #include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> +#include <rtl/ustrbuf.hxx> +#include "oox/drawingml/textbody.hxx" +#include "oox/drawingml/textparagraph.hxx" +#include "oox/drawingml/textrun.hxx" #include "oox/drawingml/diagram/diagram.hxx" #include "oox/drawingml/fillproperties.hxx" +#include "diagramlayoutatoms.hxx" +#include "diagramfragmenthandler.hxx" + +#include <iostream> +#include <fstream> + using rtl::OUString; using namespace ::com::sun::star; @@ -45,58 +57,26 @@ namespace dgm { void Connection::dump() { - OSL_TRACE("dgm: cnx modelId %s, srcId %s, dstId %s", + OSL_TRACE("dgm: cnx modelId %s, srcId %s, dstId %s, parTransId %s, presId %s, sibTransId %s, srcOrd %d, dstOrd %d", OUSTRING_TO_CSTR( msModelId ), OUSTRING_TO_CSTR( msSourceId ), - OUSTRING_TO_CSTR( msDestId ) ); -} - -Point::Point() - : mpShape( new Shape( "com.sun.star.drawing.GraphicObjectShape" ) ) - , mnType( 0 ) -{ + OUSTRING_TO_CSTR( msDestId ), + OUSTRING_TO_CSTR( msParTransId ), + OUSTRING_TO_CSTR( msPresId ), + OUSTRING_TO_CSTR( msSibTransId ), + mnSourceOrder, + mnDestOrder ); } void Point::dump() { - OSL_TRACE( "dgm: pt cnxId %s, modelId %s", + OSL_TRACE( "dgm: pt text %x, cnxId %s, modelId %s, type %d", + mpShape.get(), OUSTRING_TO_CSTR( msCnxId ), - OUSTRING_TO_CSTR( msModelId ) ); -} - -void Point::setModelId( const ::rtl::OUString & sModelId ) -{ - msModelId = sModelId; - mpShape->setName( msModelId ); -} - - -bool PointsTree::addChild( const PointsTreePtr & pChild ) -{ - bool added = false; - - OSL_ENSURE( pChild->mpParent.expired(), "can't add, has already a parent" ); - OSL_ENSURE( mpNode, "has no node" ); - if( mpNode && pChild->mpParent.expired() ) - { - pChild->mpParent = shared_from_this(); - maChildrens.push_back( pChild ); - added = true; - } - - return added; -} - -PointsTreePtr PointsTree::getParent() const -{ - if( !mpParent.expired() ) - { - return mpParent.lock() ; - } - return PointsTreePtr(); + OUSTRING_TO_CSTR( msModelId ), + mnType ); } - } // dgm namespace DiagramData::DiagramData() @@ -114,27 +94,8 @@ void DiagramData::dump() boost::bind( &dgm::Point::dump, _1 ) ); } -static void setPosition( const dgm::PointPtr & pPoint, const awt::Point & pt ) -{ - ShapePtr pShape = pPoint->getShape(); - awt::Size sz; - sz.Width = 50; - sz.Height = 50; - pShape->setPosition( pt ); - pShape->setSize( sz ); -} - -void DiagramLayout::layout( const dgm::PointsTreePtr & pTree, const awt::Point & pt ) +void DiagramLayout::layout( const dgm::Points & /*pTree*/, const awt::Point & /*pt*/ ) { - setPosition( pTree->getPoint(), pt ); - awt::Point nextPt = pt; - nextPt.Y += 50; - dgm::PointsTree::Childrens::const_iterator iter; - for( iter = pTree->beginChild(); iter != pTree->endChild(); ++iter ) - { - layout( *iter, nextPt ); - nextPt.X += 50; - } } void Diagram::setData( const DiagramDataPtr & pData) @@ -148,140 +109,237 @@ void Diagram::setLayout( const DiagramLayoutPtr & pLayout) mpLayout = pLayout; } -void Diagram::setQStyles( const DiagramQStylesPtr & pStyles) +#if OSL_DEBUG_LEVEL > 1 +rtl::OString normalizeDotName( const rtl::OUString& rStr ) { - mpQStyles = pStyles; -} + rtl::OUStringBuffer aBuf; + aBuf.append((sal_Unicode)'N'); + const sal_Int32 nLen(rStr.getLength()); + sal_Int32 nCurrIndex(0); + while( nCurrIndex < nLen ) + { + const sal_Int32 aChar=rStr.iterateCodePoints(&nCurrIndex); + if( aChar != '-' && aChar != '{' && aChar != '}' ) + aBuf.append((sal_Unicode)aChar); + } -void Diagram::setColors( const DiagramColorsPtr & pColors) -{ - mpColors = pColors; + return rtl::OUStringToOString(aBuf.makeStringAndClear(), + RTL_TEXTENCODING_UTF8); } +#endif -void Diagram::build( ) +static sal_Int32 calcDepth( const rtl::OUString& rNodeName, + const dgm::Connections& rCnx ) { - OSL_TRACE( "building diagram" ); - typedef std::map< OUString, dgm::PointPtr > PointsMap; - PointsMap aPointsMap; - dgm::Points::iterator aPointsIter( mpData->getPoints( ).begin() ); - for( ; aPointsIter != mpData->getPoints( ).end() ; aPointsIter++ ) + // find length of longest path in 'isChild' graph, ending with rNodeName + dgm::Connections::const_iterator aCurrCxn( rCnx.begin() ); + const dgm::Connections::const_iterator aEndCxn( rCnx.end() ); + while( aCurrCxn != aEndCxn ) { - const OUString & sName((*aPointsIter)->getModelId()); - if( sName.getLength() > 0 ) + if( aCurrCxn->msParTransId.getLength() && + aCurrCxn->msSibTransId.getLength() && + aCurrCxn->msSourceId.getLength() && + aCurrCxn->msDestId.getLength() && + aCurrCxn->mnType != XML_presOf && + aCurrCxn->mnType != XML_presParOf && + rNodeName == aCurrCxn->msDestId ) { - aPointsMap[ sName ] = *aPointsIter; + return calcDepth(aCurrCxn->msSourceId, + rCnx) + 1; } + ++aCurrCxn; } - typedef std::map< OUString, dgm::PointsTreePtr > PointsTreeMap; - PointsTreeMap aTreeMap; - PointsTreeMap aRoots; + return 0; +} + + +void Diagram::build( ) +{ + // build name-object maps + // ====================== + +#if OSL_DEBUG_LEVEL > 1 + std::ofstream output("/tmp/tree.dot"); + + output << "digraph datatree {" << std::endl; +#endif - dgm::Connections & aConnections(mpData->getConnections( ) ); - dgm::Connections::iterator aCnxIter; - for( aCnxIter = aConnections.begin(); aCnxIter != aConnections.end(); ++aCnxIter ) + dgm::Points::iterator aCurrPoint( getData()->getPoints( ).begin() ); + const dgm::Points::iterator aEndPoint( getData()->getPoints( ).end() ); + while( aCurrPoint != aEndPoint ) { - OSL_ENSURE( *aCnxIter, "NULL connection found" ); - if( (*aCnxIter)->mnType != XML_parOf ) +#if OSL_DEBUG_LEVEL > 1 + output << "\t" + << normalizeDotName(aCurrPoint->msModelId).getStr() + << "["; + + if( aCurrPoint->msPresentationLayoutName.getLength() ) + output << "label=\"" + << rtl::OUStringToOString( + aCurrPoint->msPresentationLayoutName, + RTL_TEXTENCODING_UTF8).getStr() << "\", "; + else + output << "label=\"" + << rtl::OUStringToOString( + aCurrPoint->msModelId, + RTL_TEXTENCODING_UTF8).getStr() << "\", "; + + switch( aCurrPoint->mnType ) { -// OSL_TRACE( "ignoring relation %s", OUSTRING_TO_CSTR( (*aCnxIter)->msModelId ) ); - continue; + case XML_doc: output << "style=filled, color=red"; break; + case XML_asst: output << "style=filled, color=green"; break; + default: + case XML_node: output << "style=filled, color=blue"; break; + case XML_pres: output << "style=filled, color=yellow"; break; + case XML_parTrans: output << "color=grey"; break; + case XML_sibTrans: output << " "; break; } - dgm::PointPtr pDest; - dgm::PointsTreePtr pSource; - PointsMap::iterator iterP; - OUString & srcId( (*aCnxIter)->msSourceId ); - OUString & dstId( (*aCnxIter)->msDestId ); - OSL_TRACE( "connexion %s -> %s", OUSTRING_TO_CSTR( srcId ), - OUSTRING_TO_CSTR( dstId ) ); - - PointsTreeMap::iterator iterT = aTreeMap.find( srcId ); - if( iterT != aTreeMap.end() ) + + output << "];" << std::endl; + + // does currpoint have any text set? + if( aCurrPoint->mpShape && + aCurrPoint->mpShape->getTextBody() && + !aCurrPoint->mpShape->getTextBody()->getParagraphs().empty() && + !aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().empty() ) { - pSource = iterT->second; + static sal_Int32 nCount=0; + + output << "\t" + << "textNode" << nCount + << " [" + << "label=\"" + << rtl::OUStringToOString( + aCurrPoint->mpShape->getTextBody()->getParagraphs().front()->getRuns().front()->getText(), + RTL_TEXTENCODING_UTF8).getStr() + << "\"" << "];" << std::endl; + output << "\t" + << normalizeDotName(aCurrPoint->msModelId).getStr() + << " -> " + << "textNode" << nCount++ + << ";" << std::endl; } - else +#endif + + const bool bInserted1=getData()->getPointNameMap().insert( + std::make_pair(aCurrPoint->msModelId,&(*aCurrPoint))).second; + (void)bInserted1; + + OSL_ENSURE(bInserted1,"Diagram::build(): non-unique point model id"); + + if( aCurrPoint->msPresentationLayoutName.getLength() ) + { + DiagramData::PointsNameMap::value_type::second_type& rVec= + getData()->getPointsPresNameMap()[aCurrPoint->msPresentationLayoutName]; + rVec.push_back(&(*aCurrPoint)); + } + ++aCurrPoint; + } + + dgm::Connections::const_iterator aCurrCxn( getData()->getConnections( ).begin() ); + const dgm::Connections::const_iterator aEndCxn( getData()->getConnections( ).end() ); + while( aCurrCxn != aEndCxn ) + { +#if OSL_DEBUG_LEVEL > 1 + if( aCurrCxn->msParTransId.getLength() || + aCurrCxn->msSibTransId.getLength() ) { - // this tree node is not found. create it with the source - // and make it the root node. - iterP = aPointsMap.find( srcId ); - if( iterP != aPointsMap.end() ) + if( aCurrCxn->msSourceId.getLength() || + aCurrCxn->msDestId.getLength() ) { - pSource.reset( new dgm::PointsTree( iterP->second ) ); - aRoots[ srcId ] = pSource; - aTreeMap[ srcId ] = pSource; + output << "\t" + << normalizeDotName(aCurrCxn->msSourceId).getStr() + << " -> " + << normalizeDotName(aCurrCxn->msParTransId).getStr() + << " -> " + << normalizeDotName(aCurrCxn->msSibTransId).getStr() + << " -> " + << normalizeDotName(aCurrCxn->msDestId).getStr() + << " [style=dotted," + << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " ")) + << "label=\"" + << rtl::OUStringToOString(aCurrCxn->msModelId, + RTL_TEXTENCODING_UTF8 ).getStr() + << "\"];" << std::endl; } else { - OSL_TRACE("parent node not found !"); + output << "\t" + << normalizeDotName(aCurrCxn->msParTransId).getStr() + << " -> " + << normalizeDotName(aCurrCxn->msSibTransId).getStr() + << " [" + << ((aCurrCxn->mnType == XML_presOf) ? " color=red, " : ((aCurrCxn->mnType == XML_presParOf) ? " color=green, " : " ")) + << "label=\"" + << rtl::OUStringToOString(aCurrCxn->msModelId, + RTL_TEXTENCODING_UTF8 ).getStr() + << "\"];" << std::endl; } } - iterP = aPointsMap.find( dstId ); - if( iterP != aPointsMap.end() ) - { - pDest = iterP->second; - } - OSL_ENSURE( pDest, "destination not found" ); - OSL_ENSURE( pSource, "source not found" ); - if(pDest && pSource) + else if( aCurrCxn->msSourceId.getLength() || + aCurrCxn->msDestId.getLength() ) + output << "\t" + << normalizeDotName(aCurrCxn->msSourceId).getStr() + << " -> " + << normalizeDotName(aCurrCxn->msDestId).getStr() + << " [label=\"" + << rtl::OUStringToOString(aCurrCxn->msModelId, + RTL_TEXTENCODING_UTF8 ).getStr() + << ((aCurrCxn->mnType == XML_presOf) ? "\", color=red]" : ((aCurrCxn->mnType == XML_presParOf) ? "\", color=green]" : "\"]")) + << ";" << std::endl; +#endif + + const bool bInserted1=getData()->getConnectionNameMap().insert( + std::make_pair(aCurrCxn->msModelId,&(*aCurrCxn))).second; + (void)bInserted1; + + OSL_ENSURE(bInserted1,"Diagram::build(): non-unique connection model id"); + + if( aCurrCxn->mnType == XML_presOf ) { - dgm::PointsTreePtr pNode( new dgm::PointsTree( pDest ) ); - bool added = pSource->addChild( pNode ); - (void)added; - aRoots.erase( dstId ); - OSL_ENSURE( added, "add child failed" ); - aTreeMap[ dstId ] = pNode; + DiagramData::StringMap::value_type::second_type& rVec=getData()->getPresOfNameMap()[aCurrCxn->msDestId]; + rVec.push_back( + std::make_pair( + aCurrCxn->msSourceId,sal_Int32(0))); } + + ++aCurrCxn; } - // check bounds - OSL_ENSURE( aRoots.size() == 1, "more than one root" ); - // #i92239# roots may be empty - if( !aRoots.empty() ) + + // assign outline levels + DiagramData::StringMap::iterator aPresOfIter=getData()->getPresOfNameMap().begin(); + const DiagramData::StringMap::iterator aPresOfEnd=getData()->getPresOfNameMap().end(); + while( aPresOfIter != aPresOfEnd ) { - mpRoot = aRoots.begin()->second; - OSL_TRACE( "root is %s", OUSTRING_TO_CSTR( mpRoot->getPoint()->getModelId() ) ); - for( PointsTreeMap::iterator iter = aTreeMap.begin(); - iter != aTreeMap.end(); ++iter ) + DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeIterCalcLevel=aPresOfIter->second.begin(); + const DiagramData::StringMap::value_type::second_type::iterator aPresOfNodeEnd=aPresOfIter->second.end(); + while(aPresOfNodeIterCalcLevel != aPresOfNodeEnd) { - if(! iter->second->getParent() ) - { - OSL_TRACE("node without parent %s", OUSTRING_TO_CSTR( iter->first ) ); - } + const sal_Int32 nDepth=calcDepth(aPresOfNodeIterCalcLevel->first, + getData()->getConnections()); + aPresOfNodeIterCalcLevel->second = nDepth != 0 ? nDepth : -1; + ++aPresOfNodeIterCalcLevel; } + + ++aPresOfIter; } + +#if OSL_DEBUG_LEVEL > 1 + output << "}" << std::endl; +#endif } void Diagram::addTo( const ShapePtr & pParentShape ) { - dgm::Points & aPoints( mpData->getPoints( ) ); - dgm::Points::iterator aPointsIter; + // collect data, init maps build( ); - if( mpRoot.get() ) - mpLayout->layout( mpRoot, awt::Point( 0, 0 ) ); - for( aPointsIter = aPoints.begin(); aPointsIter != aPoints.end(); ++aPointsIter ) - { - if( ( *aPointsIter )->getType() != XML_node ) - { - continue; - } - ShapePtr pShape = ( *aPointsIter )->getShape( ); - if( pShape->getName( ).getLength() > 0 ) - { - maShapeMap[ pShape->getName( ) ] = pShape; - OSL_TRACE( "Dgm: added shape %s to map", OUSTRING_TO_CSTR( pShape->getName() ) ); - } - pParentShape->addChild( pShape ); - } - - OSL_TRACE( "Dgm: addTo() # of childs %d", pParentShape->getChildren().size() ); - for( std::vector< ShapePtr >::iterator iter = pParentShape->getChildren().begin(); - iter != pParentShape->getChildren().end(); ++iter) - { - OSL_TRACE( "Dgm: shape name %s", OUSTRING_TO_CSTR( (*iter)->getName() ) ); - } + // create Shape hierarchy + ShapeCreationVisitor aCreationVisitor(pParentShape, *this); + mpLayout->getNode()->accept(aCreationVisitor); } OUString Diagram::getLayoutId() const @@ -294,6 +352,148 @@ OUString Diagram::getLayoutId() const return sLayoutId; } +uno::Reference<xml::dom::XDocument> loadFragment( + core::XmlFilterBase& rFilter, + const rtl::Reference< core::FragmentHandler >& rxHandler ) +{ + // load diagramming fragments into DOM representation, that later + // gets serialized back to SAX events and parsed + return rFilter.importFragment( rxHandler->getFragmentPath() ); +} + +void importFragment( core::XmlFilterBase& rFilter, + const uno::Reference<xml::dom::XDocument>& rXDom, + const char* /*pPropName*/, + const ShapePtr& /*pShape*/, + const rtl::Reference< core::FragmentHandler >& rxHandler ) +{ + uno::Reference<xml::sax::XFastSAXSerializable> xSerializer( + rXDom, uno::UNO_QUERY_THROW); + + // now serialize DOM tree into internal data structures + rFilter.importFragment( rxHandler, xSerializer ); +} + +void loadDiagram( const ShapePtr& pShape, + core::XmlFilterBase& rFilter, + const ::rtl::OUString& rDataModelPath, + const ::rtl::OUString& rLayoutPath, + const ::rtl::OUString& rQStylePath, + const ::rtl::OUString& rColorStylePath ) +{ + DiagramPtr pDiagram( new Diagram() ); + + DiagramDataPtr pData( new DiagramData() ); + pDiagram->setData( pData ); + + DiagramLayoutPtr pLayout( new DiagramLayout() ); + pDiagram->setLayout( pLayout ); + + // data + if( rDataModelPath.getLength() > 0 ) + { + rtl::Reference< core::FragmentHandler > xRef( + new DiagramDataFragmentHandler( rFilter, rDataModelPath, pData )); + + importFragment(rFilter, + loadFragment(rFilter,xRef), + "DiagramData", + pShape, + xRef); + } + + // layout + if( rLayoutPath.getLength() > 0 ) + { + rtl::Reference< core::FragmentHandler > xRef( + new DiagramLayoutFragmentHandler( rFilter, rLayoutPath, pLayout )); + importFragment(rFilter, + loadFragment(rFilter,xRef), + "DiagramLayout", + pShape, + xRef); + } + + // style + if( rQStylePath.getLength() > 0 ) + { + rtl::Reference< core::FragmentHandler > xRef( + new DiagramQStylesFragmentHandler( rFilter, rQStylePath, pDiagram->getStyles() )); + importFragment(rFilter, + loadFragment(rFilter,xRef), + "DiagramQStyle", + pShape, + xRef); + } + + // colors + if( rColorStylePath.getLength() > 0 ) + { + rtl::Reference< core::FragmentHandler > xRef( + new ColorFragmentHandler( rFilter, rColorStylePath, pDiagram->getColors() )); + importFragment(rFilter, + loadFragment(rFilter,xRef), + "DiagramColorStyle", + pShape, + xRef); + } + + // diagram loaded. now lump together & attach to shape + pDiagram->addTo(pShape); +} + +void loadDiagram( const ShapePtr& pShape, + core::XmlFilterBase& rFilter, + const uno::Reference<xml::dom::XDocument>& rXDataModelDom, + const uno::Reference<xml::dom::XDocument>& rXLayoutDom, + const uno::Reference<xml::dom::XDocument>& rXQStyleDom, + const uno::Reference<xml::dom::XDocument>& rXColorStyleDom ) +{ + DiagramPtr pDiagram( new Diagram() ); + + DiagramDataPtr pData( new DiagramData() ); + pDiagram->setData( pData ); + + DiagramLayoutPtr pLayout( new DiagramLayout() ); + pDiagram->setLayout( pLayout ); + + OUString aEmpty; + + // data + if( rXDataModelDom.is() ) + importFragment(rFilter, + rXDataModelDom, + "DiagramData", + pShape, + new DiagramDataFragmentHandler( rFilter, aEmpty, pData )); + + // layout + if( rXLayoutDom.is() ) + importFragment(rFilter, + rXLayoutDom, + "DiagramLayout", + pShape, + new DiagramLayoutFragmentHandler( rFilter, aEmpty, pLayout )); + + // style + if( rXQStyleDom.is() ) + importFragment(rFilter, + rXQStyleDom, + "DiagramQStyle", + pShape, + new DiagramQStylesFragmentHandler( rFilter, aEmpty, pDiagram->getStyles() )); + + // colors + if( rXColorStyleDom.is() ) + importFragment(rFilter, + rXColorStyleDom, + "DiagramColorStyle", + pShape, + new ColorFragmentHandler( rFilter, aEmpty, pDiagram->getColors() )); + + // diagram loaded. now lump together & attach to shape + pDiagram->addTo(pShape); +} } } |