Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/schematic_file.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               schematic_file.cpp
00003                              --------------------
00004     begin                : Sat Mar 27 2004
00005     copyright            : (C) 2003 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #ifdef HAVE_CONFIG_H
00019 # include <config.h>
00020 #endif
00021 
00022 #include <QtCore>
00023 #include <QMessageBox>
00024 #include <QDir>
00025 #include <QStringList>
00026 #include <QPlainTextEdit>
00027 #include <Q3PtrList>
00028 #include <QTextStream>
00029 #include <QList>
00030 #include <QProcess>
00031 #include <QDebug>
00032 
00033 #include "main.h"
00034 #include "node.h"
00035 #include "schematic.h"
00036 #include "diagrams/diagrams.h"
00037 #include "paintings/paintings.h"
00038 #include "components/spicefile.h"
00039 #include "components/vhdlfile.h"
00040 #include "components/verilogfile.h"
00041 #include "components/libcomp.h"
00042 #include "module.h"
00043 #include "misc.h"
00044 
00045 
00046 // Here the subcircuits, SPICE components etc are collected. It must be
00047 // global to also work within the subcircuits.
00048 SubMap FileList;
00049 
00050 
00051 // -------------------------------------------------------------
00052 // Creates a Qucs file format (without document properties) in the returning
00053 // string. This is used to copy the selected elements into the clipboard.
00054 QString Schematic::createClipboardFile()
00055 {
00056   int z=0;  // counts selected elements
00057   Wire *pw;
00058   Diagram *pd;
00059   Painting *pp;
00060   Component *pc;
00061 
00062   QString s("<Qucs Schematic " PACKAGE_VERSION ">\n");
00063 
00064   // Build element document.
00065   s += "<Components>\n";
00066   for(pc = Components->first(); pc != 0; pc = Components->next())
00067     if(pc->isSelected) {
00068       s += pc->save()+"\n";  z++; }
00069   s += "</Components>\n";
00070 
00071   s += "<Wires>\n";
00072   for(pw = Wires->first(); pw != 0; pw = Wires->next())
00073     if(pw->isSelected) {
00074       z++;
00075       if(pw->Label) if(!pw->Label->isSelected) {
00076   s += pw->save().section('"', 0, 0)+"\"\" 0 0 0>\n";
00077   continue;
00078       }
00079       s += pw->save()+"\n";
00080     }
00081   for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
00082     if(pn->Label) if(pn->Label->isSelected) {
00083       s += pn->Label->save()+"\n";  z++; }
00084   s += "</Wires>\n";
00085 
00086   s += "<Diagrams>\n";
00087   for(pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
00088     if(pd->isSelected) {
00089       s += pd->save()+"\n";  z++; }
00090   s += "</Diagrams>\n";
00091 
00092   s += "<Paintings>\n";
00093   for(pp = Paintings->first(); pp != 0; pp = Paintings->next())
00094     if(pp->isSelected)
00095       if(pp->Name.at(0) != '.') {  // subcircuit specific -> do not copy
00096         s += "<"+pp->save()+">\n";  z++; }
00097   s += "</Paintings>\n";
00098 
00099   if(z == 0) return "";   // return empty if no selection
00100 
00101   return s;
00102 }
00103 
00104 // -------------------------------------------------------------
00105 // Only read fields without loading them.
00106 bool Schematic::loadIntoNothing(QTextStream *stream)
00107 {
00108   QString Line, cstr;
00109   while(!stream->atEnd()) {
00110     Line = stream->readLine();
00111     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
00112   }
00113 
00114   QMessageBox::critical(0, QObject::tr("Error"),
00115   QObject::tr("Format Error:\n'Painting' field is not closed!"));
00116   return false;
00117 }
00118 
00119 // -------------------------------------------------------------
00120 // Paste from clipboard.
00121 bool Schematic::pasteFromClipboard(QTextStream *stream, Q3PtrList<Element> *pe)
00122 {
00123   QString Line;
00124 
00125   Line = stream->readLine();
00126   if(Line.left(16) != "<Qucs Schematic ")   // wrong file type ?
00127     return false;
00128 
00129   QString s = PACKAGE_VERSION;
00130   Line = Line.mid(16, Line.length()-17);
00131   if(Line != s) {  // wrong version number ?
00132     QMessageBox::critical(0, QObject::tr("Error"),
00133                  QObject::tr("Wrong document version: ")+Line);
00134     return false;
00135   }
00136 
00137   // read content in symbol edit mode *************************
00138   if(symbolMode) {
00139     while(!stream->atEnd()) {
00140       Line = stream->readLine();
00141       if(Line == "<Components>") {
00142         if(!loadIntoNothing(stream)) return false; }
00143       else
00144       if(Line == "<Wires>") {
00145         if(!loadIntoNothing(stream)) return false; }
00146       else
00147       if(Line == "<Diagrams>") {
00148         if(!loadIntoNothing(stream)) return false; }
00149       else
00150       if(Line == "<Paintings>") {
00151         if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; }
00152       else {
00153         QMessageBox::critical(0, QObject::tr("Error"),
00154        QObject::tr("Clipboard Format Error:\nUnknown field!"));
00155         return false;
00156       }
00157     }
00158 
00159     return true;
00160   }
00161 
00162   // read content in schematic edit mode *************************
00163   while(!stream->atEnd()) {
00164     Line = stream->readLine();
00165     if(Line == "<Components>") {
00166       if(!loadComponents(stream, (Q3PtrList<Component>*)pe)) return false; }
00167     else
00168     if(Line == "<Wires>") {
00169       if(!loadWires(stream, pe)) return false; }
00170     else
00171     if(Line == "<Diagrams>") {
00172       if(!loadDiagrams(stream, (Q3PtrList<Diagram>*)pe)) return false; }
00173     else
00174     if(Line == "<Paintings>") {
00175       if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; }
00176     else {
00177       QMessageBox::critical(0, QObject::tr("Error"),
00178        QObject::tr("Clipboard Format Error:\nUnknown field!"));
00179       return false;
00180     }
00181   }
00182 
00183   return true;
00184 }
00185 
00186 // -------------------------------------------------------------
00187 int Schematic::saveSymbolCpp (void)
00188 {
00189   QFileInfo info (DocName);
00190   QString cppfile = info.dirPath () + QDir::separator() + DataSet;
00191   QFile file (cppfile);
00192 
00193   if (!file.open (QIODevice::WriteOnly)) {
00194     QMessageBox::critical (0, QObject::tr("Error"),
00195        QObject::tr("Cannot save C++ file \"%1\"!").arg(cppfile));
00196     return -1;
00197   }
00198 
00199   QTextStream stream (&file);
00200 
00201   // automatically compute boundings of drawing
00202   int xmin = INT_MAX;
00203   int ymin = INT_MAX;
00204   int xmax = INT_MIN;
00205   int ymax = INT_MIN;
00206   int x1, y1, x2, y2;
00207   int maxNum = 0;
00208   Painting * pp;
00209 
00210   stream << "  // symbol drawing code\n";
00211   for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
00212     if (pp->Name == ".ID ") continue;
00213     if (pp->Name == ".PortSym ") {
00214       if (((PortSymbol*)pp)->numberStr.toInt() > maxNum)
00215   maxNum = ((PortSymbol*)pp)->numberStr.toInt();
00216       x1 = ((PortSymbol*)pp)->cx;
00217       y1 = ((PortSymbol*)pp)->cy;
00218       if (x1 < xmin) xmin = x1;
00219       if (x1 > xmax) xmax = x1;
00220       if (y1 < ymin) ymin = y1;
00221       if (y1 > ymax) ymax = y1;
00222       continue;
00223     }
00224     pp->Bounding (x1, y1, x2, y2);
00225     if (x1 < xmin) xmin = x1;
00226     if (x2 > xmax) xmax = x2;
00227     if (y1 < ymin) ymin = y1;
00228     if (y2 > ymax) ymax = y2;
00229     stream << "  " << pp->saveCpp () << "\n";
00230   }
00231 
00232   stream << "\n  // terminal definitions\n";
00233   for (int i = 1; i <= maxNum; i++) {
00234     for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
00235       if (pp->Name == ".PortSym ")
00236   if (((PortSymbol*)pp)->numberStr.toInt() == i)
00237     stream << "  " << pp->saveCpp () << "\n";
00238     }
00239   }
00240 
00241   stream << "\n  // symbol boundings\n"
00242    << "  x1 = " << xmin << "; " << "  y1 = " << ymin << ";\n"
00243    << "  x2 = " << xmax << "; " << "  y2 = " << ymax << ";\n";
00244 
00245   stream << "\n  // property text position\n";
00246   for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ())
00247     if (pp->Name == ".ID ")
00248       stream << "  " << pp->saveCpp () << "\n";
00249 
00250   file.close ();
00251   return 0;
00252 }
00253 
00254 // save symbol paintings in JSON format
00255 int Schematic::saveSymbolJSON()
00256 {
00257   QFileInfo info (DocName);
00258   QString jsonfile = info.dirPath () + QDir::separator()
00259                    + info.baseName() + "_sym.json";
00260 
00261   qDebug() << "saveSymbolJson for " << jsonfile;
00262 
00263   QFile file (jsonfile);
00264 
00265   if (!file.open (QIODevice::WriteOnly)) {
00266     QMessageBox::critical (0, QObject::tr("Error"),
00267        QObject::tr("Cannot save JSON symbol file \"%1\"!").arg(jsonfile));
00268     return -1;
00269   }
00270 
00271   QTextStream stream (&file);
00272 
00273   // automatically compute boundings of drawing
00274   int xmin = INT_MAX;
00275   int ymin = INT_MAX;
00276   int xmax = INT_MIN;
00277   int ymax = INT_MIN;
00278   int x1, y1, x2, y2;
00279   int maxNum = 0;
00280   Painting * pp;
00281 
00282   stream << "{\n";
00283 
00284   stream << "\"paintings\" : [\n";
00285 
00286   // symbol drawing code"
00287   for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
00288     if (pp->Name == ".ID ") continue;
00289     if (pp->Name == ".PortSym ") {
00290       if (((PortSymbol*)pp)->numberStr.toInt() > maxNum)
00291   maxNum = ((PortSymbol*)pp)->numberStr.toInt();
00292       x1 = ((PortSymbol*)pp)->cx;
00293       y1 = ((PortSymbol*)pp)->cy;
00294       if (x1 < xmin) xmin = x1;
00295       if (x1 > xmax) xmax = x1;
00296       if (y1 < ymin) ymin = y1;
00297       if (y1 > ymax) ymax = y1;
00298       continue;
00299     }
00300     pp->Bounding (x1, y1, x2, y2);
00301     if (x1 < xmin) xmin = x1;
00302     if (x2 > xmax) xmax = x2;
00303     if (y1 < ymin) ymin = y1;
00304     if (y2 > ymax) ymax = y2;
00305     stream << "  " << pp->saveJSON() << "\n";
00306   }
00307 
00308   // terminal definitions
00309   //stream << "terminal \n";
00310   for (int i = 1; i <= maxNum; i++) {
00311     for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
00312       if (pp->Name == ".PortSym ")
00313   if (((PortSymbol*)pp)->numberStr.toInt() == i)
00314     stream << "  " << pp->saveJSON () << "\n";
00315     }
00316   }
00317 
00318   stream << "],\n"; //end of paintings JSON array
00319 
00320   // symbol boundings
00321   stream
00322     << "  \"x1\" : " << xmin << ",\n" << "  \"y1\" : " << ymin << ",\n"
00323     << "  \"x2\" : " << xmax << ",\n" << "  \"y2\" : " << ymax << ",\n";
00324 
00325   // property text position
00326   for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ())
00327     if (pp->Name == ".ID ")
00328       stream << "  " << pp->saveJSON () << "\n";
00329 
00330   stream << "}\n";
00331 
00332   file.close ();
00333   return 0;
00334 
00335 
00336 }
00337 
00338 // -------------------------------------------------------------
00339 // Returns the number of subcircuit ports.
00340 int Schematic::saveDocument()
00341 {
00342   QFile file(DocName);
00343   if(!file.open(QIODevice::WriteOnly)) {
00344     QMessageBox::critical(0, QObject::tr("Error"),
00345         QObject::tr("Cannot save document!"));
00346     return -1;
00347   }
00348 
00349   QTextStream stream(&file);
00350 
00351   stream << "<Qucs Schematic " << PACKAGE_VERSION << ">\n";
00352 
00353   stream << "<Properties>\n";
00354   if(symbolMode) {
00355     stream << "  <View=" << tmpViewX1<<","<<tmpViewY1<<","
00356        << tmpViewX2<<","<<tmpViewY2<< ",";
00357     stream <<tmpScale<<","<<tmpPosX<<","<<tmpPosY << ">\n";
00358   }
00359   else {
00360     stream << "  <View=" << ViewX1<<","<<ViewY1<<","
00361        << ViewX2<<","<<ViewY2<< ",";
00362     stream << Scale <<","<<contentsX()<<","<<contentsY() << ">\n";
00363   }
00364   stream << "  <Grid=" << GridX<<","<<GridY<<","
00365       << GridOn << ">\n";
00366   stream << "  <DataSet=" << DataSet << ">\n";
00367   stream << "  <DataDisplay=" << DataDisplay << ">\n";
00368   stream << "  <OpenDisplay=" << SimOpenDpl << ">\n";
00369   stream << "  <Script=" << Script << ">\n";
00370   stream << "  <RunScript=" << SimRunScript << ">\n";
00371   stream << "  <showFrame=" << showFrame << ">\n";
00372 
00373   QString t;
00374   misc::convert2ASCII(t = Frame_Text0);
00375   stream << "  <FrameText0=" << t << ">\n";
00376   misc::convert2ASCII(t = Frame_Text1);
00377   stream << "  <FrameText1=" << t << ">\n";
00378   misc::convert2ASCII(t = Frame_Text2);
00379   stream << "  <FrameText2=" << t << ">\n";
00380   misc::convert2ASCII(t = Frame_Text3);
00381   stream << "  <FrameText3=" << t << ">\n";
00382   stream << "</Properties>\n";
00383 
00384   Painting *pp;
00385   stream << "<Symbol>\n";     // save all paintings for symbol
00386   for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next())
00387     stream << "  <" << pp->save() << ">\n";
00388   stream << "</Symbol>\n";
00389 
00390   stream << "<Components>\n";    // save all components
00391   for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next())
00392     stream << "  " << pc->save() << "\n";
00393   stream << "</Components>\n";
00394 
00395   stream << "<Wires>\n";    // save all wires
00396   for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next())
00397     stream << "  " << pw->save() << "\n";
00398 
00399   // save all labeled nodes as wires
00400   for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
00401     if(pn->Label) stream << "  " << pn->Label->save() << "\n";
00402   stream << "</Wires>\n";
00403 
00404   stream << "<Diagrams>\n";    // save all diagrams
00405   for(Diagram *pd = DocDiags.first(); pd != 0; pd = DocDiags.next())
00406     stream << "  " << pd->save() << "\n";
00407   stream << "</Diagrams>\n";
00408 
00409   stream << "<Paintings>\n";     // save all paintings
00410   for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next())
00411     stream << "  <" << pp->save() << ">\n";
00412   stream << "</Paintings>\n";
00413 
00414   file.close();
00415 
00416   // additionally save symbol C++ code if in a symbol drawing and the
00417   // associated file is a Verilog-A file
00418   if (fileSuffix () == "sym") {
00419     if (fileSuffix (DataDisplay) == "va") {
00420       saveSymbolCpp ();
00421       saveSymbolJSON ();
00422 
00423       // TODO slit this into another method, or merge into saveSymbolJSON
00424       // handle errors in separate
00425       qDebug() << "  -> Run adms for symbol";
00426 
00427       QString vaFile;
00428 
00429 //      QDir prefix = QDir(QucsSettings.BinDir);
00430 
00431       QDir include = QDir(QucsSettings.BinDir+"../include/qucs-core");
00432 
00433       //pick admsXml from settings
00434       QString admsXml = QucsSettings.AdmsXmlBinDir.canonicalPath();
00435 
00436 #ifdef __MINGW32__
00437       admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml.exe");
00438 #else
00439       admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml");
00440 #endif
00441 
00442       QString workDir = QucsSettings.QucsWorkDir.absolutePath();
00443 
00444       qDebug() << "App path : " << qApp->applicationDirPath();
00445       qDebug() << "workdir"  << workDir;
00446       qDebug() << "homedir"  << QucsSettings.QucsHomeDir.absolutePath();
00447 
00448       vaFile = QucsSettings.QucsWorkDir.filePath(fileBase()+".va");
00449 
00450       QStringList Arguments;
00451       Arguments << QDir::toNativeSeparators(vaFile)
00452                 << "-I" << QDir::toNativeSeparators(include.absolutePath())
00453                 << "-e" << QDir::toNativeSeparators(include.absFilePath("qucsMODULEguiJSONsymbol.xml"))
00454                 << "-A" << "dyload";
00455 
00456 //      QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
00457 //      env.insert("PATH", env.value("PATH") );
00458 
00459       QFile file(admsXml);
00460       if ( !file.exists() ){
00461         QMessageBox::critical(this, tr("Error"),
00462                               tr("Program admsXml not found: %1\n\n"
00463                                   "Set the admsXml location on the application settings.").arg(admsXml));
00464         return -1;
00465       }
00466 
00467       qDebug() << "Command: " << admsXml << Arguments.join(" ");
00468 
00469       // need to cd into project to run admsXml?
00470       QDir::setCurrent(workDir);
00471 
00472       QProcess builder;
00473       builder.setProcessChannelMode(QProcess::MergedChannels);
00474 
00475       builder.start(admsXml, Arguments);
00476 
00477 
00478       // how to capture [warning]? need to modify admsXml?
00479       // TODO put stdout, stderr into a dock window, not messagebox
00480       if (!builder.waitForFinished()) {
00481         QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" "));
00482         cmdString = cmdString + builder.errorString();
00483         QMessageBox::critical(this, tr("Error"), cmdString);
00484       }
00485       else {
00486         QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" "));
00487         cmdString = cmdString + builder.readAll();
00488         QMessageBox::information(this, tr("Status"), cmdString);
00489       }
00490 
00491       // Append _sym.json into _props.json, save into _symbol.json
00492       QFile f1(QucsSettings.QucsWorkDir.filePath(fileBase()+"_props.json"));
00493       QFile f2(QucsSettings.QucsWorkDir.filePath(fileBase()+"_sym.json"));
00494       f1.open(QIODevice::ReadOnly | QIODevice::Text);
00495       f2.open(QIODevice::ReadOnly | QIODevice::Text);
00496 
00497       QString dat1 = QString(f1.readAll());
00498       QString dat2 = QString(f2.readAll());
00499       QString finalJSON = dat1.append(dat2);
00500 
00501       // remove joining point
00502       finalJSON = finalJSON.replace("}{", "");
00503 
00504       QFile f3(QucsSettings.QucsWorkDir.filePath(fileBase()+"_symbol.json"));
00505       f3.open(QIODevice::WriteOnly | QIODevice::Text);
00506       QTextStream out(&f3);
00507       out << finalJSON;
00508 
00509       f1.close();
00510       f2.close();
00511       f3.close();
00512 
00513       // TODO choose icon, default to something or provided png
00514 
00515     } // if DataDisplay va
00516   } // if suffix .sym
00517 
00518   return 0;
00519 }
00520 
00521 // -------------------------------------------------------------
00522 bool Schematic::loadProperties(QTextStream *stream)
00523 {
00524   bool ok = true;
00525   QString Line, cstr, nstr;
00526   while(!stream->atEnd()) {
00527     Line = stream->readLine();
00528     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;  // field end ?
00529     Line = Line.trimmed();
00530     if(Line.isEmpty()) continue;
00531 
00532     if(Line.at(0) != '<') {
00533       QMessageBox::critical(0, QObject::tr("Error"),
00534     QObject::tr("Format Error:\nWrong property field limiter!"));
00535       return false;
00536     }
00537     if(Line.at(Line.length()-1) != '>') {
00538       QMessageBox::critical(0, QObject::tr("Error"),
00539     QObject::tr("Format Error:\nWrong property field limiter!"));
00540       return false;
00541     }
00542     Line = Line.mid(1, Line.length()-2);   // cut off start and end character
00543 
00544     cstr = Line.section('=',0,0);    // property type
00545     nstr = Line.section('=',1,1);    // property value
00546          if(cstr == "View") {
00547     ViewX1 = nstr.section(',',0,0).toInt(&ok); if(ok) {
00548     ViewY1 = nstr.section(',',1,1).toInt(&ok); if(ok) {
00549     ViewX2 = nstr.section(',',2,2).toInt(&ok); if(ok) {
00550     ViewY2 = nstr.section(',',3,3).toInt(&ok); if(ok) {
00551     Scale  = nstr.section(',',4,4).toDouble(&ok); if(ok) {
00552     tmpViewX1 = nstr.section(',',5,5).toInt(&ok); if(ok)
00553     tmpViewY1 = nstr.section(',',6,6).toInt(&ok); }}}}} }
00554     else if(cstr == "Grid") {
00555     GridX = nstr.section(',',0,0).toInt(&ok); if(ok) {
00556     GridY = nstr.section(',',1,1).toInt(&ok); if(ok) {
00557     if(nstr.section(',',2,2).toInt(&ok) == 0) GridOn = false;
00558     else GridOn = true; }} }
00559     else if(cstr == "DataSet") DataSet = nstr;
00560     else if(cstr == "DataDisplay") DataDisplay = nstr;
00561     else if(cstr == "OpenDisplay")
00562     if(nstr.toInt(&ok) == 0) SimOpenDpl = false;
00563     else SimOpenDpl = true;
00564     else if(cstr == "Script") Script = nstr;
00565     else if(cstr == "RunScript")
00566     if(nstr.toInt(&ok) == 0) SimRunScript = false;
00567     else SimRunScript = true;
00568     else if(cstr == "showFrame")
00569     showFrame = nstr.at(0).toLatin1() - '0';
00570     else if(cstr == "FrameText0") misc::convert2Unicode(Frame_Text0 = nstr);
00571     else if(cstr == "FrameText1") misc::convert2Unicode(Frame_Text1 = nstr);
00572     else if(cstr == "FrameText2") misc::convert2Unicode(Frame_Text2 = nstr);
00573     else if(cstr == "FrameText3") misc::convert2Unicode(Frame_Text3 = nstr);
00574     else {
00575       QMessageBox::critical(0, QObject::tr("Error"),
00576      QObject::tr("Format Error:\nUnknown property: ")+cstr);
00577       return false;
00578     }
00579     if(!ok) {
00580       QMessageBox::critical(0, QObject::tr("Error"),
00581      QObject::tr("Format Error:\nNumber expected in property field!"));
00582       return false;
00583     }
00584   }
00585 
00586   QMessageBox::critical(0, QObject::tr("Error"),
00587                QObject::tr("Format Error:\n'Property' field is not closed!"));
00588   return false;
00589 }
00590 
00591 // ---------------------------------------------------
00592 // Inserts a component without performing logic for wire optimization.
00593 void Schematic::simpleInsertComponent(Component *c)
00594 {
00595   Node *pn;
00596   int x, y;
00597   // connect every node of component
00598   foreach(Port *pp, c->Ports) {
00599     x = pp->x+c->cx;
00600     y = pp->y+c->cy;
00601 
00602     // check if new node lies upon existing node
00603     for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
00604       if(pn->cx == x) if(pn->cy == y) {
00605   if (!pn->DType.isEmpty()) {
00606     pp->Type = pn->DType;
00607   }
00608   if (!pp->Type.isEmpty()) {
00609     pn->DType = pp->Type;
00610   }
00611   break;
00612       }
00613 
00614     if(pn == 0) { // create new node, if no existing one lies at this position
00615       pn = new Node(x, y);
00616       DocNodes.append(pn);
00617     }
00618     pn->Connections.append(c);  // connect schematic node to component node
00619     if (!pp->Type.isEmpty()) {
00620       pn->DType = pp->Type;
00621     }
00622 
00623     pp->Connection = pn;  // connect component node to schematic node
00624   }
00625 
00626   DocComps.append(c);
00627 }
00628 
00629 // -------------------------------------------------------------
00630 bool Schematic::loadComponents(QTextStream *stream, Q3PtrList<Component> *List)
00631 {
00632   QString Line, cstr;
00633   Component *c;
00634   while(!stream->atEnd()) {
00635     Line = stream->readLine();
00636     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
00637     Line = Line.trimmed();
00638     if(Line.isEmpty()) continue;
00639 
00641     c = getComponentFromName(Line, this);
00642     if(!c) return false;
00643 
00644     if(List) {  // "paste" ?
00645       int z;
00646       for(z=c->Name.length()-1; z>=0; z--) // cut off number of component name
00647         if(!c->Name.at(z).isDigit()) break;
00648       c->Name = c->Name.left(z+1);
00649       List->append(c);
00650     }
00651     else  simpleInsertComponent(c);
00652   }
00653 
00654   QMessageBox::critical(0, QObject::tr("Error"),
00655      QObject::tr("Format Error:\n'Component' field is not closed!"));
00656   return false;
00657 }
00658 
00659 // -------------------------------------------------------------
00660 // Inserts a wire without performing logic for optimizing.
00661 void Schematic::simpleInsertWire(Wire *pw)
00662 {
00663   Node *pn;
00664   // check if first wire node lies upon existing node
00665   for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
00666     if(pn->cx == pw->x1) if(pn->cy == pw->y1) break;
00667 
00668   if(!pn) {   // create new node, if no existing one lies at this position
00669     pn = new Node(pw->x1, pw->y1);
00670     DocNodes.append(pn);
00671   }
00672 
00673   if(pw->x1 == pw->x2) if(pw->y1 == pw->y2) {
00674     pn->Label = pw->Label;   // wire with length zero are just node labels
00675     if (pn->Label) {
00676       pn->Label->Type = isNodeLabel;
00677       pn->Label->pOwner = pn;
00678     }
00679     delete pw;           // delete wire because this is not a wire
00680     return;
00681   }
00682   pn->Connections.append(pw);  // connect schematic node to component node
00683   pw->Port1 = pn;
00684 
00685   // check if second wire node lies upon existing node
00686   for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
00687     if(pn->cx == pw->x2) if(pn->cy == pw->y2) break;
00688 
00689   if(!pn) {   // create new node, if no existing one lies at this position
00690     pn = new Node(pw->x2, pw->y2);
00691     DocNodes.append(pn);
00692   }
00693   pn->Connections.append(pw);  // connect schematic node to component node
00694   pw->Port2 = pn;
00695 
00696   DocWires.append(pw);
00697 }
00698 
00699 // -------------------------------------------------------------
00700 bool Schematic::loadWires(QTextStream *stream, Q3PtrList<Element> *List)
00701 {
00702   Wire *w;
00703   QString Line;
00704   while(!stream->atEnd()) {
00705     Line = stream->readLine();
00706     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
00707     Line = Line.trimmed();
00708     if(Line.isEmpty()) continue;
00709 
00710     // (Node*)4 =  move all ports (later on)
00711     w = new Wire(0,0,0,0, (Node*)4,(Node*)4);
00712     if(!w->load(Line)) {
00713       QMessageBox::critical(0, QObject::tr("Error"),
00714     QObject::tr("Format Error:\nWrong 'wire' line format!"));
00715       delete w;
00716       return false;
00717     }
00718     if(List) {
00719       if(w->x1 == w->x2) if(w->y1 == w->y2) if(w->Label) {
00720   w->Label->Type = isMovingLabel;
00721   List->append(w->Label);
00722   delete w;
00723   continue;
00724       }
00725       List->append(w);
00726       if(w->Label)  List->append(w->Label);
00727     }
00728     else simpleInsertWire(w);
00729   }
00730 
00731   QMessageBox::critical(0, QObject::tr("Error"),
00732     QObject::tr("Format Error:\n'Wire' field is not closed!"));
00733   return false;
00734 }
00735 
00736 // -------------------------------------------------------------
00737 bool Schematic::loadDiagrams(QTextStream *stream, Q3PtrList<Diagram> *List)
00738 {
00739   Diagram *d;
00740   QString Line, cstr;
00741   while(!stream->atEnd()) {
00742     Line = stream->readLine();
00743     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
00744     Line = Line.trimmed();
00745     if(Line.isEmpty()) continue;
00746 
00747     cstr = Line.section(' ',0,0);    // diagram type
00748          if(cstr == "<Rect") d = new RectDiagram();
00749     else if(cstr == "<Polar") d = new PolarDiagram();
00750     else if(cstr == "<Tab") d = new TabDiagram();
00751     else if(cstr == "<Smith") d = new SmithDiagram();
00752     else if(cstr == "<ySmith") d = new SmithDiagram(0,0,false);
00753     else if(cstr == "<PS") d = new PSDiagram();
00754     else if(cstr == "<SP") d = new PSDiagram(0,0,false);
00755     else if(cstr == "<Rect3D") d = new Rect3DDiagram();
00756     else if(cstr == "<Curve") d = new CurveDiagram();
00757     else if(cstr == "<Time") d = new TimingDiagram();
00758     else if(cstr == "<Truth") d = new TruthDiagram();
00759     else {
00760       QMessageBox::critical(0, QObject::tr("Error"),
00761        QObject::tr("Format Error:\nUnknown diagram!"));
00762       return false;
00763     }
00764 
00765     if(!d->load(Line, stream)) {
00766       QMessageBox::critical(0, QObject::tr("Error"),
00767     QObject::tr("Format Error:\nWrong 'diagram' line format!"));
00768       delete d;
00769       return false;
00770     }
00771     List->append(d);
00772   }
00773 
00774   QMessageBox::critical(0, QObject::tr("Error"),
00775          QObject::tr("Format Error:\n'Diagram' field is not closed!"));
00776   return false;
00777 }
00778 
00779 // -------------------------------------------------------------
00780 bool Schematic::loadPaintings(QTextStream *stream, Q3PtrList<Painting> *List)
00781 {
00782   Painting *p=0;
00783   QString Line, cstr;
00784   while(!stream->atEnd()) {
00785     Line = stream->readLine();
00786     if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
00787 
00788     Line = Line.trimmed();
00789     if(Line.isEmpty()) continue;
00790     if( (Line.at(0) != '<') || (Line.at(Line.length()-1) != '>')) {
00791       QMessageBox::critical(0, QObject::tr("Error"),
00792   QObject::tr("Format Error:\nWrong 'painting' line delimiter!"));
00793       return false;
00794     }
00795     Line = Line.mid(1, Line.length()-2);  // cut off start and end character
00796 
00797     cstr = Line.section(' ',0,0);    // painting type
00798          if(cstr == "Line") p = new GraphicLine();
00799     else if(cstr == "EArc") p = new EllipseArc();
00800     else if(cstr == ".PortSym") p = new PortSymbol();
00801     else if(cstr == ".ID") p = new ID_Text();
00802     else if(cstr == "Text") p = new GraphicText();
00803     else if(cstr == "Rectangle") p = new Rectangle();
00804     else if(cstr == "Arrow") p = new Arrow();
00805     else if(cstr == "Ellipse") p = new Ellipse();
00806     else {
00807       QMessageBox::critical(0, QObject::tr("Error"),
00808     QObject::tr("Format Error:\nUnknown painting!"));
00809       return false;
00810     }
00811 
00812     if(!p->load(Line)) {
00813       QMessageBox::critical(0, QObject::tr("Error"),
00814   QObject::tr("Format Error:\nWrong 'painting' line format!"));
00815       delete p;
00816       return false;
00817     }
00818     List->append(p);
00819   }
00820 
00821   QMessageBox::critical(0, QObject::tr("Error"),
00822   QObject::tr("Format Error:\n'Painting' field is not closed!"));
00823   return false;
00824 }
00825 
00830 bool Schematic::loadDocument()
00831 {
00832   QFile file(DocName);
00833   if(!file.open(QIODevice::ReadOnly)) {
00835     if (QucsMain)
00836       QMessageBox::critical(0, QObject::tr("Error"),
00837                  QObject::tr("Cannot load document: ")+DocName);
00838     else
00839       qCritical() << "Schematic::loadDocument:"
00840                   << QObject::tr("Cannot load document: ")+DocName;
00841     return false;
00842   }
00843 
00844   // Keep reference to source file (the schematic file)
00845   setFileInfo(DocName);
00846 
00847   QString Line;
00848   QTextStream stream(&file);
00849 
00850   // read header **************************
00851   do {
00852     if(stream.atEnd()) {
00853       file.close();
00854       return true;
00855     }
00856 
00857     Line = stream.readLine();
00858   } while(Line.isEmpty());
00859 
00860   if(Line.left(16) != "<Qucs Schematic ") {  // wrong file type ?
00861     file.close();
00862     QMessageBox::critical(0, QObject::tr("Error"),
00863      QObject::tr("Wrong document type: ")+DocName);
00864     return false;
00865   }
00866 
00867   Line = Line.mid(16, Line.length()-17);
00868   if(!misc::checkVersion(Line)) { // wrong version number ?
00869 
00870     QMessageBox::StandardButton result;
00871     result = QMessageBox::warning(0,
00872                                   QObject::tr("Warning"),
00873                                   QObject::tr("Wrong document version \n" +
00874                                               DocName + "\n"
00875                                               "Try to open it anyway?"),
00876                                   QMessageBox::Yes|QMessageBox::No);
00877 
00878     if (result==QMessageBox::No) {
00879         file.close();
00880         return false;
00881     }
00882 
00883     //QMessageBox::critical(0, QObject::tr("Error"),
00884         // QObject::tr("Wrong document version: ")+Line);
00885   }
00886 
00887   // read content *************************
00888   while(!stream.atEnd()) {
00889     Line = stream.readLine();
00890     Line = Line.trimmed();
00891     if(Line.isEmpty()) continue;
00892 
00893     if(Line == "<Symbol>") {
00894       if(!loadPaintings(&stream, &SymbolPaints)) {
00895         file.close();
00896         return false;
00897       }
00898     }
00899     else
00900     if(Line == "<Properties>") {
00901       if(!loadProperties(&stream)) { file.close(); return false; } }
00902     else
00903     if(Line == "<Components>") {
00904       if(!loadComponents(&stream)) { file.close(); return false; } }
00905     else
00906     if(Line == "<Wires>") {
00907       if(!loadWires(&stream)) { file.close(); return false; } }
00908     else
00909     if(Line == "<Diagrams>") {
00910       if(!loadDiagrams(&stream, &DocDiags)) { file.close(); return false; } }
00911     else
00912     if(Line == "<Paintings>") {
00913       if(!loadPaintings(&stream, &DocPaints)) { file.close(); return false; } }
00914     else {
00915        qDebug() << Line;
00916        QMessageBox::critical(0, QObject::tr("Error"),
00917        QObject::tr("File Format Error:\nUnknown field!"));
00918       file.close();
00919       return false;
00920     }
00921   }
00922 
00923   file.close();
00924   return true;
00925 }
00926 
00927 // -------------------------------------------------------------
00928 // Creates a Qucs file format (without document properties) in the returning
00929 // string. This is used to save state for undo operation.
00930 QString Schematic::createUndoString(char Op)
00931 {
00932   Wire *pw;
00933   Diagram *pd;
00934   Painting *pp;
00935   Component *pc;
00936 
00937   // Build element document.
00938   QString s = "  \n";
00939   s.replace(0,1,Op);
00940   for(pc = DocComps.first(); pc != 0; pc = DocComps.next())
00941     s += pc->save()+"\n";
00942   s += "</>\n";  // short end flag
00943 
00944   for(pw = DocWires.first(); pw != 0; pw = DocWires.next())
00945     s += pw->save()+"\n";
00946   // save all labeled nodes as wires
00947   for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
00948     if(pn->Label) s += pn->Label->save()+"\n";
00949   s += "</>\n";
00950 
00951   for(pd = DocDiags.first(); pd != 0; pd = DocDiags.next())
00952     s += pd->save()+"\n";
00953   s += "</>\n";
00954 
00955   for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next())
00956     s += "<"+pp->save()+">\n";
00957   s += "</>\n";
00958 
00959   return s;
00960 }
00961 
00962 // -------------------------------------------------------------
00963 // Same as "createUndoString(char Op)" but for symbol edit mode.
00964 QString Schematic::createSymbolUndoString(char Op)
00965 {
00966   Painting *pp;
00967 
00968   // Build element document.
00969   QString s = "  \n";
00970   s.replace(0,1,Op);
00971   s += "</>\n";  // short end flag for components
00972   s += "</>\n";  // short end flag for wires
00973   s += "</>\n";  // short end flag for diagrams
00974 
00975   for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next())
00976     s += "<"+pp->save()+">\n";
00977   s += "</>\n";
00978 
00979   return s;
00980 }
00981 
00982 // -------------------------------------------------------------
00983 // Is quite similiar to "loadDocument()" but with less error checking.
00984 // Used for "undo" function.
00985 bool Schematic::rebuild(QString *s)
00986 {
00987   DocWires.clear(); // delete whole document
00988   DocNodes.clear();
00989   DocComps.clear();
00990   DocDiags.clear();
00991   DocPaints.clear();
00992 
00993   QString Line;
00994   QTextStream stream(s, QIODevice::ReadOnly);
00995   Line = stream.readLine();  // skip identity byte
00996 
00997   // read content *************************
00998   if(!loadComponents(&stream))  return false;
00999   if(!loadWires(&stream))  return false;
01000   if(!loadDiagrams(&stream, &DocDiags))  return false;
01001   if(!loadPaintings(&stream, &DocPaints)) return false;
01002 
01003   return true;
01004 }
01005 
01006 // -------------------------------------------------------------
01007 // Same as "rebuild(QString *s)" but for symbol edit mode.
01008 bool Schematic::rebuildSymbol(QString *s)
01009 {
01010   SymbolPaints.clear(); // delete whole document
01011 
01012   QString Line;
01013   QTextStream stream(s, QIODevice::ReadOnly);
01014   Line = stream.readLine();  // skip identity byte
01015 
01016   // read content *************************
01017   Line = stream.readLine();  // skip components
01018   Line = stream.readLine();  // skip wires
01019   Line = stream.readLine();  // skip diagrams
01020   if(!loadPaintings(&stream, &SymbolPaints)) return false;
01021 
01022   return true;
01023 }
01024 
01025 
01026 // ***************************************************************
01027 // *****                                                     *****
01028 // *****             Functions to create netlist             *****
01029 // *****                                                     *****
01030 // ***************************************************************
01031 
01032 void Schematic::createNodeSet(QStringList& Collect, int& countInit,
01033             Conductor *pw, Node *p1)
01034 {
01035   if(pw->Label)
01036     if(!pw->Label->initValue.isEmpty())
01037       Collect.append("NodeSet:NS" + QString::number(countInit++) + " " +
01038                      p1->Name + " U=\"" + pw->Label->initValue + "\"");
01039 }
01040 
01041 // ---------------------------------------------------
01042 void Schematic::throughAllNodes(bool User, QStringList& Collect,
01043         int& countInit)
01044 {
01045   Node *pn;
01046   int z=0;
01047 
01048   for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
01049     if(pn->Name.isEmpty() == User) {
01050       continue;  // already named ?
01051     }
01052     if(!User) {
01053       if(isAnalog)
01054   pn->Name = "_net";
01055       else
01056   pn->Name = "net_net";   // VHDL names must not begin with '_'
01057       pn->Name += QString::number(z++);  // create numbered node name
01058     }
01059     else if(pn->State) {
01060       continue;  // already worked on
01061     }
01062 
01063     if(isAnalog) createNodeSet(Collect, countInit, pn, pn);
01064 
01065     pn->State = 1;
01066     propagateNode(Collect, countInit, pn);
01067   }
01068 }
01069 
01070 // ----------------------------------------------------------
01071 // Checks whether this file is a qucs file and whether it is an subcircuit.
01072 // It returns the number of subcircuit ports.
01073 int Schematic::testFile(const QString& DocName)
01074 {
01075   QFile file(DocName);
01076   if(!file.open(QIODevice::ReadOnly)) {
01077     return -1;
01078   }
01079 
01080   QString Line;
01081   // .........................................
01082   // To strongly speed up the file read operation the whole file is
01083   // read into the memory in one piece.
01084   QTextStream ReadWhole(&file);
01085   QString FileString = ReadWhole.read();
01086   file.close();
01087   QTextStream stream(&FileString, QIODevice::ReadOnly);
01088 
01089 
01090   // read header ........................
01091   do {
01092     if(stream.atEnd()) {
01093       file.close();
01094       return -2;
01095     }
01096     Line = stream.readLine();
01097     Line = Line.trimmed();
01098   } while(Line.isEmpty());
01099 
01100   if(Line.left(16) != "<Qucs Schematic ") {  // wrong file type ?
01101     file.close();
01102     return -3;
01103   }
01104 
01105   Line = Line.mid(16, Line.length()-17);
01106   if(!misc::checkVersion(Line)) { // wrong version number ?
01107       if (!QucsSettings.IgnoreFutureVersion) {
01108           file.close();
01109           return -4;
01110       }
01111     //file.close();
01112     //return -4;
01113   }
01114 
01115   // read content ....................
01116   while(!stream.atEnd()) {
01117     Line = stream.readLine();
01118     if(Line == "<Components>") break;
01119   }
01120 
01121   int z=0;
01122   while(!stream.atEnd()) {
01123     Line = stream.readLine();
01124     if(Line == "</Components>") {
01125       file.close();
01126       return z;       // return number of ports
01127     }
01128 
01129     Line = Line.trimmed();
01130     QString s = Line.section(' ',0,0);    // component type
01131     if(s == "<Port") z++;
01132   }
01133   return -5;  // component field not closed
01134 }
01135 
01136 // ---------------------------------------------------
01137 // Collects the signal names for digital simulations.
01138 void Schematic::collectDigitalSignals(void)
01139 {
01140   Node *pn;
01141 
01142   for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
01143     DigMap::Iterator it = Signals.find(pn->Name);
01144     if(it == Signals.end()) { // avoid redeclaration of signal
01145       Signals.insert(pn->Name, DigSignal(pn->Name, pn->DType));
01146     } else if (!pn->DType.isEmpty()) {
01147       it.data().Type = pn->DType;
01148     }
01149   }
01150 }
01151 
01152 // ---------------------------------------------------
01153 // Propagates the given node to connected component ports.
01154 void Schematic::propagateNode(QStringList& Collect,
01155             int& countInit, Node *pn)
01156 {
01157   bool setName=false;
01158   Q3PtrList<Node> Cons;
01159   Node *p2;
01160   Wire *pw;
01161   Element *pe;
01162 
01163   Cons.append(pn);
01164   for(p2 = Cons.first(); p2 != 0; p2 = Cons.next())
01165     for(pe = p2->Connections.first(); pe != 0; pe = p2->Connections.next())
01166       if(pe->Type == isWire) {
01167   pw = (Wire*)pe;
01168   if(p2 != pw->Port1) {
01169     if(pw->Port1->Name.isEmpty()) {
01170       pw->Port1->Name = pn->Name;
01171       pw->Port1->State = 1;
01172       Cons.append(pw->Port1);
01173       setName = true;
01174     }
01175   }
01176   else {
01177     if(pw->Port2->Name.isEmpty()) {
01178       pw->Port2->Name = pn->Name;
01179       pw->Port2->State = 1;
01180       Cons.append(pw->Port2);
01181       setName = true;
01182     }
01183   }
01184   if(setName) {
01185     Cons.findRef(p2);   // back to current Connection
01186     if (isAnalog) createNodeSet(Collect, countInit, pw, pn);
01187     setName = false;
01188   }
01189       }
01190   Cons.clear();
01191 }
01192 
01193 #include <iostream>
01194 
01206 bool Schematic::throughAllComps(QTextStream *stream, int& countInit,
01207                    QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts)
01208 {
01209   bool r;
01210   QString s;
01211 
01212   // give the ground nodes the name "gnd", and insert subcircuits etc.
01213   Q3PtrListIterator<Component> it(DocComps);
01214   Component *pc;
01215   while((pc = it.current()) != 0) {
01216     ++it;
01217     if(pc->isActive != COMP_IS_ACTIVE) continue;
01218 
01219     // check analog/digital typed components
01220     if(isAnalog) {
01221       if((pc->Type & isAnalogComponent) == 0) {
01222         ErrText->appendPlainText(QObject::tr("ERROR: Component \"%1\" has no analog model.").arg(pc->Name));
01223         return false;
01224       }
01225     } else {
01226       if((pc->Type & isDigitalComponent) == 0) {
01227         ErrText->appendPlainText(QObject::tr("ERROR: Component \"%1\" has no digital model.").arg(pc->Name));
01228         return false;
01229       }
01230     }
01231 
01232     // handle ground symbol
01233     if(pc->Model == "GND") {
01234       pc->Ports.first()->Connection->Name = "gnd";
01235       continue;
01236     }
01237 
01238     // handle subcircuits
01239     if(pc->Model == "Sub")
01240     {
01241       int i;
01242       // tell the subcircuit it belongs to this schematic
01243       pc->setSchematic (this);
01244       QString f = pc->getSubcircuitFile();
01245       SubMap::Iterator it = FileList.find(f);
01246       if(it != FileList.end())
01247       {
01248         if (!it.data().PortTypes.isEmpty())
01249         {
01250           i = 0;
01251           // apply in/out signal types of subcircuit
01252           foreach(Port *pp, pc->Ports)
01253           {
01254             pp->Type = it.data().PortTypes[i];
01255             pp->Connection->DType = pp->Type;
01256             i++;
01257           }
01258         }
01259         continue;   // insert each subcircuit just one time
01260       }
01261 
01262       // The subcircuit has not previously been added
01263       SubFile sub = SubFile("SCH", f);
01264       FileList.insert(f, sub);
01265 
01266 
01267       // load subcircuit schematic
01268       s = pc->Props.first()->Value;
01269       Schematic *d = new Schematic(0, pc->getSubcircuitFile());
01270       if(!d->loadDocument())      // load document if possible
01271       {
01272           delete d;
01274           QString message = QObject::tr("ERROR: Cannot load subcircuit \"%1\".").arg(s);
01275           if (QucsMain) // GUI is running
01276             ErrText->appendPlainText(message);
01277           else // command line
01278             qCritical() << "Schematic::throughAllComps" << message;
01279           return false;
01280       }
01281       d->DocName = s;
01282       d->isVerilog = isVerilog;
01283       d->isAnalog = isAnalog;
01284       d->creatingLib = creatingLib;
01285       r = d->createSubNetlist(stream, countInit, Collect, ErrText, NumPorts);
01286       if (r)
01287       {
01288         i = 0;
01289         // save in/out signal types of subcircuit
01290         foreach(Port *pp, pc->Ports)
01291         {
01292             //if(i>=d->PortTypes.count())break;
01293             pp->Type = d->PortTypes[i];
01294             pp->Connection->DType = pp->Type;
01295             i++;
01296         }
01297         sub.PortTypes = d->PortTypes;
01298         FileList.replace(f, sub);
01299       }
01300       delete d;
01301       if(!r)
01302       {
01303         return false;
01304       }
01305       continue;
01306     } // if(pc->Model == "Sub")
01307 
01308     // handle library symbols
01309     if(pc->Model == "Lib") {
01310       if(creatingLib) {
01311   ErrText->appendPlainText(
01312       QObject::tr("WARNING: Skipping library component \"%1\".").
01313       arg(pc->Name));
01314   continue;
01315       }
01316       s = pc->getSubcircuitFile() + "/" + pc->Props.at(1)->Value;
01317       SubMap::Iterator it = FileList.find(s);
01318       if(it != FileList.end())
01319         continue;   // insert each library subcircuit just one time
01320       FileList.insert(s, SubFile("LIB", s));
01321 
01322       if(isAnalog)
01323   r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 1);
01324       else {
01325   if(isVerilog)
01326     r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 4);
01327   else
01328     r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 2);
01329       }
01330       if(!r) {
01331   ErrText->appendPlainText(
01332       QObject::tr("ERROR: Cannot load library component \"%1\".").
01333       arg(pc->Name));
01334   return false;
01335       }
01336       continue;
01337     }
01338 
01339     // handle SPICE subcircuit components
01340     if(pc->Model == "SPICE") {
01341       s = pc->Props.first()->Value;
01342       // tell the spice component it belongs to this schematic
01343       pc->setSchematic (this);
01344       if(s.isEmpty()) {
01345         ErrText->appendPlainText(QObject::tr("ERROR: No file name in SPICE component \"%1\".").
01346                         arg(pc->Name));
01347         return false;
01348       }
01349       QString f = pc->getSubcircuitFile();
01350       SubMap::Iterator it = FileList.find(f);
01351       if(it != FileList.end())
01352         continue;   // insert each spice component just one time
01353       FileList.insert(f, SubFile("CIR", f));
01354 
01355       SpiceFile *sf = (SpiceFile*)pc;
01356       r = sf->createSubNetlist(stream);
01357       ErrText->appendPlainText(sf->getErrorText());
01358       if(!r) return false;
01359       continue;
01360     }
01361 
01362     // handle digital file subcircuits
01363     if(pc->Model == "VHDL" || pc->Model == "Verilog") {
01364       if(isVerilog && pc->Model == "VHDL")
01365   continue;
01366       if(!isVerilog && pc->Model == "Verilog")
01367   continue;
01368       s = pc->Props.getFirst()->Value;
01369       if(s.isEmpty()) {
01370         ErrText->appendPlainText(QObject::tr("ERROR: No file name in %1 component \"%2\".").
01371       arg(pc->Model).
01372                         arg(pc->Name));
01373         return false;
01374       }
01375       QString f = pc->getSubcircuitFile();
01376       SubMap::Iterator it = FileList.find(f);
01377       if(it != FileList.end())
01378         continue;   // insert each vhdl/verilog component just one time
01379       s = ((pc->Model == "VHDL") ? "VHD" : "VER");
01380       FileList.insert(f, SubFile(s, f));
01381 
01382       if(pc->Model == "VHDL") {
01383   VHDL_File *vf = (VHDL_File*)pc;
01384   r = vf->createSubNetlist(stream);
01385   ErrText->appendPlainText(vf->getErrorText());
01386   if(!r) return false;
01387       }
01388       if(pc->Model == "Verilog") {
01389   Verilog_File *vf = (Verilog_File*)pc;
01390   r = vf->createSubNetlist(stream);
01391   ErrText->appendPlainText(vf->getErrorText());
01392   if(!r) return false;
01393       }
01394       continue;
01395     }
01396   }
01397   return true;
01398 }
01399 
01400 // ---------------------------------------------------
01401 // Follows the wire lines in order to determine the node names for
01402 // each component. Output into "stream", NodeSets are collected in
01403 // "Collect" and counted with "countInit".
01404 bool Schematic::giveNodeNames(QTextStream *stream, int& countInit,
01405                    QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts)
01406 {
01407   // delete the node names
01408   for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
01409     pn->State = 0;
01410     if(pn->Label) {
01411       if(isAnalog)
01412         pn->Name = pn->Label->Name;
01413       else
01414         pn->Name = "net" + pn->Label->Name;
01415     }
01416     else pn->Name = "";
01417   }
01418 
01419   // set the wire names to the connected node
01420   for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next())
01421     if(pw->Label != 0) {
01422       if(isAnalog)
01423         pw->Port1->Name = pw->Label->Name;
01424       else  // avoid to use reserved VHDL words
01425         pw->Port1->Name = "net" + pw->Label->Name;
01426     }
01427 
01428   // go through components
01429   if(!throughAllComps(stream, countInit, Collect, ErrText, NumPorts))
01430     return false;
01431 
01432   // work on named nodes first in order to preserve the user given names
01433   throughAllNodes(true, Collect, countInit);
01434 
01435   // give names to the remaining (unnamed) nodes
01436   throughAllNodes(false, Collect, countInit);
01437 
01438   if(!isAnalog) // collect all node names for VHDL signal declaration
01439     collectDigitalSignals();
01440 
01441   return true;
01442 }
01443 
01444 // ---------------------------------------------------
01445 bool Schematic::createLibNetlist(QTextStream *stream, QPlainTextEdit *ErrText,
01446          int NumPorts)
01447 {
01448   int countInit = 0;
01449   QStringList Collect;
01450   Collect.clear();
01451   FileList.clear();
01452   Signals.clear();
01453   // Apply node names and collect subcircuits and file include
01454   creatingLib = true;
01455   if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts)) {
01456     creatingLib = false;
01457     return false;
01458   }
01459   creatingLib = false;
01460 
01461   // Marking start of actual top-level subcircuit
01462   QString c;
01463   if(!isAnalog) {
01464     if (isVerilog)
01465       c = "///";
01466     else
01467       c = "---";
01468   }
01469   else c = "###";
01470   (*stream) << "\n" << c << " TOP LEVEL MARK " << c << "\n";
01471 
01472   // Emit subcircuit components
01473   createSubNetlistPlain(stream, ErrText, NumPorts);
01474 
01475   Signals.clear();  // was filled in "giveNodeNames()"
01476   return true;
01477 }
01478 
01479 //#define VHDL_SIGNAL_TYPE "bit"
01480 //#define VHDL_LIBRARIES   ""
01481 #define VHDL_SIGNAL_TYPE "std_logic"
01482 #define VHDL_LIBRARIES   "\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n"
01483 
01484 // ---------------------------------------------------
01485 void Schematic::createSubNetlistPlain(QTextStream *stream, QPlainTextEdit *ErrText,
01486 int NumPorts)
01487 {
01488   int i, z;
01489   QString s;
01490   QStringList SubcircuitPortNames;
01491   QStringList SubcircuitPortTypes;
01492   QStringList InPorts;
01493   QStringList OutPorts;
01494   QStringList InOutPorts;
01495   QStringList::iterator it_name;
01496   QStringList::iterator it_type;
01497   Component *pc;
01498 
01499   // probably creating a library currently
01500   QTextStream * tstream = stream;
01501   QFile ofile;
01502   if(creatingLib) {
01503     QString f = misc::properAbsFileName(DocName) + ".lst";
01504     ofile.setFileName(f);
01505     if(!ofile.open(IO_WriteOnly)) {
01506       ErrText->appendPlainText(tr("ERROR: Cannot create library file \"%s\".").arg(f));
01507       return;
01508     }
01509     tstream = new QTextStream(&ofile);
01510   }
01511 
01512   // collect subcircuit ports and sort their node names into
01513   // "SubcircuitPortNames"
01514   PortTypes.clear();
01515   for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01516     if(pc->Model.at(0) == '.') { // no simulations in subcircuits
01517       ErrText->appendPlainText(
01518         QObject::tr("WARNING: Ignore simulation component in subcircuit \"%1\".").arg(DocName)+"\n");
01519       continue;
01520     }
01521     else if(pc->Model == "Port") {
01522       i = pc->Props.first()->Value.toInt();
01523       for(z=SubcircuitPortNames.size(); z<i; z++) { // add empty port names
01524         SubcircuitPortNames.append(" ");
01525         SubcircuitPortTypes.append(" ");
01526       }
01527       it_name = SubcircuitPortNames.begin();
01528       it_type = SubcircuitPortTypes.begin();
01529       for(int n=1;n<i;n++)
01530       {
01531         it_name++;
01532         it_type++;
01533       }
01534       (*it_name) = pc->Ports.first()->Connection->Name;
01535       DigMap::Iterator it = Signals.find(*it_name);
01536       if(it!=Signals.end())
01537         (*it_type) = it.data().Type;
01538       // propagate type to port symbol
01539       pc->Ports.first()->Connection->DType = *it_type;
01540 
01541       if(!isAnalog) {
01542         if (isVerilog) {
01543           Signals.erase(*it_name); // remove node name
01544           switch(pc->Props.at(1)->Value.at(0).toLatin1()) {
01545             case 'a':
01546               InOutPorts.append(*it_name);
01547               break;
01548             case 'o':
01549               OutPorts.append(*it_name);
01550               break;
01551               default:
01552                 InPorts.append(*it_name);
01553           }
01554         }
01555         else {
01556           // remove node name of output port
01557           Signals.erase(*it_name);
01558           switch(pc->Props.at(1)->Value.at(0).toLatin1()) {
01559             case 'a':
01560               (*it_name) += " : inout"; // attribute "analog" is "inout"
01561               break;
01562             case 'o': // output ports need workaround
01563               Signals.insert(*it_name, DigSignal(*it_name, *it_type));
01564               (*it_name) = "net_out" + (*it_name);
01565               // no "break;" here !!!
01566             default:
01567               (*it_name) += " : " + pc->Props.at(1)->Value;
01568           }
01569           (*it_name) += " " + ((*it_type).isEmpty() ?
01570           VHDL_SIGNAL_TYPE : (*it_type));
01571         }
01572       }
01573     }
01574   }
01575 
01576   // remove empty subcircuit ports (missing port numbers)
01577   for(it_name = SubcircuitPortNames.begin(),
01578       it_type = SubcircuitPortTypes.begin();
01579       it_name != SubcircuitPortNames.end(); ) {
01580     if(*it_name == " ") {
01581       it_name = SubcircuitPortNames.remove(it_name);
01582       it_type = SubcircuitPortTypes.remove(it_type);
01583     } else {
01584       PortTypes.append(*it_type);
01585       it_name++;
01586       it_type++;
01587     }
01588   }
01589 
01590   QString f = misc::properFileName(DocName);
01591   QString Type = misc::properName(f);
01592 
01593   Painting *pi;
01594   if(isAnalog) {
01595     // ..... analog subcircuit ...................................
01596     (*tstream) << "\n.Def:" << Type << " " << SubcircuitPortNames.join(" ");
01597     for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
01598       if(pi->Name == ".ID ") {
01599         ID_Text *pid = (ID_Text*)pi;
01600         QList<SubParameter *>::const_iterator it;
01601         for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) {
01602           s = (*it)->Name; // keep 'Name' unchanged
01603           (*tstream) << " " << s.replace("=", "=\"") << '"';
01604         }
01605         break;
01606       }
01607     (*tstream) << '\n';
01608 
01609     // write all components with node names into netlist file
01610     for(pc = DocComps.first(); pc != 0; pc = DocComps.next())
01611       (*tstream) << pc->getNetlist();
01612 
01613     (*tstream) << ".Def:End\n";
01614 
01615   }
01616   else {
01617     if (isVerilog) {
01618       // ..... digital subcircuit ...................................
01619       (*tstream) << "\nmodule Sub_" << Type << " ("
01620               << SubcircuitPortNames.join(", ") << ");\n";
01621 
01622       // subcircuit in/out connections
01623       if(!InPorts.isEmpty())
01624         (*tstream) << " input " << InPorts.join(", ") << ";\n";
01625       if(!OutPorts.isEmpty())
01626         (*tstream) << " output " << OutPorts.join(", ") << ";\n";
01627       if(!InOutPorts.isEmpty())
01628         (*tstream) << " inout " << InOutPorts.join(", ") << ";\n";
01629 
01630       // subcircuit connections
01631       if(!Signals.isEmpty()) {
01632         QList<DigSignal> values = Signals.values();
01633         QList<DigSignal>::const_iterator it;
01634         for (it = values.constBegin(); it != values.constEnd(); ++it) {
01635           (*tstream) << " wire " << (*it).Name << ";\n";
01636         }
01637       }
01638       (*tstream) << "\n";
01639 
01640       // subcircuit parameters
01641       for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
01642         if(pi->Name == ".ID ") {
01643           QList<SubParameter *>::const_iterator it;
01644           ID_Text *pid = (ID_Text*)pi;
01645           for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) {
01646             s = (*it)->Name.section('=', 0,0);
01647             QString v = misc::Verilog_Param((*it)->Name.section('=', 1,1));
01648             (*tstream) << " parameter " << s << " = " << v << ";\n";
01649           }
01650           (*tstream) << "\n";
01651           break;
01652         }
01653 
01654       // write all equations into netlist file
01655       for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01656         if(pc->Model == "Eqn") {
01657           (*tstream) << pc->get_Verilog_Code(NumPorts);
01658         }
01659       }
01660 
01661       if(Signals.find("gnd") != Signals.end())
01662       (*tstream) << " assign gnd = 0;\n"; // should appear only once
01663 
01664       // write all components into netlist file
01665       for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01666         if(pc->Model != "Eqn") {
01667           s = pc->get_Verilog_Code(NumPorts);
01668           if(s.length()>0 && s.at(0) == '\xA7') {  //section symbol
01669             ErrText->appendPlainText(s.mid(1));
01670           }
01671           else (*tstream) << s;
01672         }
01673       }
01674 
01675       (*tstream) << "endmodule\n";
01676     } else {
01677       // ..... digital subcircuit ...................................
01678       (*tstream) << VHDL_LIBRARIES;
01679       (*tstream) << "entity Sub_" << Type << " is\n"
01680                 << " port ("
01681                 << SubcircuitPortNames.join(";\n ") << ");\n";
01682 
01683       for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
01684         if(pi->Name == ".ID ") {
01685           ID_Text *pid = (ID_Text*)pi;
01686           QList<SubParameter *>::const_iterator it;
01687 
01688           (*tstream) << " generic (";
01689 
01690           for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) {
01691             s = (*it)->Name;
01692             QString t = (*it)->Type.isEmpty() ? "real" : (*it)->Type;
01693             (*tstream) << s.replace("=", " : "+t+" := ") << ";\n ";
01694           }
01695 
01696           (*tstream) << ");\n";
01697           break;
01698         }
01699 
01700       (*tstream) << "end entity;\n"
01701                   << "use work.all;\n"
01702                   << "architecture Arch_Sub_" << Type << " of Sub_" << Type
01703                   << " is\n";
01704 
01705       if(!Signals.isEmpty()) {
01706         QList<DigSignal> values = Signals.values();
01707         QList<DigSignal>::const_iterator it;
01708         for (it = values.constBegin(); it != values.constEnd(); ++it) {
01709           (*tstream) << " signal " << (*it).Name << " : "
01710           << ((*it).Type.isEmpty() ?
01711           VHDL_SIGNAL_TYPE : (*it).Type) << ";\n";
01712         }
01713       }
01714 
01715       // write all equations into netlist file
01716       for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01717         if(pc->Model == "Eqn") {
01718           ErrText->appendPlainText(
01719                       QObject::tr("WARNING: Equations in \"%1\" are 'time' typed.").
01720           arg(pc->Name));
01721           (*tstream) << pc->get_VHDL_Code(NumPorts);
01722         }
01723       }
01724 
01725       (*tstream) << "begin\n";
01726 
01727       if(Signals.find("gnd") != Signals.end())
01728       (*tstream) << " gnd <= '0';\n"; // should appear only once
01729 
01730       // write all components into netlist file
01731       for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01732         if(pc->Model != "Eqn") {
01733             s = pc->get_VHDL_Code(NumPorts);
01734             if(s.length()>0 && s.at(0) == '\xA7') {  //section symbol
01735               ErrText->appendPlainText(s.mid(1));
01736           }
01737           else (*tstream) << s;
01738         }
01739       }
01740 
01741       (*tstream) << "end architecture;\n";
01742     }
01743   }
01744 
01745   // close file
01746   if(creatingLib) {
01747     ofile.close();
01748     delete tstream;
01749   }
01750 }
01751 // ---------------------------------------------------
01752 // Write the netlist as subcircuit to the text stream 'stream'.
01753 bool Schematic::createSubNetlist(QTextStream *stream, int& countInit,
01754                      QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts)
01755 {
01756 //  int Collect_count = Collect.count();   // position for this subcircuit
01757 
01758   // TODO: NodeSets have to be put into the subcircuit block.
01759   if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts))
01760     return false;
01761 
01762 /*  Example for TODO
01763       for(it = Collect.at(Collect_count); it != Collect.end(); )
01764       if((*it).left(4) == "use ") {  // output all subcircuit uses
01765         (*stream) << (*it);
01766         it = Collect.remove(it);
01767       }
01768       else it++;*/
01769 
01770   // Emit subcircuit components
01771   createSubNetlistPlain(stream, ErrText, NumPorts);
01772 
01773   Signals.clear();  // was filled in "giveNodeNames()"
01774   return true;
01775 }
01776 
01777 // ---------------------------------------------------
01778 // Determines the node names and writes subcircuits into netlist file.
01779 int Schematic::prepareNetlist(QTextStream& stream, QStringList& Collect,
01780                               QPlainTextEdit *ErrText)
01781 {
01782   if(showBias > 0) showBias = -1;  // do not show DC bias anymore
01783 
01784   isVerilog = false;
01785   isAnalog = true;
01786   bool isTruthTable = false;
01787   int allTypes = 0, NumPorts = 0;
01788 
01789   // Detect simulation domain (analog/digital) by looking at component types.
01790   for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01791     if(pc->isActive == COMP_IS_OPEN) continue;
01792     if(pc->Model.at(0) == '.') {
01793       if(pc->Model == ".Digi") {
01794         if(allTypes & isDigitalComponent) {
01795           ErrText->appendPlainText(
01796              QObject::tr("ERROR: Only one digital simulation allowed."));
01797           return -10;
01798         }
01799         if(pc->Props.getFirst()->Value != "TimeList")
01800           isTruthTable = true;
01801         if(pc->Props.getLast()->Value != "VHDL")
01802           isVerilog = true;
01803         allTypes |= isDigitalComponent;
01804         isAnalog = false;
01805       }
01806       else allTypes |= isAnalogComponent;
01807       if((allTypes & isComponent) == isComponent) {
01808         ErrText->appendPlainText(
01809            QObject::tr("ERROR: Analog and digital simulations cannot be mixed."));
01810         return -10;
01811       }
01812     }
01813     else if(pc->Model == "DigiSource") NumPorts++;
01814   }
01815 
01816   if((allTypes & isAnalogComponent) == 0) {
01817     if(allTypes == 0) {
01818       // If no simulation exists, assume analog simulation. There may
01819       // be a simulation within a SPICE file. Otherwise Qucsator will
01820       // output an error.
01821       isAnalog = true;
01822       allTypes |= isAnalogComponent;
01823       NumPorts = -1;
01824     }
01825     else {
01826       if(NumPorts < 1 && isTruthTable) {
01827         ErrText->appendPlainText(
01828            QObject::tr("ERROR: Digital simulation needs at least one digital source."));
01829         return -10;
01830       }
01831       if(!isTruthTable) NumPorts = 0;
01832     }
01833   }
01834   else {
01835     NumPorts = -1;
01836     isAnalog = true;
01837   }
01838 
01839   // first line is documentation
01840   if(allTypes & isAnalogComponent)
01841     stream << "#";
01842   else if (isVerilog)
01843     stream << "//";
01844   else
01845     stream << "--";
01846   stream << " Qucs " << PACKAGE_VERSION << "  " << DocName << "\n";
01847 
01848   // set timescale property for verilog schematics
01849   if (isVerilog) {
01850     stream << "\n`timescale 1ps/100fs\n";
01851   }
01852 
01853   int countInit = 0;  // counts the nodesets to give them unique names
01854   if(!giveNodeNames(&stream, countInit, Collect, ErrText, NumPorts))
01855     return -10;
01856 
01857   if(allTypes & isAnalogComponent)
01858     return NumPorts;
01859 
01860   if (!isVerilog) {
01861     stream << VHDL_LIBRARIES;
01862     stream << "entity TestBench is\n"
01863      << "end entity;\n"
01864      << "use work.all;\n";
01865   }
01866   return NumPorts;
01867 }
01868 
01869 // ---------------------------------------------------
01870 // Write the beginning of digital netlist to the text stream 'stream'.
01871 void Schematic::beginNetlistDigital(QTextStream& stream)
01872 {
01873   if (isVerilog) {
01874     stream << "module TestBench ();\n";
01875     QList<DigSignal> values = Signals.values();
01876     QList<DigSignal>::const_iterator it;
01877     for (it = values.constBegin(); it != values.constEnd(); ++it) {
01878       stream << "  wire " << (*it).Name << ";\n";
01879     }
01880     stream << "\n";
01881   } else {
01882     stream << "architecture Arch_TestBench of TestBench is\n";
01883     QList<DigSignal> values = Signals.values();
01884     QList<DigSignal>::const_iterator it;
01885     for (it = values.constBegin(); it != values.constEnd(); ++it) {
01886       stream << "  signal " << (*it).Name << " : "
01887        << ((*it).Type.isEmpty() ?
01888      VHDL_SIGNAL_TYPE : (*it).Type) << ";\n";
01889     }
01890     stream << "begin\n";
01891   }
01892 
01893   if(Signals.find("gnd") != Signals.end()) {
01894     if (isVerilog) {
01895       stream << "  assign gnd = 0;\n";
01896     } else {
01897       stream << "  gnd <= '0';\n";  // should appear only once
01898     }
01899   }
01900 }
01901 
01902 // ---------------------------------------------------
01903 // Write the end of digital netlist to the text stream 'stream'.
01904 void Schematic::endNetlistDigital(QTextStream& stream)
01905 {
01906   if (isVerilog) {
01907   } else {
01908     stream << "end architecture;\n";
01909   }
01910 }
01911 
01912 // ---------------------------------------------------
01913 // write all components with node names into the netlist file
01914 QString Schematic::createNetlist(QTextStream& stream, int NumPorts)
01915 {
01916   if(!isAnalog) {
01917     beginNetlistDigital(stream);
01918   }
01919 
01920   Signals.clear();  // was filled in "giveNodeNames()"
01921   FileList.clear();
01922 
01923   QString s, Time;
01924   for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
01925     if(isAnalog) {
01926       s = pc->getNetlist();
01927     }
01928     else {
01929       if(pc->Model == ".Digi" && pc->isActive) {  // simulation component ?
01930         if(NumPorts > 0) { // truth table simulation ?
01931     if (isVerilog)
01932       Time = QString::number((1 << NumPorts));
01933     else
01934       Time = QString::number((1 << NumPorts) - 1) + " ns";
01935         } else {
01936           Time = pc->Props.at(1)->Value;
01937     if (isVerilog) {
01938       if(!misc::Verilog_Time(Time, pc->Name)) return Time;
01939     } else {
01940       if(!misc::VHDL_Time(Time, pc->Name)) return Time;  // wrong time format
01941     }
01942         }
01943       }
01944       if (isVerilog) {
01945   s = pc->get_Verilog_Code(NumPorts);
01946       } else {
01947   s = pc->get_VHDL_Code(NumPorts);
01948       }
01949       if (s.length()>0 && s.at(0) == '\xA7'){
01950           return s; // return error
01951       }
01952     }
01953     stream << s;
01954   }
01955 
01956   if(!isAnalog) {
01957     endNetlistDigital(stream);
01958   }
01959 
01960   return Time;
01961 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines