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 //-----------------------------------------------------------------------------
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
),
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
)
62 visit( node
, row
, column
, marked
, 500 );
65 void GraphItemModel::visit( Node
& node
, int row
, int column
, Node::Set
& marked
, int maxDepth
)
71 if ( marked
.find( &node
) != marked
.end( ) )
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
);
85 // Create a new persistent index
86 nodePersistentIndex
= new QPersistentModelIndex( nodeIndex
);
87 _nodePersistentIndexMap
.insert( std::pair
< Node
*, QPersistentModelIndex
* >( &node
, nodePersistentIndex
) );
93 Edge::List
& edgeList
= node
.getOutEdges( );
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
;
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( ) );
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( ) );
134 case Qt::DisplayRole
:
135 result
= node
->getLabel( );
137 case Qt::DecorationRole
:
138 if ( style
!= 0 && style
->has( "icon" ) )
140 QIcon
icon( style
->getIcon( "icon" ) );
141 if ( !icon
.isNull( ) )
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
);
159 case Qt::TextColorRole
:
163 QColor backColor
= style
->getColor( "textcolor" );
164 if ( backColor
.isValid( ) )
170 case Qt::UserRole
+ POSITION_X
:
171 result
= node
->getPosition( )( 0 );
173 case Qt::UserRole
+ POSITION_Y
:
174 result
= node
->getPosition( )( 1 );
176 case Qt::UserRole
+ DIMENSION_X
:
177 result
= node
->getDimension( )( 0 );
179 case Qt::UserRole
+ DIMENSION_Y
:
180 result
= node
->getDimension( )( 1 );
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
);
202 index
= new QPersistentModelIndex( createIndex( row
, column
, node
) );
203 return ( index
!= 0 ? QModelIndex( *index
) : QModelIndex( ) );
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( );
229 Node
* node
= static_cast< Node
* >( index
.internalPointer( ) );
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
);
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( );
256 Node
* node
= static_cast< Node
* >( parent
.internalPointer( ) );
258 return node
->getOutEdges( ).size( );
263 int GraphItemModel::columnCount( const QModelIndex
& parent
) const
268 bool GraphItemModel::setData ( const QModelIndex
& index
, const QVariant
& value
, int role
)
270 if ( !index
.isValid( ) )
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 ) );
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 );
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( ) );
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
);
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
;
372 if ( nodePersistentIndex
!= 0 )
374 parentIndex
= nodePersistentIndex
->parent( );
375 nodeRow
= nodePersistentIndex
->row( );
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
);
397 //-----------------------------------------------------------------------------