Fix manual.tex qmake configuration settings (thanks to Thomas K.!)
[qanava.git] / src / qanGraphItemModel.cpp
blob45d1e868baca1c6299ede062226ec8a620ff0f8c
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 canGraphItemModel.h
24 // \author Benoit Autheman (benoit@libqanava.org)
25 // \date 2005 November 22
26 //-----------------------------------------------------------------------------
29 // Qanava headers
30 #include "./qanStyle.h"
31 #include "./qanGraphItemModel.h"
34 //-----------------------------------------------------------------------------
35 namespace qan { // ::qan
38 /* Custom Graph Model Interface *///-------------------------------------------
39 GraphItemModel::GraphItemModel( Node::List& rootNodes ) :
40 QAbstractItemModel( ),
41 _rootNodes( rootNodes ),
42 _styleManager( 0 )
47 void GraphItemModel::init( Node::List& rootNodes )
49 _rootNodes = rootNodes;
51 // Generate persistent model indexes for all graph nodes
52 Node::List::iterator nodeIter = _rootNodes.begin( );
53 //for ( int row = 0; nodeIter != _rootNodes.end( ); row++, nodeIter++ )
54 // visit( **nodeIter, row, 0, 500 );
56 emit layoutChanged( );
59 void GraphItemModel::visit( Node& node, int row, int column, int maxDepth )
61 Node::Set marked;
62 visit( node, row, column, marked, 500 );
65 void GraphItemModel::visit( Node& node, int row, int column, Node::Set& marked, int maxDepth )
67 if ( maxDepth == 0 )
68 return;
69 maxDepth--;
71 if ( marked.find( &node ) != marked.end( ) )
72 return;
73 marked.insert( &node );
75 QModelIndex nodeIndex = createIndex( row, column, &node );
76 QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node );
78 if ( nodePersistentIndex != 0 )
80 // Update a pre existing persistent index
81 changePersistentIndex( *nodePersistentIndex, nodeIndex );
83 else
85 // Create a new persistent index
86 nodePersistentIndex = new QPersistentModelIndex( nodeIndex );
87 _nodePersistentIndexMap.insert( std::pair< Node*, QPersistentModelIndex* >( &node, nodePersistentIndex ) );
90 column = 0;
92 // visit sub nodes
93 Edge::List& edgeList = node.getOutEdges( );
94 row = 0;
95 for ( Edge::List::iterator edgeIter = edgeList.begin( ); edgeIter != edgeList.end( ); edgeIter++ )
97 Edge* edge = *edgeIter;
98 visit( edge->getDst( ), row++, column, marked, maxDepth );
102 QPersistentModelIndex* GraphItemModel::getNodePersistentIndex( Node* node ) const
104 NodePersistentIndexMap::const_iterator nodeIter = _nodePersistentIndexMap.find( node );
105 if ( nodeIter != _nodePersistentIndexMap.end( ) )
106 return nodeIter->second;
107 return 0;
109 //-----------------------------------------------------------------------------
113 /* QT Model Interface Management *///------------------------------------------
114 QVariant GraphItemModel::data( const QModelIndex &index, int role ) const
116 if ( !index.isValid( ) )
117 return QVariant( "Index invalid" );
119 Node* node = static_cast< Node* >( index.internalPointer( ) );
120 if ( node == 0 )
121 return QVariant( );
123 const Style* style = 0;
124 if ( _styleManager != 0 && node != 0 )
126 style = _styleManager->getStyle( node );
127 if ( _styleManager->getStyle( node->getType( ) ) )
128 style = _styleManager->getStyle( node->getType( ) );
131 QVariant result;
132 switch ( role )
134 case Qt::DisplayRole:
135 result = node->getLabel( );
136 break;
137 case Qt::DecorationRole:
138 if ( style != 0 && style->has( "icon" ) )
140 QIcon icon( style->getIcon( "icon" ) );
141 if ( !icon.isNull( ) )
142 result = icon;
144 break;
145 case Qt::BackgroundColorRole:
147 if ( style != 0 && style->has( "backcolor" ) )
149 QColor backColor = style->getColor( "backcolor" );
150 if ( backColor.isValid( ) )
152 QColor bc( backColor );
153 bc.setAlpha( 50 );
154 result = bc;
158 break;
159 case Qt::TextColorRole:
161 if ( style != 0 )
163 QColor backColor = style->getColor( "textcolor" );
164 if ( backColor.isValid( ) )
165 result = backColor;
168 break;
170 case Qt::UserRole + POSITION_X:
171 result = node->getPosition( )( 0 );
172 break;
173 case Qt::UserRole + POSITION_Y:
174 result = node->getPosition( )( 1 );
175 break;
176 case Qt::UserRole + DIMENSION_X:
177 result = node->getDimension( )( 0 );
178 break;
179 case Qt::UserRole + DIMENSION_Y:
180 result = node->getDimension( )( 1 );
181 break;
182 default:
183 break;
185 return result;
188 Qt::ItemFlags GraphItemModel::flags( const QModelIndex& index ) const
190 return ( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
193 QModelIndex GraphItemModel::index( int row, int column, const QModelIndex &parent ) const
195 if ( !parent.isValid( ) )
197 if ( row < _rootNodes.size( ) )
199 Node* node = _rootNodes.at( row );
200 QPersistentModelIndex* index = getNodePersistentIndex( node );
201 if ( index == 0 )
202 index = new QPersistentModelIndex( createIndex( row, column, node ) );
203 return ( index != 0 ? QModelIndex( *index ) : QModelIndex( ) );
206 else
208 Node* node = static_cast< Node* >( parent.internalPointer( ) );
209 if ( node != 0 && row < node->getOutEdges( ).size( ) )
211 Edge* edge = node->getOutEdges( ).at( row );
212 Node& outNode = edge->getDst( );
214 QPersistentModelIndex* persistentIndex = getNodePersistentIndex( &outNode );
215 if ( persistentIndex == 0 )
216 persistentIndex = new QPersistentModelIndex( createIndex( row, column, &outNode ) );
217 return ( persistentIndex != 0 ? QModelIndex( *persistentIndex ) : QModelIndex( ) );
220 return QModelIndex( );
223 QModelIndex GraphItemModel::parent( const QModelIndex &index ) const
225 if ( !index.isValid( ) )
226 return QModelIndex( );
227 else
229 Node* node = static_cast< Node* >( index.internalPointer( ) );
230 Node* superNode = 0;
231 if ( node != 0 && ( node->getInEdges( ).size( ) > 0 ) )
232 superNode = &( *node->getInEdges( ).begin( ) )->getSrc( );
234 if ( superNode != 0 && superNode->getOutEdges( ).size( ) > 0 )
236 QPersistentModelIndex* index = getNodePersistentIndex( superNode );
237 if ( index == 0 )
238 index = new QPersistentModelIndex( createIndex( 0, 0, superNode ) );
239 return ( index != 0 ? QModelIndex( *index ) : QModelIndex( ) );
242 return QModelIndex( );
245 bool GraphItemModel::hasChildren( const QModelIndex& parent ) const
247 return ( rowCount( parent ) > 0 );
250 int GraphItemModel::rowCount( const QModelIndex& parent ) const
252 if ( !parent.isValid( ) )
253 return _rootNodes.size( );
254 else
256 Node* node = static_cast< Node* >( parent.internalPointer( ) );
257 if ( node != 0 )
258 return node->getOutEdges( ).size( );
260 return 0;
263 int GraphItemModel::columnCount( const QModelIndex& parent ) const
265 return 1;
268 bool GraphItemModel::setData ( const QModelIndex& index, const QVariant& value, int role )
270 if ( !index.isValid( ) )
271 return true;
273 if ( value.type( ) == QVariant::String )
275 QString name = value.toString( );
276 Node* node = static_cast< Node* >( index.internalPointer( ) );
277 //_graph.modifyNode( *node, name.toStdString( ), node->getType( ), _graph.findObject( node ) );
278 // FIXME
280 return true;
282 //-----------------------------------------------------------------------------
285 void GraphItemModel::nodeInsertedBegin( Node& node )
287 Node::List inNodes; node.collectInNodes( inNodes );
288 if ( inNodes.size( ) == 0 ) // Root node
289 //beginInsertRows( QModelIndex( ), _rootNodes.size( ), _rootNodes.size( ) + 1 );
290 emit rowsAboutToBeInserted( QModelIndex( ), _rootNodes.size( ), _rootNodes.size( ) + 1 );
291 else
293 for ( Node::List::iterator inNodeIter = inNodes.begin( ); inNodeIter != inNodes.end( ); inNodeIter++ )
295 Node* inNode = *inNodeIter;
296 QPersistentModelIndex* parentPersistentIndex = getNodePersistentIndex( inNode );
297 QModelIndex parentIndex( parentPersistentIndex != 0 ? QModelIndex( *parentPersistentIndex ) : QModelIndex( ) );
298 //beginInsertRows( parentIndex, inNode->getOutDegree( ) /*- 1*/, inNode->getOutDegree( ) /*- 1*/ + 1 );
299 emit rowsAboutToBeInserted( parentIndex, inNode->getOutDegree( ) /*- 1*/, inNode->getOutDegree( ) /*- 1*/ + 1 );
304 void GraphItemModel::nodeInserted( Node& node )
306 Node::List inNodes; node.collectInNodes( inNodes );
307 if ( inNodes.size( ) == 0 /*&& _graph.isRootNode( node )*/ )
309 // Generate persistent model indexes for all graph root nodes
310 Node::List::iterator nodeIter = _rootNodes.begin( );
311 for ( int row = 0; nodeIter != _rootNodes.end( ); row++, nodeIter++ )
312 visit( **nodeIter, row, 0, 1 );
313 //emit rowsInserted( QModelIndex( ), _rootNodes.size( ), _rootNodes.size( ) + 1 );
314 emit rowsInserted( QModelIndex( ), _rootNodes.size( ) - 1, _rootNodes.size( ) );
316 else
318 int nodeRow = 0;
319 for ( Node::List::iterator inNodeIter = inNodes.begin( ); inNodeIter != inNodes.end( ); nodeRow++, inNodeIter++ )
321 Node* inNode = *inNodeIter;
322 QPersistentModelIndex* parentPersistentIndex = getNodePersistentIndex( inNode );
323 QModelIndex parentIndex( parentPersistentIndex != 0 ? QModelIndex( *parentPersistentIndex ) : QModelIndex( ) );
325 visit( *inNode, parentIndex.row( ), 0, 2 );
327 QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node );
328 int nodeRow = 0;
329 if ( nodePersistentIndex != 0 && nodePersistentIndex->isValid( ) )
330 nodeRow = nodePersistentIndex->row( );
331 emit rowsInserted( parentIndex, nodeRow, nodeRow + 1 );
335 // endInsertRows( ); // Bug in QT 4.1.0
336 //emit layoutChanged( );
339 void GraphItemModel::nodeRemovedBegin( Node& node )
341 NodePersistentIndexMap::iterator nodeIter = _nodePersistentIndexMap.find( &node );
342 if ( nodeIter != _nodePersistentIndexMap.end( ) )
344 QPersistentModelIndex* nodePersistentIndex = nodeIter->second;
345 int row = nodePersistentIndex->row( );
346 QModelIndex parentIndex = nodePersistentIndex->parent( );
347 //beginRemoveRows( parentIndex, row, row + 1 );
348 emit rowsAboutToBeRemoved( parentIndex, row, row + 1 );
352 void GraphItemModel::nodeRemoved( Node& node )
354 QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node );
356 // Adjust other concerned node model index (rows and columns index may now be invalid)
358 Node::List inNodes; node.collectInNodes( inNodes );
359 if ( inNodes.size( ) == 0 ) // A removed node should always have no in or out nodes
361 // Generate persistent model indexes for all graph nodes
362 Node::List::iterator nodeIter = _rootNodes.begin( );
363 for ( int row = 0; nodeIter != _rootNodes.end( ); row++, nodeIter++ )
364 visit( **nodeIter, row, 0, 1 );
368 _nodePersistentIndexMap.erase( &node );
370 QModelIndex parentIndex;
371 int nodeRow = 0;
372 if ( nodePersistentIndex != 0 )
374 parentIndex = nodePersistentIndex->parent( );
375 nodeRow = nodePersistentIndex->row( );
378 if ( nodeRow != -1 )
379 emit rowsRemoved( parentIndex, nodeRow, nodeRow + 1 );
381 //endRemoveRows( ); // Bug in QT 4.1.0
382 emit layoutChanged( );
385 void GraphItemModel::nodeChanged( qan::Node& node )
387 QPersistentModelIndex* persistentNodeIndex = getNodePersistentIndex( &node );
388 if ( persistentNodeIndex != 0 )
390 QModelIndex nodeIndex( *persistentNodeIndex );
391 if ( nodeIndex.isValid( ) )
392 emit dataChanged( nodeIndex, nodeIndex );
396 } // ::qan
397 //-----------------------------------------------------------------------------