You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/circuitdocument.cpp

822 lines
23 KiB

/***************************************************************************
* Copyright (C) 2003-2005 by David Saxton *
* david@bluehaze.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "canvasmanipulator.h"
#include "circuitdocument.h"
#include "circuitview.h"
#include "component.h"
#include "connector.h"
#include "core/ktlconfig.h"
#include "cnitemgroup.h"
#include "documentiface.h"
#include "drawpart.h"
#include "ecnode.h"
#include "itemdocumentdata.h"
#include "ktechlab.h"
#include "pin.h"
#include "simulator.h"
#include "subcircuits.h"
#include "switch.h"
#include <kdebug.h>
#include <kinputdialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <tqregexp.h>
#include <tqtimer.h>
CircuitDocument::CircuitDocument( const TQString & caption, KTechlab *ktechlab, const char *name )
: ICNDocument( caption, ktechlab, name )
{
m_pOrientationAction = new KActionMenu( i18n("Orientation"), "rotate", this );
m_type = Document::dt_circuit;
m_pDocumentIface = new CircuitDocumentIface(this);
m_fileExtensionInfo = i18n("*.circuit|Circuit(*.circuit)\n*|All Files");
m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() );
m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() );
m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() );
m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() );
m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() );
m_cmManager->addManipulatorInfo( CMItemDrag::manipulatorInfo() );
connect( this, TQT_SIGNAL(connectorAdded(Connector*)), this, TQT_SLOT(requestAssignCircuits()) );
connect( this, TQT_SIGNAL(connectorAdded(Connector*)), this, TQT_SLOT(connectorAdded(Connector*)) );
m_updateCircuitsTmr = new TQTimer();
connect( m_updateCircuitsTmr, TQT_SIGNAL(timeout()), this, TQT_SLOT(assignCircuits()) );
requestStateSave();
}
CircuitDocument::~CircuitDocument()
{
m_bDeleted = true;
deleteCircuits();
delete m_updateCircuitsTmr;
m_updateCircuitsTmr = 0l;
delete m_pDocumentIface;
m_pDocumentIface = 0l;
}
void CircuitDocument::slotInitItemActions( Item *itemBase )
{
ICNDocument::slotInitItemActions(itemBase);
CircuitView * activeCircuitView = dynamic_cast<CircuitView*>(activeView());
if ( !p_ktechlab || !activeCircuitView )
return;
Component * item = dynamic_cast<Component*>(itemBase);
if ( !item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() )
return;
KAction * orientation_actions[] = {
activeCircuitView->action("edit_orientation_0"),
activeCircuitView->action("edit_orientation_90"),
activeCircuitView->action("edit_orientation_180"),
activeCircuitView->action("edit_orientation_270") };
if ( !item || !item->canRotate() )
{
for ( unsigned i = 0; i < 4; ++i )
orientation_actions[i]->setEnabled(false);
return;
}
for ( unsigned i = 0; i < 4; ++ i)
{
orientation_actions[i]->setEnabled(true);
m_pOrientationAction->remove( orientation_actions[i] );
m_pOrientationAction->insert( orientation_actions[i] );
}
if ( item->angleDegrees() == 0 )
(static_cast<KToggleAction*>( orientation_actions[0] ))->setChecked(true);
else if ( item->angleDegrees() == 90 )
(static_cast<KToggleAction*>( orientation_actions[1] ))->setChecked(true);
else if ( item->angleDegrees() == 180 )
(static_cast<KToggleAction*>( orientation_actions[2] ))->setChecked(true);
else if ( item->angleDegrees() == 270 )
(static_cast<KToggleAction*>( orientation_actions[3] ))->setChecked(true);
}
void CircuitDocument::rotateCounterClockwise()
{
m_selectList->slotRotateCCW();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::rotateClockwise()
{
m_selectList->slotRotateCW();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::itemFlip()
{
m_selectList->slotFlip();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::setOrientation0()
{
m_selectList->slotSetOrientation0();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::setOrientation90()
{
m_selectList->slotSetOrientation90();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::setOrientation180()
{
m_selectList->slotSetOrientation180();
requestRerouteInvalidatedConnectors();
}
void CircuitDocument::setOrientation270()
{
m_selectList->slotSetOrientation270();
requestRerouteInvalidatedConnectors();
}
View *CircuitDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name )
{
View *view = new CircuitView( this, viewContainer, viewAreaId, name );
handleNewView(view);
return view;
}
void CircuitDocument::slotUpdateConfiguration()
{
ICNDocument::slotUpdateConfiguration();
NodeList::iterator nodeEnd = m_nodeList.end();
for ( NodeList::iterator it = m_nodeList.begin(); it != nodeEnd; ++it )
{
(static_cast<ECNode*>((Node*)*it))->setShowVoltageBars( KTLConfig::showVoltageBars() );
}
ComponentList::iterator componentsEnd = m_componentList.end();
for ( ComponentList::iterator it = m_componentList.begin(); it != componentsEnd; ++it )
(*it)->slotUpdateConfiguration();
}
void CircuitDocument::update()
{
ICNDocument::update();
if ( KTLConfig::showVoltageBars() )
{
NodeList::iterator end = m_nodeList.end();
for ( NodeList::iterator it = m_nodeList.begin(); it != end; ++it )
{
(static_cast<ECNode*>((Node*)*it))->setNodeChanged();
}
}
}
void CircuitDocument::fillContextMenu( const TQPoint &pos )
{
ICNDocument::fillContextMenu(pos);
CircuitView * activeCircuitView = dynamic_cast<CircuitView*>(activeView());
if ( m_selectList->count() < 1 || !activeCircuitView )
return;
Component * item = dynamic_cast<Component*>( selectList()->activeItem() );
// NOTE: I negated this whole condition because I couldn't make out quite what the
//logic was --electronerd
if (!( !item && m_selectList->count() > 0 || !m_selectList->itemsAreSameType() ))
{
KAction * orientation_actions[] = {
activeCircuitView->action("edit_orientation_0"),
activeCircuitView->action("edit_orientation_90"),
activeCircuitView->action("edit_orientation_180"),
activeCircuitView->action("edit_orientation_270") };
if ( !item || !item->canRotate() )
return;
for ( unsigned i = 0; i < 4; ++ i)
{
m_pOrientationAction->remove( orientation_actions[i] );
m_pOrientationAction->insert( orientation_actions[i] );
}
TQPtrList<KAction> orientation_actionlist;
// orientation_actionlist.prepend( new KActionSeparator() );
orientation_actionlist.append( m_pOrientationAction );
p_ktechlab->plugActionList( "orientation_actionlist", orientation_actionlist );
}
if(m_selectList->count() > 1 && countExtCon(m_selectList->items()) > 0)
{
TQPtrList<KAction> component_actionlist;
// component_actionlist.append( new KActionSeparator() );
component_actionlist.append( activeCircuitView->action("circuit_create_subcircuit") );
p_ktechlab->plugActionList( "component_actionlist", component_actionlist );
}
}
void CircuitDocument::deleteCircuits()
{
const CircuitList::iterator end = m_circuitList.end();
for ( CircuitList::iterator it = m_circuitList.begin(); it != end; ++it )
{
Simulator::self()->detachCircuit(*it);
delete *it;
}
m_circuitList.clear();
m_pinList.clear();
m_wireList.clear();
}
void CircuitDocument::requestAssignCircuits()
{
// kdDebug() << k_funcinfo << endl;
deleteCircuits();
m_updateCircuitsTmr->stop();
m_updateCircuitsTmr->start( 0, true );
}
void CircuitDocument::connectorAdded( Connector * connector )
{
if (connector)
{
connect( connector, TQT_SIGNAL(numWiresChanged(unsigned )), this, TQT_SLOT(requestAssignCircuits()) );
connect( connector, TQT_SIGNAL(removed(Connector*)), this, TQT_SLOT(requestAssignCircuits()) );
}
}
void CircuitDocument::itemAdded( Item * item)
{
ICNDocument::itemAdded( item );
componentAdded( item );
}
void CircuitDocument::componentAdded( Item * item )
{
Component * component = dynamic_cast<Component*>(item);
if (!component)
return;
requestAssignCircuits();
connect( component, TQT_SIGNAL(elementCreated(Element*)), this, TQT_SLOT(requestAssignCircuits()) );
connect( component, TQT_SIGNAL(elementDestroyed(Element*)), this, TQT_SLOT(requestAssignCircuits()) );
connect( component, TQT_SIGNAL(removed(Item*)), this, TQT_SLOT(componentRemoved(Item*)) );
// We don't attach the component to the Simulator just yet, as the
// Component's vtable is not yet fully constructed, and so Simulator can't
// tell whether or not it is a logic component
if ( !m_toSimulateList.contains(component) )
m_toSimulateList << component;
}
void CircuitDocument::componentRemoved( Item * item )
{
Component * component = dynamic_cast<Component*>(item);
if (!component)
return;
m_componentList.remove(component);
requestAssignCircuits();
Simulator::self()->detachComponent(component);
}
void CircuitDocument::calculateConnectorCurrents()
{
const CircuitList::iterator circuitEnd = m_circuitList.end();
for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitEnd; ++it )
(*it)->updateCurrents();
PinList groundPins;
// Tell the Pins to reset their calculated currents to zero
m_pinList.remove((Pin*)0l);
const PinList::iterator pinEnd = m_pinList.end();
for ( PinList::iterator it = m_pinList.begin(); it != pinEnd; ++it )
{
if ( Pin *n = dynamic_cast<Pin*>((Pin*)*it) )
{
n->resetCurrent();
n->setSwitchCurrentsUnknown();
if ( !n->parentECNode()->isChildNode() )
{
n->setCurrentKnown( true );
// (and it has a current of 0 amps)
}
else if ( n->groundType() == Pin::gt_always )
{
groundPins << n;
n->setCurrentKnown( false );
}
else
{
// Child node that is non ground
n->setCurrentKnown( n->parentECNode()->numPins() < 2 );
}
}
}
// Tell the components to update their ECNode's currents' from the elements
const ComponentList::iterator componentEnd = m_componentList.end();
for ( ComponentList::iterator it = m_componentList.begin(); it != componentEnd; ++it )
(*it)->setNodalCurrents();
// And now for the wires and switches...
m_wireList.remove((Wire*)0l);
const WireList::iterator clEnd = m_wireList.end();
for ( WireList::iterator it = m_wireList.begin(); it != clEnd; ++it )
(*it)->setCurrentKnown(false);
SwitchList switches = m_switchList;
WireList wires = m_wireList;
bool found = true;
while ( (!wires.isEmpty() || !switches.isEmpty() || !groundPins.isEmpty()) && found )
{
found = false;
WireList::iterator wiresEnd = wires.end();
for ( WireList::iterator it = wires.begin(); it != wiresEnd; )
{
if ( (*it)->calculateCurrent() )
{
found = true;
WireList::iterator oldIt = it;
++it;
wires.remove(oldIt);
}
else
++it;
}
SwitchList::iterator switchesEnd = switches.end();
for ( SwitchList::iterator it = switches.begin(); it != switchesEnd; )
{
if ( (*it)->calculateCurrent() )
{
found = true;
SwitchList::iterator oldIt = it;
++it;
switches.remove(oldIt);
}
else
++it;
}
PinList::iterator groundPinsEnd = groundPins.end();
for ( PinList::iterator it = groundPins.begin(); it != groundPinsEnd; )
{
if ( (*it)->calculateCurrentFromWires() )
{
found = true;
PinList::iterator oldIt = it;
++it;
groundPins.remove(oldIt);
}
else
++it;
}
}
}
void CircuitDocument::assignCircuits()
{
// Now we can finally add the unadded components to the Simulator
const ComponentList::iterator toSimulateEnd = m_toSimulateList.end();
for ( ComponentList::iterator it = m_toSimulateList.begin(); it != toSimulateEnd; ++it )
Simulator::self()->attachComponent(*it);
m_toSimulateList.clear();
// Stage 0: Build up pin and wire lists
m_pinList.clear();
const NodeList::const_iterator nodeListEnd = m_nodeList.end();
for ( NodeList::const_iterator it = m_nodeList.begin(); it != nodeListEnd; ++it )
{
if ( ECNode * ecnode = dynamic_cast<ECNode*>((Node*)*it) )
{
for ( unsigned i = 0; i < ecnode->numPins(); i++ )
m_pinList << ecnode->pin(i);
}
}
m_wireList.clear();
const ConnectorList::const_iterator connectorListEnd = m_connectorList.end();
for ( ConnectorList::const_iterator it = m_connectorList.begin(); it != connectorListEnd; ++it )
{
for ( unsigned i = 0; i < (*it)->numWires(); i++ )
m_wireList << (*it)->wire(i);
}
typedef TQValueList<PinList> PinListList;
// Stage 1: Partition the circuit up into dependent areas (bar splitting
// at ground pins)
PinList unassignedPins = m_pinList;
PinListList pinListList;
while ( !unassignedPins.isEmpty() )
{
PinList pinList;
getPartition( *unassignedPins.begin(), & pinList, & unassignedPins );
pinListList.append(pinList);
}
// kdDebug () << "pinListList.size()="<<pinListList.size()<<endl;
// Stage 2: Split up each partition into circuits by ground pins
const PinListList::iterator nllEnd = pinListList.end();
for ( PinListList::iterator it = pinListList.begin(); it != nllEnd; ++it )
splitIntoCircuits(&*it);
// Stage 3: Initialize the circuits
m_circuitList.remove(0l);
CircuitList::iterator circuitListEnd = m_circuitList.end();
for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it )
(*it)->init();
m_switchList.clear();
m_componentList.clear();
const ItemList::const_iterator cilEnd = m_itemList.end();
for ( ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it )
{
Component * component = dynamic_cast<Component*>((Item*)(*it));
if ( !component )
continue;
m_componentList << component;
component->initElements(0);
m_switchList += component->switchList();
}
circuitListEnd = m_circuitList.end();
for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it )
(*it)->createMatrixMap();
for ( ItemList::const_iterator it = m_itemList.begin(); it != cilEnd; ++it )
{
Component * component = dynamic_cast<Component*>((Item*)(*it));
if (component)
component->initElements(1);
}
circuitListEnd = m_circuitList.end();
for ( CircuitList::iterator it = m_circuitList.begin(); it != circuitListEnd; ++it )
{
(*it)->initCache();
Simulator::self()->attachCircuit(*it);
}
}
void CircuitDocument::getPartition( Pin *pin, PinList *pinList, PinList *unassignedPins, bool onlyGroundDependent )
{
if (!pin)
return;
unassignedPins->remove(pin);
if ( pinList->contains(pin) )
return;
pinList->append(pin);
const PinList localConnectedPins = pin->localConnectedPins();
const PinList::const_iterator end = localConnectedPins.end();
for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it )
getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
const PinList groundDependentPins = pin->groundDependentPins();
const PinList::const_iterator dEnd = groundDependentPins.end();
for ( PinList::const_iterator it = groundDependentPins.begin(); it != dEnd; ++it )
getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
if (!onlyGroundDependent)
{
PinList circuitDependentPins = pin->circuitDependentPins();
const PinList::const_iterator dEnd = circuitDependentPins.end();
for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it )
getPartition( *it, pinList, unassignedPins, onlyGroundDependent );
}
}
void CircuitDocument::splitIntoCircuits( PinList *pinList )
{
// First: identify ground
PinList unassignedPins = *pinList;
typedef TQValueList<PinList> PinListList;
PinListList pinListList;
while ( !unassignedPins.isEmpty() )
{
PinList tempPinList;
getPartition( *unassignedPins.begin(), & tempPinList, & unassignedPins, true );
pinListList.append(tempPinList);
}
const PinListList::iterator nllEnd = pinListList.end();
for ( PinListList::iterator it = pinListList.begin(); it != nllEnd; ++it )
Circuit::identifyGround(*it);
bool allGround = false;
while ( !pinList->isEmpty() && !allGround )
{
PinList::iterator end = pinList->end();
PinList::iterator it = pinList->begin();
while ( it != end && (*it)->eqId() == -1 )
++it;
if ( it == end )
allGround = true;
else
{
Circuitoid *circuitoid = new Circuitoid;
recursivePinAdd( *it, circuitoid, pinList );
if ( !tryAsLogicCircuit(circuitoid) )
m_circuitList += createCircuit(circuitoid);
delete circuitoid;
}
}
// Remaining pins are ground; tell them about it
// TODO This is a bit hacky....
const PinList::iterator end = pinList->end();
for ( PinList::iterator it = pinList->begin(); it != end; ++it )
{
(*it)->setVoltage(0.0);
ElementList elements = (*it)->elements();
const ElementList::iterator eEnd = elements.end();
for ( ElementList::iterator it = elements.begin(); it != eEnd; ++it )
{
if ( LogicIn * logicIn = dynamic_cast<LogicIn*>(*it) )
{
logicIn->setLastState(false);
logicIn->callCallback();
}
}
}
}
void CircuitDocument::recursivePinAdd( Pin *pin, Circuitoid *circuitoid, PinList *unassignedPins )
{
if (!pin)
return;
if ( pin->eqId() != -1 )
unassignedPins->remove(pin);
if ( circuitoid->contains(pin) )
return;
circuitoid->addPin(pin);
if ( pin->eqId() == -1 )
return;
const PinList localConnectedPins = pin->localConnectedPins();
const PinList::const_iterator end = localConnectedPins.end();
for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it )
recursivePinAdd( *it, circuitoid, unassignedPins );
const WireList inputList = pin->inputWireList();
WireList::const_iterator conEnd = inputList.end();
for ( WireList::const_iterator it = inputList.begin(); it != conEnd; ++it )
circuitoid->addWire(*it);
const WireList outputList = pin->outputWireList();
conEnd = outputList.end();
for ( WireList::const_iterator it = outputList.begin(); it != conEnd; ++it )
circuitoid->addWire(*it);
const PinList groundDependentPins = pin->groundDependentPins();
const PinList::const_iterator gdEnd = groundDependentPins.end();
for ( PinList::const_iterator it = groundDependentPins.begin(); it != gdEnd; ++it )
recursivePinAdd( *it, circuitoid, unassignedPins );
const PinList circuitDependentPins = pin->circuitDependentPins();
const PinList::const_iterator cdEnd = circuitDependentPins.end();
for ( PinList::const_iterator it = circuitDependentPins.begin(); it != cdEnd; ++it )
recursivePinAdd( *it, circuitoid, unassignedPins );
const ElementList elements = pin->elements();
const ElementList::const_iterator eEnd = elements.end();
for ( ElementList::const_iterator it = elements.begin(); it != eEnd; ++it )
circuitoid->addElement(*it);
}
bool CircuitDocument::tryAsLogicCircuit( Circuitoid *circuitoid )
{
if (!circuitoid)
return false;
if ( circuitoid->elementList.size() == 0 )
{
// This doesn't quite belong here...but whatever. Initialize all
// pins to voltage zero as they won't get set to zero otherwise
const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd();
for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it )
(*it)->setVoltage(0.0);
// A logic circuit only requires there to be no non-logic components,
// and at most one LogicOut - so this qualifies
return true;
}
LogicInList logicInList;
LogicOut *out = 0l;
uint logicInCount = 0;
uint logicOutCount = 0;
ElementList::const_iterator end = circuitoid->elementList.end();
for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it )
{
if ( (*it)->type() == Element::Element_LogicOut )
{
logicOutCount++;
out = static_cast<LogicOut*>(*it);
}
else if ( (*it)->type() == Element::Element_LogicIn )
{
logicInCount++;
logicInList += static_cast<LogicIn*>(*it);
}
else
return false;
}
if ( logicOutCount > 1 )
return false;
else if ( logicOutCount == 1 )
Simulator::self()->createLogicChain( out, logicInList, circuitoid->pinList );
else
{
// We have ourselves stranded LogicIns...so lets set them all to low
const PinList::const_iterator pinListEnd = circuitoid->pinList.constEnd();
for ( PinList::const_iterator it = circuitoid->pinList.constBegin(); it != pinListEnd; ++it )
(*it)->setVoltage(0.0);
for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != end; ++it )
{
LogicIn * logicIn = static_cast<LogicIn*>(*it);
logicIn->setNextLogic(0l);
logicIn->setElementSet(0l);
if ( logicIn->isHigh() )
{
logicIn->setLastState(false);
logicIn->callCallback();
}
}
}
return true;
}
Circuit *CircuitDocument::createCircuit( Circuitoid *circuitoid )
{
if (!circuitoid) {
return 0l;
}
Circuit *circuit = new Circuit();
const PinList::const_iterator nEnd = circuitoid->pinList.end();
for ( PinList::const_iterator it = circuitoid->pinList.begin(); it != nEnd; ++it )
circuit->addPin(*it);
const ElementList::const_iterator eEnd = circuitoid->elementList.end();
for ( ElementList::const_iterator it = circuitoid->elementList.begin(); it != eEnd; ++it )
circuit->addElement(*it);
return circuit;
}
void CircuitDocument::createSubcircuit()
{
ItemList itemList = m_selectList->items();
const ItemList::iterator itemListEnd = itemList.end();
for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it )
{
if ( !dynamic_cast<Component*>((Item*)*it) )
*it = 0l;
}
itemList.remove((Item*)0l);
if ( itemList.isEmpty() )
{
KMessageBox::sorry( activeView(), i18n("No components were found in the selection.") );
return;
}
// Number of external connections
const int extConCount = countExtCon(itemList);
if ( extConCount == 0 )
{
KMessageBox::sorry( activeView(), i18n("No External Connection components were found in the selection.") );
return;
}
bool ok;
const TQString name = KInputDialog::getText( "Subcircuit", "Name", TQString(), &ok, activeView() );
if (!ok)
return;
SubcircuitData subcircuit;
subcircuit.addItems(itemList);
subcircuit.addNodes( getCommonNodes(itemList) );
subcircuit.addConnectors( getCommonConnectors(itemList) );
Subcircuits::addSubcircuit( name, subcircuit.toXML() );
}
int CircuitDocument::countExtCon( const ItemList &itemList ) const
{
int count = 0;
const ItemList::const_iterator end = itemList.end();
for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it )
{
Item * item = *it;
if ( item && item->type() == "ec/external_connection" )
count++;
}
return count;
}
bool CircuitDocument::isValidItem( const TQString &itemId )
{
return itemId.startsWith("ec/") || itemId.startsWith("dp/") || itemId.startsWith("sc/");
}
bool CircuitDocument::isValidItem( Item *item )
{
return (dynamic_cast<Component*>(item) || dynamic_cast<DrawPart*>(item));
}
void CircuitDocument::displayEquations()
{
kdDebug() << "######################################################" << endl;
const CircuitList::iterator end = m_circuitList.end();
int i = 1;
for ( CircuitList::iterator it = m_circuitList.begin(); it != end; ++it )
{
kdDebug() << "Equation set "<<i<<":\n";
(*it)->displayEquations();
i++;
}
kdDebug() << "######################################################" << endl;
}
#include "circuitdocument.moc"