Qucs-GUI
0.0.19
|
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 }