circuitdocument.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 "canvasmanipulator.h"
00012 #include "circuitdocument.h"
00013 #include "circuitview.h"
00014 #include "component.h"
00015 #include "connector.h"
00016 #include "core/ktlconfig.h"
00017 #include "cnitemgroup.h"
00018 #include "documentiface.h"
00019 #include "drawpart.h"
00020 #include "ecnode.h"
00021 #include "itemdocumentdata.h"
00022 #include "ktechlab.h"
00023 #include "pin.h"
00024 #include "simulator.h"
00025 #include "subcircuits.h"
00026 #include "switch.h"
00027 
00028 #include <kdebug.h>
00029 #include <kinputdialog.h> 
00030 #include <klocale.h>
00031 #include <kmessagebox.h>
00032 #include <qregexp.h>
00033 #include <qtimer.h>
00034 #include <cassert>
00035 
00036 CircuitDocument::CircuitDocument( const QString & caption, KTechlab *ktechlab, const char *name )
00037         : ICNDocument( caption, ktechlab, name )
00038 {
00039         m_pOrientationAction = new KActionMenu( i18n("Orientation"), "rotate", this );
00040         
00041         m_type = Document::dt_circuit;
00042         m_pDocumentIface = new CircuitDocumentIface(this);
00043         m_fileExtensionInfo = i18n("*.circuit|Circuit(*.circuit)\n*|All Files");
00044         
00045         m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() );
00046         m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() );
00047         m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() );
00048         m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() );
00049         m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() );
00050         m_cmManager->addManipulatorInfo( CMItemDrag::manipulatorInfo() );
00051         
00052         connect( this, SIGNAL(connectorAdded(Connector*)), this, SLOT(requestAssignCircuits()) );
00053         connect( this, SIGNAL(connectorAdded(Connector*)), this, SLOT(connectorAdded(Connector*)) );
00054         
00055         m_updateCircuitsTmr = new QTimer();
00056         connect( m_updateCircuitsTmr, SIGNAL(timeout()), this, SLOT(assignCircuits()) );
00057         
00058         requestStateSave();
00059 }
00060 
00061 CircuitDocument::~CircuitDocument()
00062 {
00063         m_bDeleted = true;
00064         deleteCircuits();
00065         
00066         delete m_updateCircuitsTmr;
00067         delete m_pDocumentIface;
00068 }
00069 
00070 void CircuitDocument::slotInitItemActions( Item *itemBase )
00071 {
00072         ICNDocument::slotInitItemActions(itemBase);
00073         
00074         CircuitView * activeCircuitView = dynamic_cast<CircuitView*>(activeView());
00075         if ( !p_ktechlab || !activeCircuitView )
00076                 return;
00077         
00078         Component * item = dynamic_cast<Component*>(itemBase);
00079         
00080         if ( !item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() )
00081                 return;
00082         
00083         KAction * orientation_actions[] = {
00084                 activeCircuitView->action("edit_orientation_0"),
00085                 activeCircuitView->action("edit_orientation_90"),
00086                 activeCircuitView->action("edit_orientation_180"),
00087                 activeCircuitView->action("edit_orientation_270") };
00088 
00089         if ( !item || !item->canRotate() ) {
00090                 for ( unsigned i = 0; i < 4; ++i )
00091                         orientation_actions[i]->setEnabled(false);
00092                 return;
00093         }
00094 
00095         for ( unsigned i = 0; i < 4; ++ i) {
00096                 orientation_actions[i]->setEnabled(true);
00097                 m_pOrientationAction->remove( orientation_actions[i] );
00098                 m_pOrientationAction->insert( orientation_actions[i] );
00099         }
00100 
00101         if ( item->angleDegrees() == 0 )
00102                 (static_cast<KToggleAction*>( orientation_actions[0] ))->setChecked(true);
00103         else if ( item->angleDegrees() == 90 )
00104                 (static_cast<KToggleAction*>( orientation_actions[1] ))->setChecked(true);
00105         else if ( item->angleDegrees() == 180 )
00106                 (static_cast<KToggleAction*>( orientation_actions[2] ))->setChecked(true);
00107         else if ( item->angleDegrees() == 270 )
00108                 (static_cast<KToggleAction*>( orientation_actions[3] ))->setChecked(true);
00109 }
00110 
00111 void CircuitDocument::rotateCounterClockwise()
00112 {
00113         m_selectList->slotRotateCCW();
00114         requestRerouteInvalidatedConnectors();
00115 }
00116 
00117 void CircuitDocument::rotateClockwise()
00118 {
00119         m_selectList->slotRotateCW();
00120         requestRerouteInvalidatedConnectors();
00121 }
00122 
00123 void CircuitDocument::itemFlip()
00124 {
00125         m_selectList->slotFlip();
00126         requestRerouteInvalidatedConnectors();
00127 }
00128 
00129 void CircuitDocument::setOrientation0()
00130 {
00131         m_selectList->slotSetOrientation0();
00132         requestRerouteInvalidatedConnectors();
00133 }
00134 
00135 void CircuitDocument::setOrientation90()
00136 {
00137         m_selectList->slotSetOrientation90();
00138         requestRerouteInvalidatedConnectors();
00139 }
00140 
00141 void CircuitDocument::setOrientation180()
00142 {
00143         m_selectList->slotSetOrientation180();
00144         requestRerouteInvalidatedConnectors();
00145 }
00146 
00147 void CircuitDocument::setOrientation270()
00148 {
00149         m_selectList->slotSetOrientation270();
00150         requestRerouteInvalidatedConnectors();
00151 }
00152 
00153 View *CircuitDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name )
00154 {
00155         View *view = new CircuitView( this, viewContainer, viewAreaId, name );
00156         handleNewView(view);
00157         return view;
00158 }
00159 
00160 void CircuitDocument::slotUpdateConfiguration()
00161 {
00162         ICNDocument::slotUpdateConfiguration();
00163 
00164         NodeList::iterator nodeEnd = m_nodeList.end();
00165         for(NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it) {
00166                 (static_cast<ECNode*>((Node*)*it))->setShowVoltageBars( KTLConfig::showVoltageBars() );
00167         }
00168 
00169         ComponentList::iterator componentsEnd = m_componentList.end();
00170         for(ComponentList::iterator it = m_componentList.begin(); it != componentsEnd; ++it)
00171                 (*it)->slotUpdateConfiguration();
00172 }
00173 
00174 void CircuitDocument::update()
00175 {
00176         ICNDocument::update();
00177 
00178         if(KTLConfig::showVoltageBars()) {
00179                 NodeList::iterator end = m_nodeList.end();
00180                 for(NodeList::iterator it = m_nodeList.begin(); it != end; ++it ) {
00181                         (static_cast<ECNode*>((Node*)*it))->setNodeChanged();
00182                 }
00183         }
00184 }
00185 
00186 void CircuitDocument::fillContextMenu( const QPoint &pos )
00187 {
00188         ICNDocument::fillContextMenu(pos);
00189 
00190         CircuitView *activeCircuitView = dynamic_cast<CircuitView*>(activeView());
00191 
00192         if(m_selectList->count() < 1 || !activeCircuitView ) return;
00193 
00194         Component *item = dynamic_cast<Component*>( selectList()->activeItem() );
00195 
00196         // NOTE: I negated this whole condition because I couldn't make out quite what the
00197         //logic was --electronerd
00198         if(!(!item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() )) {
00199                 KAction *orientation_actions[] = {
00200                         activeCircuitView->action("edit_orientation_0"),
00201                         activeCircuitView->action("edit_orientation_90"),
00202                         activeCircuitView->action("edit_orientation_180"),
00203                         activeCircuitView->action("edit_orientation_270") };
00204         
00205                 if(!item || !item->canRotate() ) return;
00206         
00207                 for(unsigned i = 0; i < 4; ++ i) {
00208                         m_pOrientationAction->remove( orientation_actions[i] );
00209                         m_pOrientationAction->insert( orientation_actions[i] );
00210                 }
00211 
00212                 QPtrList<KAction> orientation_actionlist;
00213         //      orientation_actionlist.prepend( new KActionSeparator() );
00214                 orientation_actionlist.append( m_pOrientationAction );
00215                 p_ktechlab->plugActionList( "orientation_actionlist", orientation_actionlist );
00216         }
00217         
00218         if(m_selectList->count() > 1 && countExtCon(m_selectList->items()) > 0) {
00219                 QPtrList<KAction> component_actionlist;
00220         //      component_actionlist.append( new KActionSeparator() );
00221                 component_actionlist.append( activeCircuitView->action("circuit_create_subcircuit") );
00222                 p_ktechlab->plugActionList( "component_actionlist", component_actionlist );
00223         }
00224 }
00225 
00226 void CircuitDocument::deleteCircuits()
00227 {
00228         const CircuitList::iterator end = m_circuitList.end();
00229         for(CircuitList::iterator it = m_circuitList.begin(); it != end; ++it ) {
00230                 Simulator::self()->detachCircuit(*it);
00231                 delete *it;
00232         }
00233 
00234         m_circuitList.clear();
00235         m_pinList.clear();
00236         m_wireList.clear();
00237 }
00238 
00239 void CircuitDocument::requestAssignCircuits() {
00240 //      kdDebug() << k_funcinfo << endl;
00241         deleteCircuits();
00242         m_updateCircuitsTmr->stop();
00243         m_updateCircuitsTmr->start( 0, true );
00244 }
00245 
00246 void CircuitDocument::connectorAdded( Connector * connector )
00247 {
00248         if (connector) {
00249                 connect( connector, SIGNAL(numWiresChanged(unsigned )), this, SLOT(requestAssignCircuits()) );
00250                 connect( connector, SIGNAL(removed(Connector*)), this, SLOT(requestAssignCircuits()) );
00251         }
00252 }
00253 
00254 void CircuitDocument::itemAdded( Item * item)
00255 {
00256         ICNDocument::itemAdded( item );
00257         componentAdded( item );
00258 }
00259 
00260 void CircuitDocument::componentAdded( Item * item )
00261 {
00262         Component *component = dynamic_cast<Component*>(item);
00263 
00264         if(!component) return;
00265 
00266         requestAssignCircuits();
00267 
00268         connect( component, SIGNAL(elementCreated(Element*)), this, SLOT(requestAssignCircuits()) );
00269         connect( component, SIGNAL(elementDestroyed(Element*)), this, SLOT(requestAssignCircuits()) );
00270         connect( component, SIGNAL(removed(Item*)), this, SLOT(componentRemoved(Item*)) );
00271         
00272         // We don't attach the component to the Simulator just yet, as the
00273         // Component's vtable is not yet fully constructed, and so Simulator can't
00274         // tell whether or not it is a logic component
00275         if ( !m_toSimulateList.contains(component) )
00276                 m_toSimulateList << component;
00277 }
00278 
00279 void CircuitDocument::componentRemoved( Item * item )
00280 {
00281         Component *component = dynamic_cast<Component*>(item);
00282 
00283         if (!component) return;
00284 
00285         m_componentList.remove(component);
00286 
00287         requestAssignCircuits();
00288         Simulator::self()->detachComponent(component);
00289 }
00290 
00291 void CircuitDocument::calculateConnectorCurrents()
00292 {
00293         const CircuitList::iterator circuitEnd = m_circuitList.end();
00294         for(CircuitList::iterator it = m_circuitList.begin(); it != circuitEnd; ++it )
00295                 (*it)->updateCurrents();
00296 
00297         PinList groundPins;
00298 
00299         // Tell the Pins to reset their calculated currents to zero
00300 
00301         m_pinList.remove((Pin*)0);
00302         const PinList::iterator pinEnd = m_pinList.end();
00303         for(PinList::iterator it = m_pinList.begin(); it != pinEnd; ++it )  {
00304                 if(Pin *n = dynamic_cast<Pin*>((Pin*)*it) ) {
00305                         n->resetCurrent();
00306                         n->setSwitchCurrentsUnknown();
00307                         
00308                         if ( !n->parentECNode()->isChildNode() ) {
00309                                 n->setCurrentKnown( true );
00310                                 // (and it has a current of 0 amps)
00311                         } else if ( n->groundType() == Pin::gt_always ) {
00312                                 groundPins << n;
00313                                 n->setCurrentKnown( false );
00314                         } else {
00315                                 // Child node that is non ground
00316                                 n->setCurrentKnown( n->parentECNode()->numPins() < 2 );
00317                         }
00318                 }
00319         }
00320 
00321         // Tell the components to update their ECNode's currents' from the elements
00322         const ComponentList::iterator componentEnd = m_componentList.end();
00323         for ( ComponentList::iterator it = m_componentList.begin(); it != componentEnd; ++it ) (*it)->setNodalCurrents();
00324 
00325         // And now for the wires and switches...
00326         m_wireList.remove((Wire*)0);
00327         const WireList::iterator clEnd = m_wireList.end();
00328         for ( WireList::iterator it = m_wireList.begin(); it != clEnd; ++it )
00329                 (*it)->setCurrentKnown(false);
00330 
00331         SwitchList switches = m_switchList;
00332         WireList wires = m_wireList;
00333         bool found = true;
00334         while((!wires.isEmpty() || !switches.isEmpty() || !groundPins.isEmpty()) && found ) {
00335                 found = false;
00336                 
00337                 WireList::iterator wiresEnd = wires.end();
00338                 for ( WireList::iterator it = wires.begin(); it != wiresEnd; )
00339                 {
00340                         if ( (*it)->calculateCurrent() )  {
00341                                 found = true;
00342                                 WireList::iterator oldIt = it;
00343                                 ++it;
00344                                 wires.remove(oldIt);
00345                         } else ++it;
00346                 }
00347 
00348                 SwitchList::iterator switchesEnd = switches.end();
00349                 for(SwitchList::iterator it = switches.begin(); it != switchesEnd; ) {
00350                         if ( (*it)->calculateCurrent() ) {
00351                                 found = true;
00352                                 SwitchList::iterator oldIt = it;
00353                                 ++it;
00354                                 switches.remove(oldIt);
00355                         } else ++it;
00356                 }
00357 
00358                 PinList::iterator groundPinsEnd = groundPins.end();
00359                 for(PinList::iterator it = groundPins.begin(); it != groundPinsEnd; ) {
00360                         if ( (*it)->calculateCurrentFromWires() )
00361                         {
00362                                 found = true;
00363                                 PinList::iterator oldIt = it;
00364                                 ++it;
00365                                 groundPins.remove(oldIt);
00366                         } else ++it;
00367                 }
00368         }
00369 }
00370 
00371 void CircuitDocument::assignCircuits()
00372 {
00373         // Now we can finally add the unadded components to the Simulator
00374         const ComponentList::iterator toSimulateEnd = m_toSimulateList.end();
00375         for ( ComponentList::iterator it = m_toSimulateList.begin(); it != toSimulateEnd; ++it )
00376                 Simulator::self()->attachComponent(*it);
00377         m_toSimulateList.clear();
00378         
00379         // Stage 0: Build up pin and wire lists
00380         m_pinList.clear();
00381         const NodeList::const_iterator nodeListEnd = m_nodeList.end();
00382         for ( NodeList::const_iterator it = m_nodeList.begin(); it != nodeListEnd; ++it ) {
00383                 if ( ECNode * ecnode = dynamic_cast<ECNode*>((Node*)*it) ) {
00384                         for ( unsigned i = 0; i < ecnode->numPins(); i++ )
00385                                 m_pinList << ecnode->pin(i);
00386                 }
00387         }
00388 
00389         m_wireList.clear();
00390         const ConnectorList::const_iterator connectorListEnd = m_connectorList.end();
00391         for ( ConnectorList::const_iterator it = m_connectorList.begin(); it != connectorListEnd; ++it ) {
00392                 for ( unsigned i = 0; i < (*it)->numWires(); i++ )
00393                         m_wireList << (*it)->wire(i);
00394         }
00395 
00396         typedef QValueList<PinList> PinListList;
00397 
00398         // Stage 1: Partition the circuit up into dependent areas (bar splitting
00399         // at ground pins)
00400         PinList unassignedPins = m_pinList;
00401         PinListList pinListList;
00402 
00403         while(!unassignedPins.isEmpty() ) {
00404                 PinList pinList;
00405                 getPartition( *unassignedPins.begin(), & pinList, & unassignedPins );
00406                 pinListList.append(pinList);
00407         }
00408 //      kdDebug () << "pinListList.size()="<<pinListList.size()<<endl;
00409         
00410         // Stage 2: Split up each partition into circuits by ground pins
00411         const PinListList::iterator nllEnd = pinListList.end();
00412 
00413         for ( PinListList::iterator it = pinListList.begin(); it != nllEnd; ++it )
00414                 splitIntoCircuits(&*it);
00415         
00416         // Stage 3: Initialize the circuits
00417         m_circuitList.remove(0);
00418         CircuitList::iterator circuitListEnd = m_circuitList.end();
00419 
00420         for(CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it) (*it)->init();
00421 
00422         m_switchList.clear();
00423         m_componentList.clear();
00424         const ItemList::const_iterator cilEnd = m_itemList.end();
00425 
00426         for(ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it ) {
00427                 Component * component = dynamic_cast<Component*>((Item*)(*it));
00428                 if ( !component ) continue;
00429 
00430                 m_componentList << component;
00431                 component->initElements(0);
00432                 m_switchList += component->switchList();
00433         }
00434 
00435         circuitListEnd = m_circuitList.end();
00436         for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it )
00437                 (*it)->createMatrixMap();
00438         
00439         for(ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it ) {
00440                 Component * component = dynamic_cast<Component*>((Item*)(*it));
00441                 if (component)
00442                         component->initElements(1);
00443         }
00444         
00445         circuitListEnd = m_circuitList.end();
00446         for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it ) {
00447                 (*it)->initCache();
00448                 Simulator::self()->attachCircuit(*it);
00449         }
00450 }
00451 
00452 void CircuitDocument::getPartition( Pin *pin, PinList *pinList, PinList *unassignedPins, bool onlyGroundDependent ) {
00453         if(!pin) return;
00454 
00455         unassignedPins->remove(pin);
00456         
00457         if ( pinList->contains(pin) ) return;
00458 
00459         pinList->append(pin);
00460 
00461         const PinList localConnectedPins = pin->localConnectedPins();
00462         const PinList::const_iterator end = localConnectedPins.end();
00463 
00464         for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it )
00465                 getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
00466         
00467         const PinList groundDependentPins = pin->groundDependentPins();
00468         const PinList::const_iterator dEnd = groundDependentPins.end();
00469 
00470         for ( PinList::const_iterator it = groundDependentPins.begin(); it != dEnd; ++it )
00471                 getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
00472 
00473         if (!onlyGroundDependent) {
00474                 PinList circuitDependentPins = pin->circuitDependentPins();
00475                 const PinList::const_iterator dEnd = circuitDependentPins.end();
00476                 for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it )
00477                         getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
00478         }
00479 }
00480 
00481 void CircuitDocument::splitIntoCircuits( PinList *pinList )
00482 {
00483         // First: identify ground
00484         PinList unassignedPins = *pinList;
00485 
00486         typedef QValueList<PinList> PinListList;
00487 
00488         PinListList pinListList;
00489         while ( !unassignedPins.isEmpty() ) {
00490                 PinList tempPinList;
00491                 getPartition( *unassignedPins.begin(), & tempPinList, & unassignedPins, true );
00492                 pinListList.append(tempPinList);
00493         }
00494 
00495         const PinListList::iterator nllEnd = pinListList.end();
00496         for(PinListList::iterator it = pinListList.begin(); it != nllEnd; ++it )
00497                 Circuit::identifyGround(*it);
00498 
00499         bool allGround = false;
00500         while(!pinList->isEmpty() && !allGround ) {
00501                 PinList::iterator end = pinList->end();
00502                 PinList::iterator it = pinList->begin();
00503 
00504                 while(it != end && (*it)->eqId() == -1 )
00505                         ++it;
00506 
00507                 if ( it == end ) allGround = true;
00508                 else {
00509                         Circuitoid *circuitoid = new Circuitoid;
00510                         recursivePinAdd( *it, circuitoid, pinList );
00511 
00512                         if ( !tryAsLogicCircuit(circuitoid) )
00513                                 m_circuitList += createCircuit(circuitoid);
00514 
00515                         delete circuitoid;
00516                 }
00517         }
00518 
00519         // Remaining pins are ground; tell them about it
00520         // TODO This is a bit hacky....
00521         const PinList::iterator end = pinList->end();
00522         for(PinList::iterator it = pinList->begin(); it != end; ++it ) {
00523                 (*it)->setVoltage(0.0);
00524 
00525                 ElementList elements = (*it)->elements();
00526                 const ElementList::iterator eEnd = elements.end();
00527                 for(ElementList::iterator it = elements.begin(); it != eEnd; ++it )
00528                 {
00529                         if(LogicIn * logicIn = dynamic_cast<LogicIn*>(*it) ) {
00530                                 logicIn->setLastState(false);
00531                                 logicIn->callCallback();
00532                         }
00533                 }
00534         }
00535 }
00536 
00537 void CircuitDocument::recursivePinAdd( Pin *pin, Circuitoid *circuitoid, PinList *unassignedPins )
00538 {
00539         if (!pin) return;
00540 
00541         if ( pin->eqId() != -1 )
00542                 unassignedPins->remove(pin);
00543 
00544         if ( circuitoid->contains(pin) ) return;
00545 
00546         circuitoid->addPin(pin);
00547 
00548         if ( pin->eqId() == -1 ) return;
00549 
00550         const PinList localConnectedPins = pin->localConnectedPins();
00551         const PinList::const_iterator end = localConnectedPins.end();
00552 
00553         for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it )
00554                 recursivePinAdd( *it, circuitoid, unassignedPins );
00555 
00556         const WireList inputList = pin->inputWireList();
00557         WireList::const_iterator conEnd = inputList.end();
00558 
00559         for ( WireList::const_iterator it = inputList.begin(); it != conEnd; ++it )
00560                 circuitoid->addWire(*it);
00561 
00562         const WireList outputList = pin->outputWireList();
00563         conEnd = outputList.end();
00564 
00565         for ( WireList::const_iterator it = outputList.begin(); it != conEnd; ++it )
00566                 circuitoid->addWire(*it);
00567         
00568         const PinList groundDependentPins = pin->groundDependentPins();
00569         const PinList::const_iterator gdEnd = groundDependentPins.end();
00570 
00571         for ( PinList::const_iterator it = groundDependentPins.begin(); it != gdEnd; ++it )
00572                 recursivePinAdd( *it, circuitoid, unassignedPins );
00573 
00574         const PinList circuitDependentPins = pin->circuitDependentPins();
00575         const PinList::const_iterator cdEnd = circuitDependentPins.end();
00576 
00577         for ( PinList::const_iterator it = circuitDependentPins.begin(); it != cdEnd; ++it )
00578                 recursivePinAdd( *it, circuitoid, unassignedPins );
00579         
00580         const ElementList elements = pin->elements();
00581         const ElementList::const_iterator eEnd = elements.end();
00582 
00583         for ( ElementList::const_iterator it = elements.begin(); it != eEnd; ++it )
00584                 circuitoid->addElement(*it);
00585 }
00586 
00587 bool CircuitDocument::tryAsLogicCircuit( Circuitoid *circuitoid )
00588 {
00589         if (!circuitoid) return false;
00590         
00591         if ( circuitoid->elementList.size() == 0 )
00592         {
00593                 // This doesn't quite belong here...but whatever. Initialize all
00594                 // pins to voltage zero as they won't get set to zero otherwise
00595                 const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd();
00596                 for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it )
00597                         (*it)->setVoltage(0.0);
00598                 
00599                 // A logic circuit only requires there to be no non-logic components,
00600                 // and at most one LogicOut - so this qualifies
00601                 return true;
00602         }
00603 
00604         LogicInList logicInList;
00605         LogicOut *out = 0;
00606 
00607         uint logicInCount = 0;
00608         uint logicOutCount = 0;
00609         ElementList::const_iterator end = circuitoid->elementList.end();
00610         for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it ) {
00611                 if ( (*it)->type() == Element::Element_LogicOut ) {
00612                         logicOutCount++;
00613                         out = static_cast<LogicOut*>(*it);
00614                 } else if ( (*it)->type() == Element::Element_LogicIn ) {
00615                         logicInCount++;
00616                         logicInList += static_cast<LogicIn*>(*it);
00617                 } else return false;
00618         }
00619 
00620         if ( logicOutCount > 1 ) return false;
00621         else if ( logicOutCount == 1 )
00622                 Simulator::self()->createLogicChain( out, logicInList, circuitoid->pinList );
00623         else {
00624                 // We have ourselves stranded LogicIns...so lets set them all to low
00625 
00626                 const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd();
00627                 for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it )
00628                         (*it)->setVoltage(0.0);
00629 
00630                 for(ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it) {
00631                         LogicIn * logicIn = static_cast<LogicIn*>(*it);
00632                         logicIn->setNextLogic(0);
00633                         logicIn->setElementSet(0);
00634                         if ( logicIn->isHigh() ) {
00635                                 logicIn->setLastState(false);
00636                                 logicIn->callCallback();
00637                         }
00638                 }
00639         }
00640 
00641         return true;
00642 }
00643 
00644 Circuit *CircuitDocument::createCircuit( Circuitoid *circuitoid )
00645 {
00646         if (!circuitoid) return 0;
00647 
00648         Circuit *circuit = new Circuit();
00649 
00650         const PinList::const_iterator nEnd = circuitoid->pinList.end();
00651         for ( PinList::const_iterator it = circuitoid->pinList.begin(); it != nEnd; ++it )
00652                 circuit->addPin(*it);
00653 
00654         const ElementList::const_iterator eEnd = circuitoid->elementList.end();
00655         for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != eEnd; ++it )
00656                 circuit->addElement(*it);
00657 
00658         return circuit;
00659 }
00660 
00661 void CircuitDocument::createSubcircuit()
00662 {
00663         ItemList itemList = m_selectList->items();
00664         const ItemList::iterator itemListEnd = itemList.end();
00665         for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it ) {
00666                 if( !dynamic_cast<Component*>((Item*)*it) ) *it = 0;
00667         }
00668 
00669         itemList.remove((Item*)0);
00670         
00671         if ( itemList.isEmpty() ) {
00672                 KMessageBox::sorry( activeView(), i18n("No components were found in the selection.") );
00673                 return;
00674         }
00675 
00676         // Number of external connections
00677         const int extConCount = countExtCon(itemList);
00678         if ( extConCount == 0 ) {
00679                 KMessageBox::sorry( activeView(), i18n("No External Connection components were found in the selection.") );
00680                 return;
00681         }
00682         
00683         bool ok;
00684         const QString name = KInputDialog::getText( "Subcircuit", "Name", QString::null, &ok, activeView() );
00685 
00686         if (!ok) return;
00687 
00688         SubcircuitData subcircuit;
00689         subcircuit.addItems(itemList);
00690         subcircuit.addNodes( getCommonNodes(itemList) );
00691         subcircuit.addConnectors( getCommonConnectors(itemList) );
00692 
00693         Subcircuits::addSubcircuit( name, subcircuit.toXML() );
00694 }
00695 
00696 int CircuitDocument::countExtCon( const ItemList &itemList ) const
00697 {
00698         int count = 0;
00699         const ItemList::const_iterator end = itemList.end();
00700         for(ItemList::const_iterator it = itemList.begin(); it != end; ++it ) {
00701                 Item *item = *it;
00702                 if(item && item->type() == "ec/external_connection" )
00703                         count++;
00704         }
00705         return count;
00706 }
00707 
00708 bool CircuitDocument::isValidItem( const QString &itemId )
00709 {
00710         return itemId.startsWith("ec/") || itemId.startsWith("dp/") || itemId.startsWith("sc/");
00711 }
00712 
00713 bool CircuitDocument::isValidItem( Item *item )
00714 {
00715         return (dynamic_cast<Component*>(item) || dynamic_cast<DrawPart*>(item));
00716 }
00717 
00718 void CircuitDocument::displayEquations()
00719 {
00720         kdDebug() << "######################################################" << endl;
00721         const CircuitList::iterator end = m_circuitList.end();
00722         int i = 1;
00723         for(CircuitList::iterator it = m_circuitList.begin(); it != end; ++it ) {
00724                 kdDebug() << "Equation set "<<i<<":\n";
00725                 (*it)->displayEquations();
00726                 i++;
00727         }
00728         kdDebug() << "######################################################" << endl;
00729 }
00730 
00731 #include "circuitdocument.moc"
00732 

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