node.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2005 by David Saxton                               *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "cnitem.h"
00012 #include "icndocument.h"
00013 #include "connector.h"
00014 #include "itemdocumentdata.h"
00015 #include "node.h"
00016 
00017 #include <kdebug.h>
00018 
00019 #include <qpainter.h>
00020 
00021 Node::Node( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id )
00022         : QObject(), QCanvasPolygon( icnDocument->canvas() )
00023 {
00024         p_nodeGroup = 0;
00025         p_parentItem = 0;
00026         b_deleted = false;
00027         m_dir = dir;
00028         m_type = type;
00029         p_icnDocument = icnDocument;
00030         m_level = 0;
00031         m_selectedColor = QColor( 101, 134, 192 );
00032 
00033         if (id) {
00034                 m_id = *id;
00035                 if ( !p_icnDocument->registerUID(*id) )
00036                         kdError() << k_funcinfo << "Could not register id " << *id << endl;
00037         } else m_id = p_icnDocument->generateUID("node"+QString::number(type));
00038 
00039         initPoints();
00040         move( pos.x(), pos.y() );
00041         setBrush( Qt::black );
00042         setPen( Qt::black );
00043         show();
00044 
00045         emit (moved(this));
00046 }
00047 
00048 
00049 Node::~Node()
00050 {
00051         p_icnDocument->unregisterUID( id() );
00052 }
00053 
00054 
00055 int Node::rtti() const
00056 {
00057         return ICNDocument::RTTI::Node;
00058 }
00059 
00060 
00061 void Node::setLevel(const int level)
00062 {
00063         m_level = level;
00064 }
00065 
00066 bool Node::acceptInput() const
00067 {
00068         return type() != fp_out;
00069 }
00070 
00071 
00072 bool Node::acceptOutput() const
00073 {
00074         return type() != fp_in;
00075 }
00076 
00077 void Node::setVisible(bool yes)
00078 {
00079         if ( isVisible() == yes)
00080                 return;
00081         
00082         QCanvasPolygon::setVisible(yes);
00083         
00084         const ConnectorList::iterator inputEnd = m_inputConnectorList.end();
00085         for ( ConnectorList::iterator it = m_inputConnectorList.begin(); it != inputEnd; ++it )
00086         {
00087                 Connector *connector = *it;
00088                 if (connector)
00089                 {
00090                         if ( isVisible() )
00091                                 connector->setVisible(true);
00092                         
00093                         else
00094                         {
00095                                 Node *node = connector->startNode();
00096                                 connector->setVisible( node && node->isVisible() );
00097                         }
00098                 }
00099         }
00100         
00101         const ConnectorList::iterator outputEnd = m_outputConnectorList.end();
00102         for ( ConnectorList::iterator it = m_outputConnectorList.begin(); it != outputEnd; ++it )
00103         {
00104                 Connector *connector = *it;
00105                 if (connector)
00106                 {
00107                         if ( isVisible() )
00108                                 connector->setVisible(true);
00109                         
00110                         else
00111                         {
00112                                 Node *node = connector->endNode();
00113                                 connector->setVisible( node && node->isVisible() );
00114                         }
00115                 }
00116         }
00117 }
00118 
00119 
00120 bool Node::isConnected( Node *node, NodeList *checkedNodes )
00121 {
00122         if ( this == node )
00123                 return true;
00124                 
00125         bool firstNode = !checkedNodes;
00126         if (firstNode)
00127                 checkedNodes = new NodeList();
00128                 
00129         else if ( checkedNodes->contains(this) )
00130                 return false;
00131         
00132         
00133         checkedNodes->append(this);
00134         
00135         const ConnectorList::const_iterator inputEnd = m_inputConnectorList.end();
00136         for ( ConnectorList::const_iterator it = m_inputConnectorList.begin(); it != inputEnd; ++it )
00137         {
00138                 Connector *connector = *it;
00139                 if (connector)
00140                 {
00141                         Node *startNode = connector->startNode();
00142                         if ( startNode && startNode->isConnected( node, checkedNodes ) ) {
00143                                 if (firstNode) {
00144                                         delete checkedNodes;
00145                                         checkedNodes = 0;
00146                                 }
00147                                 return true;
00148                         }
00149                 }
00150         }
00151         
00152         const ConnectorList::const_iterator outputEnd = m_outputConnectorList.end();
00153         for ( ConnectorList::const_iterator it = m_outputConnectorList.begin(); it != outputEnd; ++it )
00154         {
00155                 Connector *connector = *it;
00156                 if (connector)
00157                 {
00158                         Node *endNode = connector->endNode();
00159                         if ( endNode && endNode->isConnected( node, checkedNodes ) ) {
00160                                 if (firstNode) {
00161                                         delete checkedNodes;
00162                                         checkedNodes = 0;
00163                                 }
00164                                 return true;
00165                         }
00166                 }
00167         }
00168         
00169         if (firstNode) {
00170                 delete checkedNodes;
00171                 checkedNodes = 0;
00172         }
00173         
00174         return false;
00175 }
00176 
00177 void Node::setOrientation( node_dir dir )
00178 {
00179         if ( m_dir == dir ) return;
00180 
00181         if ( dir != Node::dir_up &&
00182                  dir != Node::dir_right &&
00183                  dir != Node::dir_down &&
00184                  dir != Node::dir_left )
00185         {
00186                 kdDebug() << "Node::setOrientation: Unknown node direction "<<dir<<endl;
00187                 return;
00188         } else m_dir = dir;
00189         initPoints();
00190 }
00191 
00192 
00193 void Node::initPoints()
00194 {
00195         if ( type() == ec_junction )
00196         {
00197                 setPoints( QPointArray( QRect( -4, -4, 8, 8 ) ) );
00198                 return;
00199         }
00200         
00201         if ( type() == fp_junction )
00202         {
00203                 setPoints( QPointArray( QRect( -4, -4, 9, 9 ) ) );
00204                 return;
00205         }
00206         
00207         const int length = ( type() == ec_pin ) ? 8 : -8;
00208         
00209         // Bounding rectangle, facing right
00210         QPointArray pa( QRect( 0, -8, length, 16 ) );
00211         
00212         double angle;
00213         if              ( m_dir == Node::dir_up ) angle = -90.;
00214         else if ( m_dir == Node::dir_right ) angle = 0.;
00215         else if ( m_dir == Node::dir_down ) angle = 90.;
00216         else if ( m_dir == Node::dir_left ) angle = 180.;
00217         else
00218         {
00219                 kdError() << "Node::initPoints: unknown m_dir = "<<m_dir<<endl;
00220                 return;
00221         }
00222         
00223         QWMatrix m;
00224         m.rotate(angle);
00225         pa = m.map(pa);
00226         setPoints(pa);
00227 }
00228 
00229 
00230 QPoint Node::findConnectorDivergePoint( bool * found )
00231 {
00232         bool temp;
00233         if (!found)
00234                 found = &temp;
00235         *found = false;
00236         
00237         if ( numCon( false, false ) != 2 )
00238                 return QPoint(0,0);
00239         
00240         QPointList p1;
00241         QPointList p2;
00242         
00243         int inSize = m_inputConnectorList.count();
00244         
00245         const ConnectorList connectors = m_inputConnectorList + m_outputConnectorList;
00246         const ConnectorList::const_iterator end = connectors.end();
00247         bool gotP1 = false;
00248         bool gotP2 = false;
00249         int at = -1;
00250         for ( ConnectorList::const_iterator it = connectors.begin(); it != end && !gotP2; ++it )
00251         {
00252                 at++;
00253                 if ( !(*it) || !(*it)->canvas() )
00254                         continue;
00255                 
00256                 if (gotP1)
00257                 {
00258                         p2 = (*it)->connectorPoints( at < inSize );
00259                         gotP2 = true;
00260                 }
00261                 else
00262                 {
00263                         p1 = (*it)->connectorPoints( at < inSize );
00264                         gotP1 = true;
00265                 }
00266         }
00267         if ( !gotP1 || !gotP2 )
00268                 return QPoint(0,0);
00269         
00270         unsigned maxLength = p1.size() > p2.size() ? p1.size() : p2.size();
00271         
00272         for ( unsigned i = 1; i < maxLength; ++i ) {
00273                 if ( p1[i] != p2[i] ) {
00274                         *found = true;
00275                         return p1[i-1];
00276                 }
00277         }
00278         return QPoint(0, 0);
00279 }
00280 
00281 void Node::setParentItem( CNItem *parentItem )
00282 {
00283         if (!parentItem) {
00284                 kdError() << k_funcinfo << "no parent item" << endl;
00285                 return;
00286         }
00287 
00288         p_parentItem = parentItem;
00289 
00290         setLevel(p_parentItem->level());
00291 
00292         connect( p_parentItem, SIGNAL(movedBy(double, double )), this, SLOT(moveBy(double, double)) );
00293         connect( p_parentItem, SIGNAL(removed(Item*)), this, SLOT(removeNode(Item*)) );
00294 }
00295 
00296 void Node::removeNode()
00297 {
00298         if (b_deleted) return;
00299 
00300         b_deleted = true;
00301 
00302         emit removed(this);
00303         p_icnDocument->appendDeleteList(this);
00304 }
00305 
00306 void Node::moveBy( double dx, double dy )
00307 {
00308         if ( dx == 0 && dy == 0 ) return;
00309         QCanvasPolygon::moveBy( dx, dy );
00310         emit moved(this);
00311 }
00312 
00313 int Node::numCon( bool includeParentItem, bool includeHiddenConnectors ) const
00314 {
00315         unsigned count = 0;
00316         
00317         const ConnectorList connectors[2] = { m_inputConnectorList, m_outputConnectorList };
00318         
00319         for ( unsigned i = 0; i < 2; i++ )
00320         {
00321                 ConnectorList::const_iterator end = connectors[i].end();
00322                 for ( ConnectorList::const_iterator it = connectors[i].begin(); it != end; ++it )
00323                 {
00324                         if ( *it && (includeHiddenConnectors || (*it)->canvas()) )
00325                                 count++;
00326                 }
00327         }
00328         
00329         if ( isChildNode() && includeParentItem )
00330                 count++;
00331         
00332         return count;
00333 }
00334 
00335 
00336 void Node::addOutputConnector( Connector * const connector )
00337 {
00338         if ( type() == fp_in || !handleNewConnector(connector) )
00339                 return;
00340 
00341         m_outputConnectorList.append(connector);
00342 
00343         if(type() == fp_out || type() == fp_junction) {
00344                 // We can only have one output connector, so remove the others. Note
00345                 // that this code has to come *after* adding the new output connector,
00346                 // as this node will delete itself if it's an fp_junction and there are
00347                 // no output connectors.
00348                 
00349                 const ConnectorList connectors = m_outputConnectorList;
00350                 const ConnectorList::const_iterator end = connectors.end();
00351                 for ( ConnectorList::const_iterator it = connectors.begin(); it != end; ++it ) {
00352                         Connector * con = *it;
00353                         if ( con && con != connector )
00354                                 con->removeConnector();
00355                 }
00356         }
00357 
00358         m_outputConnectorList.remove((Connector*)0);
00359 }
00360 
00361 void Node::addInputConnector( Connector * const connector )
00362 {
00363         if ( type() == fp_out || !handleNewConnector(connector) )
00364                 return;
00365 
00366         m_inputConnectorList.append(connector);
00367 }
00368 
00369 bool Node::handleNewConnector( Connector * connector )
00370 {
00371         if (!connector) return false;
00372         
00373         if(m_inputConnectorList.contains(connector) || m_outputConnectorList.contains(connector)) {
00374                 kdWarning() << k_funcinfo << " Already have connector = " << connector << endl;
00375                 return false;
00376         }
00377         
00378         connect( this, SIGNAL(removed(Node*)), connector, SLOT(removeConnector(Node*)) );
00379         connect( connector, SIGNAL(removed(Connector*)), this, SLOT(checkForRemoval(Connector*)) );
00380         connect( connector, SIGNAL(selected(bool)), this, SLOT(setNodeSelected(bool)) );
00381 
00382         if ( !isChildNode() )
00383                 p_icnDocument->slotRequestAssignNG();
00384 
00385         return true;
00386 }
00387 
00388 Connector* Node::createInputConnector( Node * startNode )
00389 {
00390         if(type() == fp_out || !startNode) return 0;
00391 
00392         Connector *connector = new Connector( startNode, this, p_icnDocument );
00393         addInputConnector(connector);
00394 
00395         return connector;
00396 }
00397 
00398 void Node::removeConnector( Connector *connector )
00399 {
00400         if (!connector) return;
00401 
00402         ConnectorList::iterator it;
00403 
00404         it = m_inputConnectorList.find(connector);
00405         if(it != m_inputConnectorList.end() ) {
00406                 (*it)->removeConnector();
00407                 (*it) = 0;
00408         }
00409 
00410         it = m_outputConnectorList.find(connector);
00411         if(it != m_outputConnectorList.end()) {
00412                 (*it)->removeConnector();
00413                 (*it) = 0;
00414         }
00415 }
00416 
00417 void Node::checkForRemoval( Connector *connector )
00418 {
00419         removeConnector(connector);
00420         setNodeSelected(false);
00421 
00422         removeNullConnectors();
00423 
00424         if (!p_parentItem) {
00425                 int conCount = m_inputConnectorList.count() + m_outputConnectorList.count();
00426                 if ( conCount < 2 ) removeNode();
00427         }
00428 
00429         if ( type() == Node::fp_junction && m_outputConnectorList.isEmpty() )
00430                 removeNode();
00431 }
00432 
00433 void Node::removeNullConnectors()
00434 {
00435         m_inputConnectorList.remove((Connector*)0);
00436         m_outputConnectorList.remove((Connector*)0);
00437 }
00438 
00439 NodeData Node::nodeData() const
00440 {
00441         NodeData data;
00442         data.x = x();
00443         data.y = y();
00444         return data;
00445 }
00446 
00447 void Node::setNodeSelected( bool yes )
00448 {
00449         if ( isSelected() == yes ) return;
00450 
00451         QCanvasItem::setSelected(yes);
00452 
00453         setPen(   yes ? m_selectedColor : Qt::black );
00454         setBrush( yes ? m_selectedColor : Qt::black );
00455 }
00456 
00457 #include "node.moc"
00458 

Generated on Tue May 8 17:05:31 2007 for KTechLab by  doxygen 1.5.1