2 Qanava - Graph drawing library for QT
3 Copyright (C) 2006 Benoit AUTHEMAN
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //-----------------------------------------------------------------------------
21 // This file is a part of the Qanava software.
24 // \author Benoit Autheman (benoit@libqanava.org)
25 // \date 2004 February 15
26 //-----------------------------------------------------------------------------
32 namespace qan
{ // ::qan
35 /* GraphT Constructor/Destructor *///-------------------------------------------
36 template < class M
, class O
>
37 GraphT
< M
, O
>::GraphT( ) :
40 _m
.init( _rootNodes
);
41 _o
.init( _rootNodes
);
43 addAttribute
< int >( "Type", 0 );
44 addAttribute
< QString
>( "Label", QString( "" ) );
45 addAttribute
< VectorF
>( "Position", VectorF( 2 ) );
46 addAttribute
< VectorF
>( "Dimension", VectorF( 2 ) );
47 addAttribute
< QDateTime
>( "Date", QDateTime( ) );
50 template < class M
, class O
>
51 GraphT
< M
, O
>::~GraphT( )
55 //-----------------------------------------------------------------------------
58 template < class M
, class O
>
59 void GraphT
< M
, O
>::modifyNode( Node
& node
, const QString
& name
, int type
, void* object
)
61 node
.setLabel( name
);
67 setNodeObject( node
, object
);
69 _m
.nodeChanged( node
);
70 _o
.nodeChanged( node
);
73 template < class M
, class O
>
74 void GraphT
< M
, O
>::setNodeObject( Node
& node
, void* object
)
76 // Map the registered node to a given memory object that act as a key
79 _objectNodeMap
.insert( object
, &node
);
80 _nodeObjectMap
.insert( &node
, object
);
86 /* Edge/Node Management *///---------------------------------------------------
87 template < class M
, class O
>
88 void GraphT
< M
, O
>::addNode( Node
* node
, void* object
)
91 initNodeAttributes( *node
);
93 _nodes
.push_back( node
);
94 _nodesSet
.insert( node
);
97 setNodeObject( *node
, object
);
99 if ( node
->getInDegree( ) == 0 )
100 addRootNode( *node
);
103 template < class M
, class O
>
104 Node
* GraphT
< M
, O
>::addNode( const QString
& name
, int type
, void* object
)
106 Node
* node
= new Node( name
, type
);
107 addNode( node
, object
);
111 template < class M
, class O
>
112 void GraphT
< M
, O
>::insertNode( Node
* node
, void* object
)
115 addNode( node
, object
);
116 _m
.nodeInserted( *node
);
117 _o
.nodeInserted( *node
);
120 template < class M
, class O
>
121 Node
* GraphT
< M
, O
>::insertNode( const QString
& name
, int type
, void* object
)
123 Node
* node
= new Node( name
, type
);
124 insertNode( node
, object
);
128 template < class M
, class O
>
129 void GraphT
< M
, O
>::removeNode( Node
& node
)
131 // Test if node subnodes will eventually became root nodes after their super node removal
132 Node::List rootNodes
;
133 Node::List outNodes
; node
.collectOutNodes( outNodes
);
134 for ( Node::List::iterator outNodeIter
= outNodes
.begin( ); outNodeIter
!= outNodes
.end( ); outNodeIter
++ )
136 Node
* outNode
= *outNodeIter
;
137 if ( !isRootNode( *outNode
) && outNode
->getInDegree( ) <= 1 )
138 rootNodes
.push_back( outNode
);
141 // Add orphan out nodes as root node (node is removed to force view update and maintain graph coherency for listeners)
142 // Oprhan out nodes are removed before 'node' so that they still have a valid parent in
143 // an eventual associed view (for example in a QAbstractItem view, removing node would cause
144 // the model to have a gap preventing node out nodes to be destroyed).
145 for ( Node::List::iterator rootNodeIter
= rootNodes
.begin( ); rootNodeIter
!= rootNodes
.end( ); rootNodeIter
++ )
147 Node
& rootNode
= **rootNodeIter
;
148 //_m.nodeInsertedBegin( rootNode );
149 addRootNode( rootNode
);
150 _m
.nodeInserted( rootNode
);
151 _o
.nodeInserted( rootNode
);
155 //_m.nodeRemovedBegin( node );
157 // Disconnect node from its "in edges".
158 Edge::List::iterator inEdgeIter
= node
.getInEdges( ).begin( );
159 for ( ; inEdgeIter
!= node
.getInEdges( ).end( ); inEdgeIter
++ )
161 Edge
& inEdge
= ( **inEdgeIter
);
162 inEdge
.getSrc( ).getOutEdges( ).removeAll( &inEdge
);
164 node
.getInEdges( ).clear( );
166 // Disconnect node from its "out edges".
167 Edge::List::iterator outEdgeIter
= node
.getOutEdges( ).begin( );
168 for ( ; outEdgeIter
!= node
.getOutEdges( ).end( ); outEdgeIter
++ )
170 Edge
& outEdge
= ( **outEdgeIter
);
171 outEdge
.getDst( ).getInEdges( ).removeAll( &outEdge
);
173 node
.getOutEdges( ).clear( );
175 // Remove node from the graph various node list
176 _nodes
.removeAll( &node
);
177 _nodesSet
.remove( &node
);
178 void* object
= findObject( &node
);
180 _objectNodeMap
.remove( object
);
181 _nodeObjectMap
.remove( &node
);
182 removeRootNode( node
);
184 _m
.nodeRemoved( node
);
185 _o
.nodeRemoved( node
);
188 template < class M
, class O
>
189 void GraphT
< M
, O
>::addEdge( Edge
* edge
)
192 if ( edge
->hasSrc( ) )
193 edge
->getSrc( ).addOutEdge( *edge
);
194 if ( edge
->hasDst( ) )
196 edge
->getDst( ).addInEdge( *edge
);
197 removeRootNode( edge
->getDst( ) ); // Dst can't be a root node, supress it to maintain coherency
199 _edges
.push_back( edge
);
202 template < class M
, class O
>
203 Edge
* GraphT
< M
, O
>::addEdge( Node
& a
, Node
& b
, float weight
)
205 Edge
* edge
= new Edge( &a
, &b
, weight
);
211 template < class M
, class O
>
212 void GraphT
< M
, O
>::insertEdge( Edge
* edge
)
217 template < class M
, class O
>
218 Edge
* GraphT
< M
, O
>::insertEdge( Node
& src
, Node
& dst
, float weight
)
220 // Save destination node topology.
221 /* Edge::List inEdges;
222 std::copy( dst.getInEdges( ).begin( ), dst.getInEdges( ).end( ), std::back_insert_iterator< Edge::List >( inEdges ) );
224 std::copy( dst.getOutEdges( ).begin( ), dst.getOutEdges( ).end( ), std::back_insert_iterator< Edge::List >( outEdges ) );
226 // Delete the node to force view update (and eventually move the node to its correct position)
227 void* object = findObject( &dst );
230 // Restore destination node in and out edges (and reconnect theses edges to their extremity node).
231 for ( Edge::List::iterator inEdgeIter = inEdges.begin( ); inEdgeIter != inEdges.end( ); inEdgeIter++ )
233 Edge* inEdge = *inEdgeIter;
234 dst.addInEdge( *inEdge );
235 inEdge->getSrc( ).addOutEdge( *inEdge );
237 for ( Edge::List::iterator outEdgeIter = outEdges.begin( ); outEdgeIter != outEdges.end( ); outEdgeIter++ )
239 Edge* outEdge = *outEdgeIter;
240 dst.addOutEdge( *outEdge );
241 outEdge->getDst( ).addInEdge( *outEdge );
243 // Remove (eventually) out node from root node
244 removeRootNode( outEdge->getDst( ) );
247 // Insert back the node to its new correct view position
248 Edge
* edge
= addEdge( src
, dst
, weight
);
249 //insertNode( &dst, object );
250 _m
.edgeInserted( *edge
);
251 _o
.edgeInserted( *edge
);
255 template < class M
, class O
>
256 Edge
* GraphT
< M
, O
>::insertNode( Node
* node
, Node
& superNode
)
262 \return true is there is an edge between a and b (whatever is orientation is), false otherwise.
264 template < class M
, class O
>
265 bool GraphT
< M
, O
>::hasEdge( Node
& a
, Node
& b
) const
268 a
.getAdjacentNodesSet( adjacentA
);
269 if ( adjacentA
.find( &b
) != adjacentA
.end( ) )
273 b
.getAdjacentNodesSet( adjacentB
);
274 if ( adjacentB
.find( &a
) != adjacentB
.end( ) )
280 template < class M
, class O
>
281 void GraphT
< M
, O
>::updateModels( )
283 _m
.init( _rootNodes
);
284 _o
.init( _rootNodes
);
288 \return a pointer on the node of request label. 0 if no such node exists.
290 template < class M
, class O
>
291 Node
* GraphT
< M
, O
>::findNode( const QString
& label
)
293 for ( Node::List::iterator nodeIter
= _nodes
.begin( ); nodeIter
!= _nodes
.end( ); nodeIter
++ )
295 Node
* node
= *nodeIter
;
296 if ( node
->getLabel( ) == label
)
302 template < class M
, class O
>
303 Node
* GraphT
< M
, O
>::findNode( void* object
)
305 return _objectNodeMap
.value( object
, 0 );
308 template < class M
, class O
>
309 Node
* GraphT
< M
, O
>::findNode( int node
)
311 Node::List::iterator nodeIter
= _nodes
.begin( );
318 if ( nodeIter
!= _nodes
.end( ) )
324 \result The node index if node is registered in this graph, -1 if there is no node or index.
326 template < class M
, class O
>
327 int GraphT
< M
, O
>::findNode( const Node
& node
) const
329 Node::List::const_iterator nodeIter
= _nodes
.begin( );
331 while ( nodeIter
!= _nodes
.end( ) && ( *nodeIter
!= &node
) )
336 if ( nodeIter
!= _nodes
.end( ) )
341 template < class M
, class O
>
342 void* GraphT
< M
, O
>::findObject( Node
* node
)
344 NodeObjectMap::iterator objectIter
= _nodeObjectMap
.find( node
);
345 return ( objectIter
!= _nodeObjectMap
.end( ) ? objectIter
.value( ) : 0 );
349 \param node Node to be searched in this graph.
350 \return true if the node is found, false otherwise.
352 template < class M
, class O
>
353 bool GraphT
< M
, O
>::hasNode( Node
* node
) const
355 return ( _nodesSet
.find( node
) != _nodesSet
.end( ) );
358 template < class M
, class O
>
359 void GraphT
< M
, O
>::collectNodes( Node::Set
& nodes
) const
361 nodes
.reserve( _nodes
.size( ) );
362 foreach ( Node
* node
, _nodes
)
363 nodes
.insert( node
);
365 /*std::copy( _nodes.begin( ), _nodes.end( ),
366 std::insert_iterator< Node::Set >( nodes, nodes.begin( ) ) );*/
369 /*! This method clear the nodes, the fast node search cache, the node object mapping
370 system and the edge list. Registered nodes and edges are not only dereferenced, but
371 destroyed with a call to delete.
373 template < class M
, class O
>
374 void GraphT
< M
, O
>::clear( )
376 _objectNodeMap
.clear( );
377 _nodeObjectMap
.clear( );
379 for ( Edge::List::iterator edgeIter
= _edges
.begin( ); edgeIter
!= _edges
.end( ); edgeIter
++ )
384 for ( Node::List::iterator nodeIter
= _nodes
.begin( ); nodeIter
!= _nodes
.end( ); nodeIter
++ )
390 _rootNodesSet
.clear( );
392 //-----------------------------------------------------------------------------
395 /* Root Node Management *///---------------------------------------------------
397 Root nodes manually inserted via addRoot() are cleared from the root nodes (and eventually
398 automatically re-added if needed).
400 template < class M
, class O
>
401 void GraphT
< M
, O
>::generateRootNodes( )
404 for ( Node::List::iterator nodeIter
= _nodes
.begin( ); nodeIter
!= _nodes
.end( ); nodeIter
++ )
406 if ( ( *nodeIter
)->getInDegree( ) == 0 )
407 addRootNode( **nodeIter
);
412 \param node node that must be tested against the root nodes set (must be a graph node).
413 \return true if the node is a graph root node, false otherwise.
415 template < class M
, class O
>
416 bool GraphT
< M
, O
>::isRootNode( const Node
& node
) const
418 return ( _rootNodesSet
.find( const_cast< Node
* >( &node
) ) != _rootNodesSet
.end( ) );
420 //-----------------------------------------------------------------------------