0.3.1
[qanava.git] / src / qanGraphScene.cpp
blobac6af7d25fa7c02a479839f6c809ea9a5d4723f7
1 /*
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.
23 // \file canGraphScene.cpp
24 // \author Benoit Autheman (benoit@libqanava.org)
25 // \date 2005 November 22
26 //-----------------------------------------------------------------------------
29 // Qanava headers
30 #include "./qanGraph.h"
31 #include "./qanEdge.h"
32 #include "./qanGraphScene.h"
33 #include "./qanGrid.h"
36 // STD headers
37 #include <cmath>
40 // QT headers
41 #include <QVBoxLayout>
42 #include <QTimer>
43 #include <QScrollBar>
46 //-----------------------------------------------------------------------------
47 namespace qan { // ::qan
50 /* GraphScene Object Management *///-------------------------------------------
51 /*!
52 \param backgroundColor Graph canvas background color.
54 GraphScene::GraphScene( QWidget* parent, QColor backgroundColor, QSize size ) :
55 QGraphicsScene( parent )
60 GraphScene::~GraphScene( )
62 _styleManager.clear( );
64 //-----------------------------------------------------------------------------
68 /* Scene Management *///-------------------------------------------------------
69 /*! Styles registered in the style manager are not cleared, and can be reused when this
70 model will receive new edges and noeds.
72 void GraphScene::clear( )
74 // Clear all graphics items in the graphic view
75 foreach ( QGraphicsItem* item, _edgeGraphicItemMap.values( ) )
76 removeItem( item );
77 foreach ( AbstractNodeItem* item, _nodeGraphicItemMap.values( ) )
78 removeItem( item->getGraphicsItem( ) );
80 // Clear all mappings
81 _nodeGraphicItemMap.clear( );
82 _edgeGraphicItemMap.clear( );
85 VectorF GraphScene::getBoundingBox( const Node::List& nodes )
87 VectorF bbox( 2 );
88 bbox( 0 ) = 0;
89 bbox( 1 ) = 0;
91 Node::List::const_iterator nodeIter = nodes.begin( );
92 for ( ; nodeIter != nodes.end( ); nodeIter++ )
94 const Node* node = *nodeIter;
95 const VectorF& position = node->getPosition( );
96 const VectorF& dimension = node->getDimension( );
98 if ( position( 0 ) + dimension( 0 ) > bbox( 0 ) )
99 bbox( 0 ) = position( 0 ) + dimension( 0 );
100 if ( position( 1 ) + dimension( 1 ) > bbox( 1 ) )
101 bbox( 1 ) = position( 1 ) + dimension( 1 );
103 return bbox;
106 void GraphScene::updatePositions( Node* except )
108 // Update all nodes positions
109 NodeGraphicItemMap::iterator nodeIter = _nodeGraphicItemMap.begin( );
110 for ( ; nodeIter != _nodeGraphicItemMap.end( ); nodeIter++ )
112 const Node* node = nodeIter.key( );
113 AbstractNodeItem* item = nodeIter.value( );
114 if ( node != 0 && item != 0 && node != except )
116 item->getGraphicsItem( )->setPos( node->getPosition( )( 0 ), node->getPosition( )( 1 ) );
117 item->updateEdges( );
121 //-----------------------------------------------------------------------------
125 /* Style Management *///-------------------------------------------------------
126 void GraphScene::applyStyle( void* item, Style* style )
128 if ( item != 0 && style != 0 )
130 _styleManager.setStyle( item, *style );
131 updateStyle( item, style );
135 void GraphScene::updateStyle( void* item, Style* style )
137 // Update node graphic item with the style content
138 NodeGraphicItemMap::const_iterator nodeIter = _nodeGraphicItemMap.find( reinterpret_cast< Node* >( item ) );
139 if ( nodeIter != _nodeGraphicItemMap.end( ) )
141 AbstractNodeItem* item = nodeIter.value( );
142 item->setStyle( style );
144 EdgeGraphicItemMap::const_iterator edgeIter = _edgeGraphicItemMap.find( reinterpret_cast< Edge* >( item ) );
145 if ( edgeIter != _edgeGraphicItemMap.end( ) )
147 GraphItem* item = edgeIter.value( );
148 item->setStyle( style );
151 //-----------------------------------------------------------------------------
155 /* Scene Topology Management *///----------------------------------------------
156 void GraphScene::init( Node::List& rootNodes )
158 // Generate persistent model indexes for all graph nodes
159 Node::List::iterator nodeIter = rootNodes.begin( );
160 for ( int row = 0; nodeIter != rootNodes.end( ); row++, nodeIter++ )
161 visit( **nodeIter );
164 void GraphScene::edgeInserted( qan::Edge& edge )
166 insertEdge( edge );
169 void GraphScene::edgeRemoved( qan::Edge& edge )
174 void GraphScene::nodeInserted( qan::Node& node )
176 insertNode( node );
179 void GraphScene::nodeRemoved( qan::Node& node )
181 QGraphicsItem* nodeItem = getNodeGraphicItem( &node );
183 // Remove arrows
184 Edge::List edges;
185 std::copy( node.getInEdges( ).begin( ), node.getInEdges( ).end( ), std::back_insert_iterator< Edge::List >( edges ) );
186 std::copy( node.getOutEdges( ).begin( ), node.getOutEdges( ).end( ), std::back_insert_iterator< Edge::List >( edges ) );
187 for ( Edge::List::iterator edgeIter = edges.begin( ); edgeIter != edges.end( ); edgeIter++ )
189 EdgeGraphicItemMap::iterator canvasEdgeIter = _edgeGraphicItemMap.find( *edgeIter );
190 if ( canvasEdgeIter != _edgeGraphicItemMap.end( ) )
192 ( canvasEdgeIter.value( ) )->disconnectEdge( );
193 _edgeGraphicItemMap.remove( *edgeIter );
197 _nodeGraphicItemMap.remove( &node );
198 delete nodeItem;
199 update( );
202 void GraphScene::nodeChanged( qan::Node& node )
204 NodeItem* nodeItem = static_cast< NodeItem* >( getNodeGraphicItem( &node ) );
205 if ( nodeItem != 0 )
206 nodeItem->updateItem( );
209 void GraphScene::visit( qan::Node& node )
211 if ( _nodeGraphicItemMap.find( &node ) != _nodeGraphicItemMap.end( ) )
212 return;
213 insertNode( node );
215 // Visit sub nodes
216 Edge::List& edgeList = node.getOutEdges( );
217 for ( Edge::List::iterator edgeIter = edgeList.begin( ); edgeIter != edgeList.end( ); edgeIter++ )
219 Edge* edge = *edgeIter;
220 visit( edge->getDst( ) );
224 void GraphScene::insertNode( qan::Node& node )
226 // Map a graphic item to a graph node
227 AbstractNodeItem* nodeItem = createNodeItem( node, 0, QPoint( 1, 1 ), node.getLabel( ) );
228 if ( nodeItem != 0 )
229 _nodeGraphicItemMap.insert( &node, nodeItem );
231 // Generate arrows for the model
232 Edge::Set edges = Edge::Set::fromList( node.getInEdges( ) );
233 edges.unite( Edge::Set::fromList( node.getOutEdges( ) ) );
234 foreach ( Edge* edge, edges )
235 insertEdge( *edge );
238 void GraphScene::insertEdge( qan::Edge& edge )
240 EdgeGraphicItemMap::iterator canvasEdgeIter = _edgeGraphicItemMap.find( &edge );
241 if ( canvasEdgeIter == _edgeGraphicItemMap.end( ) )
243 NodeItem* src = static_cast< NodeItem* >( getNodeGraphicItem( &edge.getSrc( ) ) );
244 NodeItem* dst = static_cast< NodeItem* >( getNodeGraphicItem( &edge.getDst( ) ) );
245 if ( src != 0 && dst != 0 )
247 // Get node type associed style
248 Style* style = getStyleManager( ).getEmptyStyle( );
249 Style* edgeStyle = getStyleManager( ).getStyle( &edge );
250 if ( edgeStyle != 0 )
251 style = edgeStyle;
253 EdgeItem* edgeItem = new EdgeItem( getStyleManager( ), style, 0, this, edge, src, dst );
254 _edgeGraphicItemMap.insert( &edge, edgeItem );
257 else
258 canvasEdgeIter.value( )->show( ); // The arrow might have been previously hiden, so set it visible again
260 //-----------------------------------------------------------------------------
264 /* Model Index and Graphic Item Management *///--------------------------------
265 Node* GraphScene::getGraphicItemNode( const QGraphicsItem* item )
267 return const_cast< Node* >( _nodeGraphicItemMap.key( reinterpret_cast< AbstractNodeItem* >( const_cast< QGraphicsItem* >( item ) ) ) );
270 QGraphicsItem* GraphScene::getNodeGraphicItem( const Node* node )
272 if ( node == 0 )
273 return 0;
274 NodeGraphicItemMap::const_iterator nodeIter = _nodeGraphicItemMap.find( node );
275 if ( nodeIter != _nodeGraphicItemMap.end( ) )
276 return ( nodeIter.value( ) )->getGraphicsItem( );
277 return 0;
280 Node* GraphScene::getCurrentNode( QPoint& p )
282 /*Item::List collisions;
283 //getCanvas( )->getCollisions( p, collisions ); // FIXME
284 if ( collisions.begin( ) != collisions.end( ) )
286 Item* item = *collisions.begin( );
287 //if ( getCanvas( ) != 0 && !getCanvas( )->isFreed( item ) ) // FIXME
288 // return getGraphicItemNode( item );
290 return 0;
292 //-----------------------------------------------------------------------------
295 /* Graphic Node Factory Management *///----------------------------------------
296 /*! Ownership for the factory is transfrerred to this graph item view.
297 \param factory Graphic node factory that must be used when generating node graphic counterpart.
299 void GraphScene::registerGraphicNodeFactory( AbstractNodeItem::AbstractFactory* factory )
301 assert( factory != 0 );
302 if ( factory->isDefaultFactory( ) )
303 _factories.push_back( factory ); // Default factories must be tested after standard ones
304 else
305 _factories.push_front( factory );
309 \return A adequat graphic counterpart for node, or a node from a default factory, or 0 if no (default) factories are registered.
311 AbstractNodeItem* GraphScene::createNodeItem( Node& node, QGraphicsItem* parent,
312 QPoint origin, const QString& label )
314 // Get node type associed style
315 Style* style = getStyleManager( ).getEmptyStyle( );
316 Style* nodeStyle = getStyleManager( ).getStyle( &node );
317 if ( nodeStyle != 0 )
318 style = nodeStyle;
319 nodeStyle = getStyleManager( ).getStyle( node.getType( ) );
320 if ( nodeStyle != 0 )
321 style = nodeStyle;
323 // Find a factory able to create a grpahic item for my node
324 AbstractNodeItem::AbstractFactory::List::iterator factoryIter = _factories.begin( );
325 for ( ; factoryIter != _factories.end( ); factoryIter++ )
327 AbstractNodeItem::AbstractFactory* factory = *factoryIter;
328 if ( factory->isDefaultFactory( ) ) // Default factories create graphic node whatever the node type is
329 return factory->create( node, getStyleManager( ), parent, this, style, origin, label );
331 if ( node.getType( ) == factory->getNodeType( ) )
332 return factory->create( node, getStyleManager( ), parent, this, style, origin, label );
334 return 0; // No adequat nor default factory found
336 //-----------------------------------------------------------------------------
339 } // ::qan
340 //-----------------------------------------------------------------------------