Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/components/subcircuit.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                subcircuit.cpp
00003                               ----------------
00004     begin                : Sat Aug 23 2003
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 #include "subcircuit.h"
00019 #include "qucs.h"
00020 #include "schematic.h"
00021 #include "main.h"
00022 #include "misc.h"
00023 
00024 #include <QTextStream>
00025 #include <QFileInfo>
00026 #include <QMutex>
00027 
00028 #include <limits.h>
00029 
00030 
00031 
00032 Subcircuit::Subcircuit()
00033 {
00034   Type = isComponent;   // both analog and digital
00035   Description = QObject::tr("subcircuit");
00036 
00037   Props.append(new Property("File", "", false,
00038     QObject::tr("name of qucs schematic file")));
00039 
00040   Model = "Sub";
00041   Name  = "SUB";
00042 
00043   // Do NOT call createSymbol() here. But create port to let it rotate.
00044   Ports.append(new Port(0, 0, false));
00045 }
00046 
00047 // ---------------------------------------------------------------------
00048 Component* Subcircuit::newOne()
00049 {
00050   Subcircuit *p = new Subcircuit();
00051   p->Props.getFirst()->Value = Props.getFirst()->Value;
00052   p->recreate(0);
00053   return p;
00054 }
00055 
00056 // -------------------------------------------------------
00057 Element* Subcircuit::info(QString& Name, char* &BitmapFile, bool getNewOne)
00058 {
00059   Name = QObject::tr("Subcircuit");
00060   BitmapFile = (char *) "subcircuit";
00061 
00062   if(getNewOne) {
00063     Subcircuit *p = new Subcircuit();
00064     p->recreate(0);   // createSymbol() is NOT called in constructor !!!
00065     return p;
00066   }
00067   return 0;
00068 }
00069 
00070 // ---------------------------------------------------------------------
00071 // Makes the schematic symbol subcircuit with the correct number
00072 // of ports.
00073 void Subcircuit::createSymbol()
00074 {
00075   int No;
00076   QString FileName(Props.getFirst()->Value);
00077   FileName = getSubcircuitFile();
00078 
00079   tx = INT_MIN;
00080   ty = INT_MIN;
00081   if(loadSymbol(FileName) > 0) {  // try to load subcircuit symbol
00082     if(tx == INT_MIN)  tx = x1+4;
00083     if(ty == INT_MIN)  ty = y2+4;
00084     // remove unused ports
00085     QMutableListIterator<Port *> ip(Ports);
00086     Port *pp;
00087     while (ip.hasNext()) {
00088       pp = ip.next();
00089       if(!pp->avail) {
00090           pp = ip.peekNext();
00091           ip.remove();
00092       }
00093     }
00094   }
00095   else {
00096     No = Schematic::testFile(FileName);
00097     if(No < 0)  No = 0;
00098 
00099     Ports.clear();
00100     remakeSymbol(No);  // no symbol was found -> create standard symbol
00101   }
00102 }
00103 
00104 // ---------------------------------------------------------------------
00105 void Subcircuit::remakeSymbol(int No)
00106 {
00107   int h = 30*((No-1)/2) + 15;
00108   Lines.append(new Line(-15, -h, 15, -h,QPen(Qt::darkBlue,2)));
00109   Lines.append(new Line( 15, -h, 15,  h,QPen(Qt::darkBlue,2)));
00110   Lines.append(new Line(-15,  h, 15,  h,QPen(Qt::darkBlue,2)));
00111   Lines.append(new Line(-15, -h,-15,  h,QPen(Qt::darkBlue,2)));
00112   Texts.append(new Text(-10, -6,"sub"));
00113 
00114   int i=0, y = 15-h;
00115   while(i<No) {
00116     i++;
00117     Lines.append(new Line(-30,  y,-15,  y,QPen(Qt::darkBlue,2)));
00118     Ports.append(new Port(-30,  y));
00119     Texts.append(new Text(-25,y-14,QString::number(i)));
00120 
00121     if(i == No) break;
00122     i++;
00123     Lines.append(new Line( 15,  y, 30,  y,QPen(Qt::darkBlue,2)));
00124     Ports.append(new Port( 30,  y));
00125     Texts.append(new Text( 19,y-14,QString::number(i)));
00126     y += 60;
00127   }
00128 
00129   x1 = -30; y1 = -h-2;
00130   x2 =  30; y2 =  h+2;
00131   tx = x1+4;
00132   ty = y2+4;
00133 }
00134 
00135 // ---------------------------------------------------------------------
00136 // Loads the symbol for the subcircuit from the schematic file and
00137 // returns the number of painting elements.
00138 int Subcircuit::loadSymbol(const QString& DocName)
00139 {
00140   QFile file(DocName);
00141   if(!file.open(QIODevice::ReadOnly))
00142     return -1;
00143 
00144   QString Line;
00145   // *****************************************************************
00146   // To strongly speed up the file read operation the whole file is
00147   // read into the memory in one piece.
00148   QTextStream ReadWhole(&file);
00149   QString FileString = ReadWhole.read();
00150   file.close();
00151   QTextStream stream(&FileString, QIODevice::ReadOnly);
00152 
00153 
00154   // read header **************************
00155   do {
00156     if(stream.atEnd()) return -2;
00157     Line = stream.readLine();
00158     Line = Line.trimmed();
00159   } while(Line.isEmpty());
00160 
00161   if(Line.left(16) != "<Qucs Schematic ")  // wrong file type ?
00162     return -3;
00163 
00164   Line = Line.mid(16, Line.length()-17);
00165   if(!misc::checkVersion(Line)) // wrong version number ?
00166     return -4;
00167 
00168   // read content *************************
00169   while(!stream.atEnd()) {
00170     Line = stream.readLine();
00171     if(Line == "<Symbol>") break;
00172   }
00173 
00174   x1 = y1 = INT_MAX;
00175   x2 = y2 = INT_MIN;
00176 
00177   int z=0, Result;
00178   while(!stream.atEnd()) {
00179     Line = stream.readLine();
00180     if(Line == "</Symbol>") {
00181       x1 -= 4;   // enlarge component boundings a little
00182       x2 += 4;
00183       y1 -= 4;
00184       y2 += 4;
00185       return z;      // return number of ports
00186     }
00187 
00188     Line = Line.trimmed();
00189     if(Line.at(0) != '<') return -5;
00190     if(Line.at(Line.length()-1) != '>') return -6;
00191     Line = Line.mid(1, Line.length()-2); // cut off start and end character
00192     Result = analyseLine(Line, 1);
00193     if(Result < 0) return -7;   // line format error
00194     z += Result;
00195   }
00196 
00197   return -8;   // field not closed
00198 }
00199 
00200 // -------------------------------------------------------
00201 QString Subcircuit::netlist()
00202 {
00203   QString s = Model+":"+Name;
00204 
00205   // output all node names
00206   foreach(Port *p1, Ports)
00207     s += " "+p1->Connection->Name;   // node names
00208 
00209   // type for subcircuit
00210   QString f = misc::properFileName(Props.first()->Value);
00211   s += " Type=\""+misc::properName(f)+"\"";
00212 
00213   // output all user defined properties
00214   for(Property *pp = Props.next(); pp != 0; pp = Props.next())
00215     s += " "+pp->Name+"=\""+pp->Value+"\"";
00216   return s + '\n';
00217 }
00218 
00219 // -------------------------------------------------------
00220 QString Subcircuit::vhdlCode(int)
00221 {
00222   QString f = misc::properFileName(Props.first()->Value);
00223   QString s = "  " + Name + ": entity Sub_" + misc::properName(f);
00224 
00225   // output all user defined properties
00226   Property *pr = Props.next();
00227   if (pr) {
00228     s += " generic map (";
00229     s += pr->Value;
00230     for(pr = Props.next(); pr != 0; pr = Props.next())
00231       s += ", " + pr->Value;
00232     s += ")";
00233   }
00234 
00235   // output all node names
00236   s += " port map (";
00237   QListIterator<Port *> iport(Ports);
00238   Port *pp = iport.next();
00239   if(pp)
00240     s += pp->Connection->Name;
00241   while (iport.hasNext()) {
00242     pp = iport.next();
00243     s += ", "+pp->Connection->Name;   // node names
00244   }
00245 
00246   s += ");\n";
00247   return s;
00248 }
00249 
00250 // -------------------------------------------------------
00251 QString Subcircuit::verilogCode(int)
00252 {
00253   QString f = misc::properFileName(Props.first()->Value);
00254   QString s = "  Sub_" + misc::properName(f);
00255 
00256   // output all user defined properties
00257   Property *pr = Props.next();
00258   if (pr) {
00259     s += " #(";
00260     s += misc::Verilog_Param(pr->Value);
00261     for(pr = Props.next(); pr != 0; pr = Props.next())
00262       s += ", " + misc::Verilog_Param(pr->Value);
00263     s += ")";
00264   }
00265 
00266   // output all node names
00267   s +=  " " + Name + " (";
00268   QListIterator<Port *> iport(Ports);
00269   Port *pp = iport.next();
00270   if(pp)
00271     s += pp->Connection->Name;
00272   while (iport.hasNext()) {
00273     pp = iport.next();
00274     s += ", "+pp->Connection->Name;   // node names
00275   }
00276 
00277   s += ");\n";
00278   return s;
00279 }
00280 
00281 // -------------------------------------------------------
00282 QString Subcircuit::getSubcircuitFile()
00283 {
00284   // construct full filename
00285   QString FileName = Props.getFirst()->Value;
00286 
00287   if (FileName.isEmpty())
00288   {
00289       return misc::properAbsFileName(FileName);
00290   }
00291 
00292   QFileInfo FileInfo(FileName);
00293 
00294   if (FileInfo.exists())
00295   {
00296       // the file must be an absolute path to a schematic file
00297      return FileInfo.absoluteFilePath();
00298   }
00299   else
00300   {
00301     // get the complete base name (everything except the last '.'
00302     // and whatever follows
00303     QString baseName = FileInfo.completeBaseName();
00304 
00305     // if only a file name is supplied, first check if it is in the
00306     // same directory as the schematic file it is a part of
00307     if (FileInfo.fileName () == FileName)
00308     {
00309         // the file has no path information, just the file name
00310         if (containingSchematic)
00311         {
00312             // check if a file of the same name is in the same directory
00313             // as the schematic file, if we have a pointer to it, in
00314             // which case we use this one
00315             QFileInfo schematicFileInfo = containingSchematic->getFileInfo ();
00316             QFileInfo localFIleInfo (schematicFileInfo.canonicalPath () + "/" + baseName + ".sch");
00317             if (localFIleInfo.exists ())
00318             {
00319                 // return the subcircuit saved in the same directory
00320                 // as the schematic file
00321                 return localFIleInfo.absoluteFilePath();
00322             }
00323         }
00324     }
00325 
00326     // look up the hash table for the schematic file as
00327     // it does not seem to be an absolute path, this will also
00328     // search the home directory which is always hashed
00329     QMutex mutex;
00330     mutex.lock();
00331     QString hashsearchresult = "";
00332     // check if GUI is running and there is something in the search path lookup
00333     if ( (QucsMain != 0) && !QucsMain->schNameHash.isEmpty() )
00334       hashsearchresult = QucsMain->schNameHash.value(baseName);
00335     mutex.unlock();
00336 
00337     if (hashsearchresult.isEmpty())
00338     {
00339         // the schematic was not found in the hash table, return
00340         // what would always have been returned in this case
00341         return misc::properAbsFileName(FileName);
00342     }
00343     else
00344     {
00345         // we found an entry in the hash table, check it actually still exists
00346         FileInfo.setFile(hashsearchresult);
00347 
00348         if (FileInfo.exists())
00349         {
00350             // it does exist so return the absolute file path
00351             return FileInfo.absoluteFilePath();
00352         }
00353         else
00354         {
00355             // the schematic file does not actually exist, return
00356             // what would always have been returned in this case
00357             return misc::properAbsFileName(FileName);
00358         }
00359     }
00360 
00361   }
00362 
00363 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines