Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
schematic_file.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  schematic_file.cpp
3  --------------------
4  begin : Sat Mar 27 2004
5  copyright : (C) 2003 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <QtGui>
22 #include <QMessageBox>
23 #include <QDir>
24 #include <QStringList>
25 #include <QRegExp>
26 #include <Q3TextEdit>
27 #include <QTextEdit>
28 #include <Q3PtrList>
29 //Added by qt3to4:
30 #include <QTextStream>
31 #include <Q3ValueList>
32 
33 #include "main.h"
34 #include "node.h"
35 #include "schematic.h"
36 #include "diagrams/diagrams.h"
37 #include "paintings/paintings.h"
38 #include "components/spicefile.h"
39 #include "components/vhdlfile.h"
40 #include "components/verilogfile.h"
41 #include "components/libcomp.h"
42 #include "module.h"
43 
44 
45 // Here the subcircuits, SPICE components etc are collected. It must be
46 // global to also work within the subcircuits.
48 
49 
50 // -------------------------------------------------------------
51 // Creates a Qucs file format (without document properties) in the returning
52 // string. This is used to copy the selected elements into the clipboard.
54 {
55  int z=0; // counts selected elements
56  Wire *pw;
57  Diagram *pd;
58  Painting *pp;
59  Component *pc;
60 
61  QString s("<Qucs Schematic " PACKAGE_VERSION ">\n");
62 
63  // Build element document.
64  s += "<Components>\n";
65  for(pc = Components->first(); pc != 0; pc = Components->next())
66  if(pc->isSelected) {
67  s += pc->save()+"\n"; z++; }
68  s += "</Components>\n";
69 
70  s += "<Wires>\n";
71  for(pw = Wires->first(); pw != 0; pw = Wires->next())
72  if(pw->isSelected) {
73  z++;
74  if(pw->Label) if(!pw->Label->isSelected) {
75  s += pw->save().section('"', 0, 0)+"\"\" 0 0 0>\n";
76  continue;
77  }
78  s += pw->save()+"\n";
79  }
80  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
81  if(pn->Label) if(pn->Label->isSelected) {
82  s += pn->Label->save()+"\n"; z++; }
83  s += "</Wires>\n";
84 
85  s += "<Diagrams>\n";
86  for(pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
87  if(pd->isSelected) {
88  s += pd->save()+"\n"; z++; }
89  s += "</Diagrams>\n";
90 
91  s += "<Paintings>\n";
92  for(pp = Paintings->first(); pp != 0; pp = Paintings->next())
93  if(pp->isSelected)
94  if(pp->Name.at(0) != '.') { // subcircuit specific -> do not copy
95  s += "<"+pp->save()+">\n"; z++; }
96  s += "</Paintings>\n";
97 
98  if(z == 0) return ""; // return empty if no selection
99 
100  return s;
101 }
102 
103 // -------------------------------------------------------------
104 // Only read fields without loading them.
105 bool Schematic::loadIntoNothing(QTextStream *stream)
106 {
107  QString Line, cstr;
108  while(!stream->atEnd()) {
109  Line = stream->readLine();
110  if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
111  }
112 
113  QMessageBox::critical(0, QObject::tr("Error"),
114  QObject::tr("Format Error:\n'Painting' field is not closed!"));
115  return false;
116 }
117 
118 // -------------------------------------------------------------
119 // Paste from clipboard.
120 bool Schematic::pasteFromClipboard(QTextStream *stream, Q3PtrList<Element> *pe)
121 {
122  QString Line;
123 
124  Line = stream->readLine();
125  if(Line.left(16) != "<Qucs Schematic ") // wrong file type ?
126  return false;
127 
128  QString s = PACKAGE_VERSION;
129  Line = Line.mid(16, Line.length()-17);
130  if(Line != s) { // wrong version number ?
131  QMessageBox::critical(0, QObject::tr("Error"),
132  QObject::tr("Wrong document version: ")+Line);
133  return false;
134  }
135 
136  // read content in symbol edit mode *************************
137  if(symbolMode) {
138  while(!stream->atEnd()) {
139  Line = stream->readLine();
140  if(Line == "<Components>") {
141  if(!loadIntoNothing(stream)) return false; }
142  else
143  if(Line == "<Wires>") {
144  if(!loadIntoNothing(stream)) return false; }
145  else
146  if(Line == "<Diagrams>") {
147  if(!loadIntoNothing(stream)) return false; }
148  else
149  if(Line == "<Paintings>") {
150  if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; }
151  else {
152  QMessageBox::critical(0, QObject::tr("Error"),
153  QObject::tr("Clipboard Format Error:\nUnknown field!"));
154  return false;
155  }
156  }
157 
158  return true;
159  }
160 
161  // read content in schematic edit mode *************************
162  while(!stream->atEnd()) {
163  Line = stream->readLine();
164  if(Line == "<Components>") {
165  if(!loadComponents(stream, (Q3PtrList<Component>*)pe)) return false; }
166  else
167  if(Line == "<Wires>") {
168  if(!loadWires(stream, pe)) return false; }
169  else
170  if(Line == "<Diagrams>") {
171  if(!loadDiagrams(stream, (Q3PtrList<Diagram>*)pe)) return false; }
172  else
173  if(Line == "<Paintings>") {
174  if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; }
175  else {
176  QMessageBox::critical(0, QObject::tr("Error"),
177  QObject::tr("Clipboard Format Error:\nUnknown field!"));
178  return false;
179  }
180  }
181 
182  return true;
183 }
184 
185 // -------------------------------------------------------------
187 {
188  QFileInfo info (DocName);
189  QString cppfile = info.dirPath () + QDir::separator() + DataSet;
190  QFile file (cppfile);
191 
192  if (!file.open (QIODevice::WriteOnly)) {
193  QMessageBox::critical (0, QObject::tr("Error"),
194  QObject::tr("Cannot save C++ file \"%1\"!").arg(cppfile));
195  return -1;
196  }
197 
198  QTextStream stream (&file);
199 
200  // automatically compute boundings of drawing
201  int xmin = INT_MAX;
202  int ymin = INT_MAX;
203  int xmax = INT_MIN;
204  int ymax = INT_MIN;
205  int x1, y1, x2, y2;
206  int maxNum = 0;
207  Painting * pp;
208 
209  stream << " // symbol drawing code\n";
210  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
211  if (pp->Name == ".ID ") continue;
212  if (pp->Name == ".PortSym ") {
213  if (((PortSymbol*)pp)->numberStr.toInt() > maxNum)
214  maxNum = ((PortSymbol*)pp)->numberStr.toInt();
215  x1 = ((PortSymbol*)pp)->cx;
216  y1 = ((PortSymbol*)pp)->cy;
217  if (x1 < xmin) xmin = x1;
218  if (x1 > xmax) xmax = x1;
219  if (y1 < ymin) ymin = y1;
220  if (y1 > ymax) ymax = y1;
221  continue;
222  }
223  pp->Bounding (x1, y1, x2, y2);
224  if (x1 < xmin) xmin = x1;
225  if (x2 > xmax) xmax = x2;
226  if (y1 < ymin) ymin = y1;
227  if (y2 > ymax) ymax = y2;
228  stream << " " << pp->saveCpp () << "\n";
229  }
230 
231  stream << "\n // terminal definitions\n";
232  for (int i = 1; i <= maxNum; i++) {
233  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
234  if (pp->Name == ".PortSym ")
235  if (((PortSymbol*)pp)->numberStr.toInt() == i)
236  stream << " " << pp->saveCpp () << "\n";
237  }
238  }
239 
240  stream << "\n // symbol boundings\n"
241  << " x1 = " << xmin << "; " << " y1 = " << ymin << ";\n"
242  << " x2 = " << xmax << "; " << " y2 = " << ymax << ";\n";
243 
244  stream << "\n // property text position\n";
245  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ())
246  if (pp->Name == ".ID ")
247  stream << " " << pp->saveCpp () << "\n";
248 
249  file.close ();
250  return 0;
251 }
252 
253 // save symbol paintings in JSON format
255 {
256  QFileInfo info (DocName);
257  QString jsonfile = info.dirPath () + QDir::separator()
258  + info.baseName() + "_sym.json";
259 
260  qDebug() << "saveSymbolJson for " << jsonfile;
261 
262  QFile file (jsonfile);
263 
264  if (!file.open (QIODevice::WriteOnly)) {
265  QMessageBox::critical (0, QObject::tr("Error"),
266  QObject::tr("Cannot save JSON symbol file \"%1\"!").arg(jsonfile));
267  return -1;
268  }
269 
270  QTextStream stream (&file);
271 
272  // automatically compute boundings of drawing
273  int xmin = INT_MAX;
274  int ymin = INT_MAX;
275  int xmax = INT_MIN;
276  int ymax = INT_MIN;
277  int x1, y1, x2, y2;
278  int maxNum = 0;
279  Painting * pp;
280 
281  stream << "{\n";
282 
283  stream << "\"paintings\" : [\n";
284 
285  // symbol drawing code"
286  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
287  if (pp->Name == ".ID ") continue;
288  if (pp->Name == ".PortSym ") {
289  if (((PortSymbol*)pp)->numberStr.toInt() > maxNum)
290  maxNum = ((PortSymbol*)pp)->numberStr.toInt();
291  x1 = ((PortSymbol*)pp)->cx;
292  y1 = ((PortSymbol*)pp)->cy;
293  if (x1 < xmin) xmin = x1;
294  if (x1 > xmax) xmax = x1;
295  if (y1 < ymin) ymin = y1;
296  if (y1 > ymax) ymax = y1;
297  continue;
298  }
299  pp->Bounding (x1, y1, x2, y2);
300  if (x1 < xmin) xmin = x1;
301  if (x2 > xmax) xmax = x2;
302  if (y1 < ymin) ymin = y1;
303  if (y2 > ymax) ymax = y2;
304  stream << " " << pp->saveJSON() << "\n";
305  }
306 
307  // terminal definitions
308  //stream << "terminal \n";
309  for (int i = 1; i <= maxNum; i++) {
310  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) {
311  if (pp->Name == ".PortSym ")
312  if (((PortSymbol*)pp)->numberStr.toInt() == i)
313  stream << " " << pp->saveJSON () << "\n";
314  }
315  }
316 
317  stream << "],\n"; //end of paintings JSON array
318 
319  // symbol boundings
320  stream
321  << " \"x1\" : " << xmin << ",\n" << " \"y1\" : " << ymin << ",\n"
322  << " \"x2\" : " << xmax << ",\n" << " \"y2\" : " << ymax << ",\n";
323 
324  // property text position
325  for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ())
326  if (pp->Name == ".ID ")
327  stream << " " << pp->saveJSON () << "\n";
328 
329  stream << "}\n";
330 
331  file.close ();
332  return 0;
333 
334 
335 }
336 
337 // -------------------------------------------------------------
338 // Returns the number of subcircuit ports.
340 {
341  QFile file(DocName);
342  if(!file.open(QIODevice::WriteOnly)) {
343  QMessageBox::critical(0, QObject::tr("Error"),
344  QObject::tr("Cannot save document!"));
345  return -1;
346  }
347 
348  QTextStream stream(&file);
349 
350  stream << "<Qucs Schematic " << PACKAGE_VERSION << ">\n";
351 
352  stream << "<Properties>\n";
353  if(symbolMode) {
354  stream << " <View=" << tmpViewX1<<","<<tmpViewY1<<","
355  << tmpViewX2<<","<<tmpViewY2<< ",";
356  stream <<tmpScale<<","<<tmpPosX<<","<<tmpPosY << ">\n";
357  }
358  else {
359  stream << " <View=" << ViewX1<<","<<ViewY1<<","
360  << ViewX2<<","<<ViewY2<< ",";
361  stream << Scale <<","<<contentsX()<<","<<contentsY() << ">\n";
362  }
363  stream << " <Grid=" << GridX<<","<<GridY<<","
364  << GridOn << ">\n";
365  stream << " <DataSet=" << DataSet << ">\n";
366  stream << " <DataDisplay=" << DataDisplay << ">\n";
367  stream << " <OpenDisplay=" << SimOpenDpl << ">\n";
368  stream << " <Script=" << Script << ">\n";
369  stream << " <RunScript=" << SimRunScript << ">\n";
370  stream << " <showFrame=" << showFrame << ">\n";
371 
372  QString t;
374  stream << " <FrameText0=" << t << ">\n";
376  stream << " <FrameText1=" << t << ">\n";
378  stream << " <FrameText2=" << t << ">\n";
380  stream << " <FrameText3=" << t << ">\n";
381  stream << "</Properties>\n";
382 
383  Painting *pp;
384  stream << "<Symbol>\n"; // save all paintings for symbol
385  for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next())
386  stream << " <" << pp->save() << ">\n";
387  stream << "</Symbol>\n";
388 
389  stream << "<Components>\n"; // save all components
390  for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next())
391  stream << " " << pc->save() << "\n";
392  stream << "</Components>\n";
393 
394  stream << "<Wires>\n"; // save all wires
395  for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next())
396  stream << " " << pw->save() << "\n";
397 
398  // save all labeled nodes as wires
399  for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
400  if(pn->Label) stream << " " << pn->Label->save() << "\n";
401  stream << "</Wires>\n";
402 
403  stream << "<Diagrams>\n"; // save all diagrams
404  for(Diagram *pd = DocDiags.first(); pd != 0; pd = DocDiags.next())
405  stream << " " << pd->save() << "\n";
406  stream << "</Diagrams>\n";
407 
408  stream << "<Paintings>\n"; // save all paintings
409  for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next())
410  stream << " <" << pp->save() << ">\n";
411  stream << "</Paintings>\n";
412 
413  file.close();
414 
415  // additionally save symbol C++ code if in a symbol drawing and the
416  // associated file is a Verilog-A file
417  if (fileSuffix () == "sym") {
418  if (fileSuffix (DataDisplay) == "va") {
419  saveSymbolCpp ();
420  saveSymbolJSON ();
421 
422  // TODO slit this into another method, or merge into saveSymbolJSON
423  // handle errors in separate
424  qDebug() << " -> Run adms for symbol";
425 
426  QString vaFile;
427 
428 // QDir prefix = QDir(QucsSettings.BinDir);
429 
430  QDir include = QDir(QucsSettings.BinDir+"../include/qucs-core");
431 
432  //pick admsXml from settings
433  QString admsXml = QucsSettings.AdmsXmlBinDir.canonicalPath();
434 
435 #ifdef __MINGW32__
436  admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml.exe");
437 #else
438  admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml");
439 #endif
440 
441  QString workDir = QucsSettings.QucsWorkDir.absolutePath();
442 
443  qDebug() << "App path : " << qApp->applicationDirPath();
444  qDebug() << "workdir" << workDir;
445  qDebug() << "homedir" << QucsSettings.QucsHomeDir.absolutePath();
446 
447  vaFile = QucsSettings.QucsWorkDir.filePath(fileBase()+".va");
448 
449  QStringList Arguments;
450  Arguments << QDir::toNativeSeparators(vaFile)
451  << "-I" << QDir::toNativeSeparators(include.absolutePath())
452  << "-e" << QDir::toNativeSeparators(include.absFilePath("qucsMODULEguiJSONsymbol.xml"))
453  << "-A" << "dyload";
454 
455 // QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
456 // env.insert("PATH", env.value("PATH") );
457 
458  QFile file(admsXml);
459  if ( !file.exists() ){
460  QMessageBox::critical(this, tr("Error"),
461  tr("Program admsXml not found: %1\n\n"
462  "Set the admsXml location on the application settings.").arg(admsXml));
463  return -1;
464  }
465 
466  qDebug() << "Command: " << admsXml << Arguments.join(" ");
467 
468  // need to cd into project to run admsXml?
469  QDir::setCurrent(workDir);
470 
471  QProcess builder;
472  builder.setProcessChannelMode(QProcess::MergedChannels);
473 
474  builder.start(admsXml, Arguments);
475 
476 
477  // how to capture [warning]? need to modify admsXml?
478  // TODO put stdout, stderr into a dock window, not messagebox
479  if (!builder.waitForFinished()) {
480  QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" "));
481  cmdString = cmdString + builder.errorString();
482  QMessageBox::critical(this, tr("Error"), cmdString);
483  }
484  else {
485  QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" "));
486  cmdString = cmdString + builder.readAll();
487  QMessageBox::information(this, tr("Status"), cmdString);
488  }
489 
490  // Append _sym.json into _props.json, save into _symbol.json
491  QFile f1(QucsSettings.QucsWorkDir.filePath(fileBase()+"_props.json"));
492  QFile f2(QucsSettings.QucsWorkDir.filePath(fileBase()+"_sym.json"));
493  f1.open(QIODevice::ReadOnly | QIODevice::Text);
494  f2.open(QIODevice::ReadOnly | QIODevice::Text);
495 
496  QString dat1 = QString(f1.readAll());
497  QString dat2 = QString(f2.readAll());
498  QString finalJSON = dat1.append(dat2);
499 
500  // remove joining point
501  finalJSON = finalJSON.replace("}{", "");
502 
503  QFile f3(QucsSettings.QucsWorkDir.filePath(fileBase()+"_symbol.json"));
504  f3.open(QIODevice::WriteOnly | QIODevice::Text);
505  QTextStream out(&f3);
506  out << finalJSON;
507 
508  f1.close();
509  f2.close();
510  f3.close();
511 
512  // TODO choose icon, default to something or provided png
513 
514  } // if DataDisplay va
515  } // if suffix .sym
516 
517  return 0;
518 }
519 
520 // -------------------------------------------------------------
521 bool Schematic::loadProperties(QTextStream *stream)
522 {
523  bool ok = true;
524  QString Line, cstr, nstr;
525  while(!stream->atEnd()) {
526  Line = stream->readLine();
527  if(Line.at(0) == '<') if(Line.at(1) == '/') return true; // field end ?
528  Line = Line.stripWhiteSpace();
529  if(Line.isEmpty()) continue;
530 
531  if(Line.at(0) != '<') {
532  QMessageBox::critical(0, QObject::tr("Error"),
533  QObject::tr("Format Error:\nWrong property field limiter!"));
534  return false;
535  }
536  if(Line.at(Line.length()-1) != '>') {
537  QMessageBox::critical(0, QObject::tr("Error"),
538  QObject::tr("Format Error:\nWrong property field limiter!"));
539  return false;
540  }
541  Line = Line.mid(1, Line.length()-2); // cut off start and end character
542 
543  cstr = Line.section('=',0,0); // property type
544  nstr = Line.section('=',1,1); // property value
545  if(cstr == "View") {
546  ViewX1 = nstr.section(',',0,0).toInt(&ok); if(ok) {
547  ViewY1 = nstr.section(',',1,1).toInt(&ok); if(ok) {
548  ViewX2 = nstr.section(',',2,2).toInt(&ok); if(ok) {
549  ViewY2 = nstr.section(',',3,3).toInt(&ok); if(ok) {
550  Scale = nstr.section(',',4,4).toDouble(&ok); if(ok) {
551  tmpViewX1 = nstr.section(',',5,5).toInt(&ok); if(ok)
552  tmpViewY1 = nstr.section(',',6,6).toInt(&ok); }}}}} }
553  else if(cstr == "Grid") {
554  GridX = nstr.section(',',0,0).toInt(&ok); if(ok) {
555  GridY = nstr.section(',',1,1).toInt(&ok); if(ok) {
556  if(nstr.section(',',2,2).toInt(&ok) == 0) GridOn = false;
557  else GridOn = true; }} }
558  else if(cstr == "DataSet") DataSet = nstr;
559  else if(cstr == "DataDisplay") DataDisplay = nstr;
560  else if(cstr == "OpenDisplay")
561  if(nstr.toInt(&ok) == 0) SimOpenDpl = false;
562  else SimOpenDpl = true;
563  else if(cstr == "Script") Script = nstr;
564  else if(cstr == "RunScript")
565  if(nstr.toInt(&ok) == 0) SimRunScript = false;
566  else SimRunScript = true;
567  else if(cstr == "showFrame")
568  showFrame = nstr.at(0).latin1() - '0';
569  else if(cstr == "FrameText0") convert2Unicode(Frame_Text0 = nstr);
570  else if(cstr == "FrameText1") convert2Unicode(Frame_Text1 = nstr);
571  else if(cstr == "FrameText2") convert2Unicode(Frame_Text2 = nstr);
572  else if(cstr == "FrameText3") convert2Unicode(Frame_Text3 = nstr);
573  else {
574  QMessageBox::critical(0, QObject::tr("Error"),
575  QObject::tr("Format Error:\nUnknown property: ")+cstr);
576  return false;
577  }
578  if(!ok) {
579  QMessageBox::critical(0, QObject::tr("Error"),
580  QObject::tr("Format Error:\nNumber expected in property field!"));
581  return false;
582  }
583  }
584 
585  QMessageBox::critical(0, QObject::tr("Error"),
586  QObject::tr("Format Error:\n'Property' field is not closed!"));
587  return false;
588 }
589 
590 // ---------------------------------------------------
591 // Inserts a component without performing logic for wire optimization.
593 {
594  Node *pn;
595  int x, y;
596  // connect every node of component
597  for(Port *pp = c->Ports.first(); pp != 0; pp = c->Ports.next()) {
598  x = pp->x+c->cx;
599  y = pp->y+c->cy;
600 
601  // check if new node lies upon existing node
602  for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
603  if(pn->cx == x) if(pn->cy == y) {
604  if (!pn->DType.isEmpty()) {
605  pp->Type = pn->DType;
606  }
607  if (!pp->Type.isEmpty()) {
608  pn->DType = pp->Type;
609  }
610  break;
611  }
612 
613  if(pn == 0) { // create new node, if no existing one lies at this position
614  pn = new Node(x, y);
615  DocNodes.append(pn);
616  }
617  pn->Connections.append(c); // connect schematic node to component node
618  if (!pp->Type.isEmpty()) {
619  pn->DType = pp->Type;
620  }
621 
622  pp->Connection = pn; // connect component node to schematic node
623  }
624 
625  DocComps.append(c);
626 }
627 
628 // -------------------------------------------------------------
629 bool Schematic::loadComponents(QTextStream *stream, Q3PtrList<Component> *List)
630 {
631  QString Line, cstr;
632  Component *c;
633  while(!stream->atEnd()) {
634  Line = stream->readLine();
635  if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
636  Line = Line.stripWhiteSpace();
637  if(Line.isEmpty()) continue;
638 
640  c = getComponentFromName(Line, this);
641  if(!c) return false;
642 
643  if(List) { // "paste" ?
644  int z;
645  for(z=c->Name.length()-1; z>=0; z--) // cut off number of component name
646  if(!c->Name.at(z).isDigit()) break;
647  c->Name = c->Name.left(z+1);
648  List->append(c);
649  }
650  else simpleInsertComponent(c);
651  }
652 
653  QMessageBox::critical(0, QObject::tr("Error"),
654  QObject::tr("Format Error:\n'Component' field is not closed!"));
655  return false;
656 }
657 
658 // -------------------------------------------------------------
659 // Inserts a wire without performing logic for optimizing.
661 {
662  Node *pn;
663  // check if first wire node lies upon existing node
664  for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
665  if(pn->cx == pw->x1) if(pn->cy == pw->y1) break;
666 
667  if(!pn) { // create new node, if no existing one lies at this position
668  pn = new Node(pw->x1, pw->y1);
669  DocNodes.append(pn);
670  }
671 
672  if(pw->x1 == pw->x2) if(pw->y1 == pw->y2) {
673  pn->Label = pw->Label; // wire with length zero are just node labels
674  if (pn->Label) {
675  pn->Label->Type = isNodeLabel;
676  pn->Label->pOwner = pn;
677  }
678  delete pw; // delete wire because this is not a wire
679  return;
680  }
681  pn->Connections.append(pw); // connect schematic node to component node
682  pw->Port1 = pn;
683 
684  // check if second wire node lies upon existing node
685  for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
686  if(pn->cx == pw->x2) if(pn->cy == pw->y2) break;
687 
688  if(!pn) { // create new node, if no existing one lies at this position
689  pn = new Node(pw->x2, pw->y2);
690  DocNodes.append(pn);
691  }
692  pn->Connections.append(pw); // connect schematic node to component node
693  pw->Port2 = pn;
694 
695  DocWires.append(pw);
696 }
697 
698 // -------------------------------------------------------------
699 bool Schematic::loadWires(QTextStream *stream, Q3PtrList<Element> *List)
700 {
701  Wire *w;
702  QString Line;
703  while(!stream->atEnd()) {
704  Line = stream->readLine();
705  if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
706  Line = Line.stripWhiteSpace();
707  if(Line.isEmpty()) continue;
708 
709  // (Node*)4 = move all ports (later on)
710  w = new Wire(0,0,0,0, (Node*)4,(Node*)4);
711  if(!w->load(Line)) {
712  QMessageBox::critical(0, QObject::tr("Error"),
713  QObject::tr("Format Error:\nWrong 'wire' line format!"));
714  delete w;
715  return false;
716  }
717  if(List) {
718  if(w->x1 == w->x2) if(w->y1 == w->y2) if(w->Label) {
719  w->Label->Type = isMovingLabel;
720  List->append(w->Label);
721  delete w;
722  continue;
723  }
724  List->append(w);
725  if(w->Label) List->append(w->Label);
726  }
727  else simpleInsertWire(w);
728  }
729 
730  QMessageBox::critical(0, QObject::tr("Error"),
731  QObject::tr("Format Error:\n'Wire' field is not closed!"));
732  return false;
733 }
734 
735 // -------------------------------------------------------------
736 bool Schematic::loadDiagrams(QTextStream *stream, Q3PtrList<Diagram> *List)
737 {
738  Diagram *d;
739  QString Line, cstr;
740  while(!stream->atEnd()) {
741  Line = stream->readLine();
742  if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
743  Line = Line.stripWhiteSpace();
744  if(Line.isEmpty()) continue;
745 
746  cstr = Line.section(' ',0,0); // diagram type
747  if(cstr == "<Rect") d = new RectDiagram();
748  else if(cstr == "<Polar") d = new PolarDiagram();
749  else if(cstr == "<Tab") d = new TabDiagram();
750  else if(cstr == "<Smith") d = new SmithDiagram();
751  else if(cstr == "<ySmith") d = new SmithDiagram(0,0,false);
752  else if(cstr == "<PS") d = new PSDiagram();
753  else if(cstr == "<SP") d = new PSDiagram(0,0,false);
754  else if(cstr == "<Rect3D") d = new Rect3DDiagram();
755  else if(cstr == "<Curve") d = new CurveDiagram();
756  else if(cstr == "<Time") d = new TimingDiagram();
757  else if(cstr == "<Truth") d = new TruthDiagram();
758  else {
759  QMessageBox::critical(0, QObject::tr("Error"),
760  QObject::tr("Format Error:\nUnknown diagram!"));
761  return false;
762  }
763 
764  if(!d->load(Line, stream)) {
765  QMessageBox::critical(0, QObject::tr("Error"),
766  QObject::tr("Format Error:\nWrong 'diagram' line format!"));
767  delete d;
768  return false;
769  }
770  List->append(d);
771  }
772 
773  QMessageBox::critical(0, QObject::tr("Error"),
774  QObject::tr("Format Error:\n'Diagram' field is not closed!"));
775  return false;
776 }
777 
778 // -------------------------------------------------------------
779 bool Schematic::loadPaintings(QTextStream *stream, Q3PtrList<Painting> *List)
780 {
781  Painting *p=0;
782  QString Line, cstr;
783  while(!stream->atEnd()) {
784  Line = stream->readLine();
785  if(Line.at(0) == '<') if(Line.at(1) == '/') return true;
786 
787  Line = Line.stripWhiteSpace();
788  if(Line.isEmpty()) continue;
789  if( (Line.at(0) != '<') || (Line.at(Line.length()-1) != '>')) {
790  QMessageBox::critical(0, QObject::tr("Error"),
791  QObject::tr("Format Error:\nWrong 'painting' line delimiter!"));
792  return false;
793  }
794  Line = Line.mid(1, Line.length()-2); // cut off start and end character
795 
796  cstr = Line.section(' ',0,0); // painting type
797  if(cstr == "Line") p = new GraphicLine();
798  else if(cstr == "EArc") p = new EllipseArc();
799  else if(cstr == ".PortSym") p = new PortSymbol();
800  else if(cstr == ".ID") p = new ID_Text();
801  else if(cstr == "Text") p = new GraphicText();
802  else if(cstr == "Rectangle") p = new Rectangle();
803  else if(cstr == "Arrow") p = new Arrow();
804  else if(cstr == "Ellipse") p = new Ellipse();
805  else {
806  QMessageBox::critical(0, QObject::tr("Error"),
807  QObject::tr("Format Error:\nUnknown painting!"));
808  return false;
809  }
810 
811  if(!p->load(Line)) {
812  QMessageBox::critical(0, QObject::tr("Error"),
813  QObject::tr("Format Error:\nWrong 'painting' line format!"));
814  delete p;
815  return false;
816  }
817  List->append(p);
818  }
819 
820  QMessageBox::critical(0, QObject::tr("Error"),
821  QObject::tr("Format Error:\n'Painting' field is not closed!"));
822  return false;
823 }
824 
825 // -------------------------------------------------------------
827 {
828  QFile file(DocName);
829  if(!file.open(QIODevice::ReadOnly)) {
830  QMessageBox::critical(0, QObject::tr("Error"),
831  QObject::tr("Cannot load document: ")+DocName);
832  return false;
833  }
834 
835  QString Line;
836  QTextStream stream(&file);
837 
838  // read header **************************
839  do {
840  if(stream.atEnd()) {
841  file.close();
842  return true;
843  }
844 
845  Line = stream.readLine();
846  } while(Line.isEmpty());
847 
848  if(Line.left(16) != "<Qucs Schematic ") { // wrong file type ?
849  file.close();
850  QMessageBox::critical(0, QObject::tr("Error"),
851  QObject::tr("Wrong document type: ")+DocName);
852  return false;
853  }
854 
855  Line = Line.mid(16, Line.length()-17);
856  if(!checkVersion(Line)) { // wrong version number ?
857 
858  QMessageBox::StandardButton result;
859  result = QMessageBox::warning(0,
860  QObject::tr("Warning"),
861  QObject::tr("Wrong document version \n" +
862  DocName + "\n"
863  "Try to open it anyway?"),
864  QMessageBox::Yes|QMessageBox::No);
865 
866  if (result==QMessageBox::No) {
867  file.close();
868  return false;
869  }
870 
871  //QMessageBox::critical(0, QObject::tr("Error"),
872  // QObject::tr("Wrong document version: ")+Line);
873  }
874 
875  // read content *************************
876  while(!stream.atEnd()) {
877  Line = stream.readLine();
878  Line = Line.stripWhiteSpace();
879  if(Line.isEmpty()) continue;
880 
881  if(Line == "<Symbol>") {
882  if ((Schematic*)QucsMain != 0) // GUI running, load Symbols
883  if(!loadPaintings(&stream, &SymbolPaints)) {
884  file.close();
885  return false;
886  }
887  }
888  else
889  if(Line == "<Properties>") {
890  if(!loadProperties(&stream)) { file.close(); return false; } }
891  else
892  if(Line == "<Components>") {
893  if(!loadComponents(&stream)) { file.close(); return false; } }
894  else
895  if(Line == "<Wires>") {
896  if(!loadWires(&stream)) { file.close(); return false; } }
897  else
898  if ((Schematic*)QucsMain != 0) { // GUI running, load Diagrams, Paintings
899  if(Line == "<Diagrams>") {
900  if(!loadDiagrams(&stream, &DocDiags)) { file.close(); return false; } }
901  else
902  if(Line == "<Paintings>") {
903  if(!loadPaintings(&stream, &DocPaints)) { file.close(); return false; } }
904  else {
905  qDebug() << Line;
906  QMessageBox::critical(0, QObject::tr("Error"),
907  QObject::tr("File Format Error:\nUnknown field!"));
908  file.close();
909  return false;
910  }
911  } // Diagrams, Paintings
912  }
913 
914  file.close();
915  return true;
916 }
917 
918 // -------------------------------------------------------------
919 // Creates a Qucs file format (without document properties) in the returning
920 // string. This is used to save state for undo operation.
922 {
923  Wire *pw;
924  Diagram *pd;
925  Painting *pp;
926  Component *pc;
927 
928  // Build element document.
929  QString s = " \n";
930  s.replace(0,1,Op);
931  for(pc = DocComps.first(); pc != 0; pc = DocComps.next())
932  s += pc->save()+"\n";
933  s += "</>\n"; // short end flag
934 
935  for(pw = DocWires.first(); pw != 0; pw = DocWires.next())
936  s += pw->save()+"\n";
937  // save all labeled nodes as wires
938  for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next())
939  if(pn->Label) s += pn->Label->save()+"\n";
940  s += "</>\n";
941 
942  for(pd = DocDiags.first(); pd != 0; pd = DocDiags.next())
943  s += pd->save()+"\n";
944  s += "</>\n";
945 
946  for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next())
947  s += "<"+pp->save()+">\n";
948  s += "</>\n";
949 
950  return s;
951 }
952 
953 // -------------------------------------------------------------
954 // Same as "createUndoString(char Op)" but for symbol edit mode.
956 {
957  Painting *pp;
958 
959  // Build element document.
960  QString s = " \n";
961  s.replace(0,1,Op);
962  s += "</>\n"; // short end flag for components
963  s += "</>\n"; // short end flag for wires
964  s += "</>\n"; // short end flag for diagrams
965 
966  for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next())
967  s += "<"+pp->save()+">\n";
968  s += "</>\n";
969 
970  return s;
971 }
972 
973 // -------------------------------------------------------------
974 // Is quite similiar to "loadDocument()" but with less error checking.
975 // Used for "undo" function.
976 bool Schematic::rebuild(QString *s)
977 {
978  DocWires.clear(); // delete whole document
979  DocNodes.clear();
980  DocComps.clear();
981  DocDiags.clear();
982  DocPaints.clear();
983 
984  QString Line;
985  QTextStream stream(s, QIODevice::ReadOnly);
986  Line = stream.readLine(); // skip identity byte
987 
988  // read content *************************
989  if(!loadComponents(&stream)) return false;
990  if(!loadWires(&stream)) return false;
991  if(!loadDiagrams(&stream, &DocDiags)) return false;
992  if(!loadPaintings(&stream, &DocPaints)) return false;
993 
994  return true;
995 }
996 
997 // -------------------------------------------------------------
998 // Same as "rebuild(QString *s)" but for symbol edit mode.
999 bool Schematic::rebuildSymbol(QString *s)
1000 {
1001  SymbolPaints.clear(); // delete whole document
1002 
1003  QString Line;
1004  QTextStream stream(s, QIODevice::ReadOnly);
1005  Line = stream.readLine(); // skip identity byte
1006 
1007  // read content *************************
1008  Line = stream.readLine(); // skip components
1009  Line = stream.readLine(); // skip wires
1010  Line = stream.readLine(); // skip diagrams
1011  if(!loadPaintings(&stream, &SymbolPaints)) return false;
1012 
1013  return true;
1014 }
1015 
1016 
1017 // ***************************************************************
1018 // ***** *****
1019 // ***** Functions to create netlist *****
1020 // ***** *****
1021 // ***************************************************************
1022 
1023 void Schematic::createNodeSet(QStringList& Collect, int& countInit,
1024  Conductor *pw, Node *p1)
1025 {
1026  if(pw->Label)
1027  if(!pw->Label->initValue.isEmpty())
1028  Collect.append("NodeSet:NS" + QString::number(countInit++) + " " +
1029  p1->Name + " U=\"" + pw->Label->initValue + "\"");
1030 }
1031 
1032 // ---------------------------------------------------
1033 void Schematic::throughAllNodes(bool User, QStringList& Collect,
1034  int& countInit)
1035 {
1036  Node *pn;
1037  int z=0;
1038 
1039  for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
1040  if(pn->Name.isEmpty() == User) {
1041  continue; // already named ?
1042  }
1043  if(!User) {
1044  if(isAnalog)
1045  pn->Name = "_net";
1046  else
1047  pn->Name = "net_net"; // VHDL names must not begin with '_'
1048  pn->Name += QString::number(z++); // create numbered node name
1049  }
1050  else if(pn->State) {
1051  continue; // already worked on
1052  }
1053 
1054  if(isAnalog) createNodeSet(Collect, countInit, pn, pn);
1055 
1056  pn->State = 1;
1057  propagateNode(Collect, countInit, pn);
1058  }
1059 }
1060 
1061 // ---------------------------------------------------
1062 // Collects the signal names for digital simulations.
1064 {
1065  Node *pn;
1066 
1067  for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
1068  DigMap::Iterator it = Signals.find(pn->Name);
1069  if(it == Signals.end()) { // avoid redeclaration of signal
1070  Signals.insert(pn->Name, DigSignal(pn->Name, pn->DType));
1071  } else if (!pn->DType.isEmpty()) {
1072  it.data().Type = pn->DType;
1073  }
1074  }
1075 }
1076 
1077 // ---------------------------------------------------
1078 // Propagates the given node to connected component ports.
1079 void Schematic::propagateNode(QStringList& Collect,
1080  int& countInit, Node *pn)
1081 {
1082  bool setName=false;
1083  Q3PtrList<Node> Cons;
1084  Node *p2;
1085  Wire *pw;
1086  Element *pe;
1087 
1088  Cons.append(pn);
1089  for(p2 = Cons.first(); p2 != 0; p2 = Cons.next())
1090  for(pe = p2->Connections.first(); pe != 0; pe = p2->Connections.next())
1091  if(pe->Type == isWire) {
1092  pw = (Wire*)pe;
1093  if(p2 != pw->Port1) {
1094  if(pw->Port1->Name.isEmpty()) {
1095  pw->Port1->Name = pn->Name;
1096  pw->Port1->State = 1;
1097  Cons.append(pw->Port1);
1098  setName = true;
1099  }
1100  }
1101  else {
1102  if(pw->Port2->Name.isEmpty()) {
1103  pw->Port2->Name = pn->Name;
1104  pw->Port2->State = 1;
1105  Cons.append(pw->Port2);
1106  setName = true;
1107  }
1108  }
1109  if(setName) {
1110  Cons.findRef(p2); // back to current Connection
1111  if (isAnalog) createNodeSet(Collect, countInit, pw, pn);
1112  setName = false;
1113  }
1114  }
1115  Cons.clear();
1116 }
1117 
1118 #include <iostream>
1119 // ---------------------------------------------------
1120 // Goes through all schematic components and allows special component
1121 // handling, e.g. like subcircuit netlisting.
1122 bool Schematic::throughAllComps(QTextStream *stream, int& countInit,
1123  QStringList& Collect, QTextEdit *ErrText, int NumPorts)
1124 {
1125  bool r;
1126  QString s;
1127 
1128  // give the ground nodes the name "gnd", and insert subcircuits etc.
1129  Q3PtrListIterator<Component> it(DocComps);
1130  Component *pc;
1131  while((pc = it.current()) != 0) {
1132  ++it;
1133  if(pc->isActive != COMP_IS_ACTIVE) continue;
1134 
1135  // check analog/digital typed components
1136  if(isAnalog) {
1137  if((pc->Type & isAnalogComponent) == 0) {
1138  ErrText->insert(QObject::tr("ERROR: Component \"%1\" has no analog model.").arg(pc->Name));
1139  return false;
1140  }
1141  } else {
1142  if((pc->Type & isDigitalComponent) == 0) {
1143  ErrText->insert(QObject::tr("ERROR: Component \"%1\" has no digital model.").arg(pc->Name));
1144  return false;
1145  }
1146  }
1147 
1148  // handle ground symbol
1149  if(pc->Model == "GND") {
1150  pc->Ports.getFirst()->Connection->Name = "gnd";
1151  continue;
1152  }
1153 
1154  // handle subcircuits
1155  if(pc->Model == "Sub")
1156  {
1157  int i;
1158  // tell the subcircuit it belongs to this schematic
1159  pc->setSchematic (this);
1160  QString f = pc->getSubcircuitFile();
1161  SubMap::Iterator it = FileList.find(f);
1162  if(it != FileList.end())
1163  {
1164  if (!it.data().PortTypes.isEmpty())
1165  {
1166  i = 0;
1167  // apply in/out signal types of subcircuit
1168  for(Port *pp = pc->Ports.first(); pp; pp = pc->Ports.next(), i++)
1169  {
1170  pp->Type = it.data().PortTypes[i];
1171  pp->Connection->DType = pp->Type;
1172  }
1173  }
1174  continue; // insert each subcircuit just one time
1175  }
1176 
1177  // The subcircuit has not previously been added
1178  SubFile sub = SubFile("SCH", f);
1179  FileList.insert(f, sub);
1180 
1181 
1182  // load subcircuit schematic
1183  s = pc->Props.first()->Value;
1184  Schematic *d = new Schematic(0, pc->getSubcircuitFile());
1185  if(!d->loadDocument()) // load document if possible
1186  {
1187  delete d;
1188  ErrText->insert(QObject::tr("ERROR: Cannot load subcircuit \"%1\".").arg(s));
1189  return false;
1190  }
1191  d->DocName = s;
1192  d->isVerilog = isVerilog;
1193  d->isAnalog = isAnalog;
1194  d->creatingLib = creatingLib;
1195  r = d->createSubNetlist(stream, countInit, Collect, ErrText, NumPorts);
1196  if (r)
1197  {
1198  i = 0;
1199  // save in/out signal types of subcircuit
1200  for(Port *pp = pc->Ports.first(); pp; pp = pc->Ports.next(), i++)
1201  {
1202  //if(i>=d->PortTypes.count())break;
1203  pp->Type = d->PortTypes[i];
1204  pp->Connection->DType = pp->Type;
1205  }
1206  sub.PortTypes = d->PortTypes;
1207  FileList.replace(f, sub);
1208  }
1209  delete d;
1210  if(!r)
1211  {
1212  return false;
1213  }
1214  continue;
1215  } // if(pc->Model == "Sub")
1216 
1217  // handle library symbols
1218  if(pc->Model == "Lib") {
1219  if(creatingLib) {
1220  ErrText->insert(
1221  QObject::tr("WARNING: Skipping library component \"%1\".").
1222  arg(pc->Name));
1223  continue;
1224  }
1225  s = pc->getSubcircuitFile() + "/" + pc->Props.at(1)->Value;
1226  SubMap::Iterator it = FileList.find(s);
1227  if(it != FileList.end())
1228  continue; // insert each library subcircuit just one time
1229  FileList.insert(s, SubFile("LIB", s));
1230 
1231  if(isAnalog)
1232  r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 1);
1233  else {
1234  if(isVerilog)
1235  r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 4);
1236  else
1237  r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 2);
1238  }
1239  if(!r) {
1240  ErrText->insert(
1241  QObject::tr("ERROR: Cannot load library component \"%1\".").
1242  arg(pc->Name));
1243  return false;
1244  }
1245  continue;
1246  }
1247 
1248  // handle SPICE subcircuit components
1249  if(pc->Model == "SPICE") {
1250  s = pc->Props.first()->Value;
1251  // tell the spice component it belongs to this schematic
1252  pc->setSchematic (this);
1253  if(s.isEmpty()) {
1254  ErrText->insert(QObject::tr("ERROR: No file name in SPICE component \"%1\".").
1255  arg(pc->Name));
1256  return false;
1257  }
1258  QString f = pc->getSubcircuitFile();
1259  SubMap::Iterator it = FileList.find(f);
1260  if(it != FileList.end())
1261  continue; // insert each spice component just one time
1262  FileList.insert(f, SubFile("CIR", f));
1263 
1264  SpiceFile *sf = (SpiceFile*)pc;
1265  r = sf->createSubNetlist(stream);
1266  ErrText->insert(sf->getErrorText());
1267  if(!r) return false;
1268  continue;
1269  }
1270 
1271  // handle digital file subcircuits
1272  if(pc->Model == "VHDL" || pc->Model == "Verilog") {
1273  if(isVerilog && pc->Model == "VHDL")
1274  continue;
1275  if(!isVerilog && pc->Model == "Verilog")
1276  continue;
1277  s = pc->Props.getFirst()->Value;
1278  if(s.isEmpty()) {
1279  ErrText->insert(QObject::tr("ERROR: No file name in %1 component \"%2\".").
1280  arg(pc->Model).
1281  arg(pc->Name));
1282  return false;
1283  }
1284  QString f = pc->getSubcircuitFile();
1285  SubMap::Iterator it = FileList.find(f);
1286  if(it != FileList.end())
1287  continue; // insert each vhdl/verilog component just one time
1288  s = ((pc->Model == "VHDL") ? "VHD" : "VER");
1289  FileList.insert(f, SubFile(s, f));
1290 
1291  if(pc->Model == "VHDL") {
1292  VHDL_File *vf = (VHDL_File*)pc;
1293  r = vf->createSubNetlist(stream);
1294  ErrText->insert(vf->getErrorText());
1295  if(!r) return false;
1296  }
1297  if(pc->Model == "Verilog") {
1298  Verilog_File *vf = (Verilog_File*)pc;
1299  r = vf->createSubNetlist(stream);
1300  ErrText->insert(vf->getErrorText());
1301  if(!r) return false;
1302  }
1303  continue;
1304  }
1305  }
1306  return true;
1307 }
1308 
1309 // ---------------------------------------------------
1310 // Follows the wire lines in order to determine the node names for
1311 // each component. Output into "stream", NodeSets are collected in
1312 // "Collect" and counted with "countInit".
1313 bool Schematic::giveNodeNames(QTextStream *stream, int& countInit,
1314  QStringList& Collect, QTextEdit *ErrText, int NumPorts)
1315 {
1316  // delete the node names
1317  for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) {
1318  pn->State = 0;
1319  if(pn->Label) {
1320  if(isAnalog)
1321  pn->Name = pn->Label->Name;
1322  else
1323  pn->Name = "net" + pn->Label->Name;
1324  }
1325  else pn->Name = "";
1326  }
1327 
1328  // set the wire names to the connected node
1329  for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next())
1330  if(pw->Label != 0) {
1331  if(isAnalog)
1332  pw->Port1->Name = pw->Label->Name;
1333  else // avoid to use reserved VHDL words
1334  pw->Port1->Name = "net" + pw->Label->Name;
1335  }
1336 
1337  // go through components
1338  if(!throughAllComps(stream, countInit, Collect, ErrText, NumPorts))
1339  return false;
1340 
1341  // work on named nodes first in order to preserve the user given names
1342  throughAllNodes(true, Collect, countInit);
1343 
1344  // give names to the remaining (unnamed) nodes
1345  throughAllNodes(false, Collect, countInit);
1346 
1347  if(!isAnalog) // collect all node names for VHDL signal declaration
1349 
1350  return true;
1351 }
1352 
1353 // ---------------------------------------------------
1354 bool Schematic::createLibNetlist(QTextStream *stream, QTextEdit *ErrText,
1355  int NumPorts)
1356 {
1357  int countInit = 0;
1358  QStringList Collect;
1359  Collect.clear();
1360  FileList.clear();
1361  Signals.clear();
1362  // Apply node names and collect subcircuits and file include
1363  creatingLib = true;
1364  if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts)) {
1365  creatingLib = false;
1366  return false;
1367  }
1368  creatingLib = false;
1369 
1370  // Marking start of actual top-level subcircuit
1371  QString c;
1372  if(!isAnalog) {
1373  if (isVerilog)
1374  c = "///";
1375  else
1376  c = "---";
1377  }
1378  else c = "###";
1379  (*stream) << "\n" << c << " TOP LEVEL MARK " << c << "\n";
1380 
1381  // Emit subcircuit components
1382  createSubNetlistPlain(stream, ErrText, NumPorts);
1383 
1384  Signals.clear(); // was filled in "giveNodeNames()"
1385  return true;
1386 }
1387 
1388 //#define VHDL_SIGNAL_TYPE "bit"
1389 //#define VHDL_LIBRARIES ""
1390 #define VHDL_SIGNAL_TYPE "std_logic"
1391 #define VHDL_LIBRARIES "\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n"
1392 
1393 // ---------------------------------------------------
1394 void Schematic::createSubNetlistPlain(QTextStream *stream, QTextEdit *ErrText,
1395 int NumPorts)
1396 {
1397  int i, z;
1398  QString s;
1399  QStringList SubcircuitPortNames;
1400  QStringList SubcircuitPortTypes;
1401  QStringList InPorts;
1402  QStringList OutPorts;
1403  QStringList InOutPorts;
1404  QStringList::iterator it_name;
1405  QStringList::iterator it_type;
1406  Component *pc;
1407 
1408  // probably creating a library currently
1409  QTextStream * tstream = stream;
1410  QFile ofile;
1411  if(creatingLib) {
1412  QString f = properAbsFileName(DocName) + ".lst";
1413  ofile.setName(f);
1414  if(!ofile.open(IO_WriteOnly)) {
1415  ErrText->insert(tr("ERROR: Cannot create library file \"%s\".").arg(f));
1416  return;
1417  }
1418  tstream = new QTextStream(&ofile);
1419  }
1420 
1421  // collect subcircuit ports and sort their node names into
1422  // "SubcircuitPortNames"
1423  PortTypes.clear();
1424  for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1425  if(pc->Model.at(0) == '.') { // no simulations in subcircuits
1426  ErrText->insert(
1427  QObject::tr("WARNING: Ignore simulation component in subcircuit \"%1\".").arg(DocName)+"\n");
1428  continue;
1429  }
1430  else if(pc->Model == "Port") {
1431  i = pc->Props.first()->Value.toInt();
1432  for(z=SubcircuitPortNames.size(); z<i; z++) { // add empty port names
1433  SubcircuitPortNames.append(" ");
1434  SubcircuitPortTypes.append(" ");
1435  }
1436  it_name = SubcircuitPortNames.begin();
1437  it_type = SubcircuitPortTypes.begin();
1438  for(int n=1;n<i;n++)
1439  {
1440  it_name++;
1441  it_type++;
1442  }
1443  (*it_name) = pc->Ports.getFirst()->Connection->Name;
1444  DigMap::Iterator it = Signals.find(*it_name);
1445  if(it!=Signals.end())
1446  (*it_type) = it.data().Type;
1447  // propagate type to port symbol
1448  pc->Ports.getFirst()->Connection->DType = *it_type;
1449 
1450  if(!isAnalog) {
1451  if (isVerilog) {
1452  Signals.erase(*it_name); // remove node name
1453  switch(pc->Props.at(1)->Value.at(0).latin1()) {
1454  case 'a':
1455  InOutPorts.append(*it_name);
1456  break;
1457  case 'o':
1458  OutPorts.append(*it_name);
1459  break;
1460  default:
1461  InPorts.append(*it_name);
1462  }
1463  }
1464  else {
1465  // remove node name of output port
1466  Signals.erase(*it_name);
1467  switch(pc->Props.at(1)->Value.at(0).latin1()) {
1468  case 'a':
1469  (*it_name) += " : inout"; // attribute "analog" is "inout"
1470  break;
1471  case 'o': // output ports need workaround
1472  Signals.insert(*it_name, DigSignal(*it_name, *it_type));
1473  (*it_name) = "net_out" + (*it_name);
1474  // no "break;" here !!!
1475  default:
1476  (*it_name) += " : " + pc->Props.at(1)->Value;
1477  }
1478  (*it_name) += " " + ((*it_type).isEmpty() ?
1479  VHDL_SIGNAL_TYPE : (*it_type));
1480  }
1481  }
1482  }
1483  }
1484 
1485  // remove empty subcircuit ports (missing port numbers)
1486  for(it_name = SubcircuitPortNames.begin(),
1487  it_type = SubcircuitPortTypes.begin();
1488  it_name != SubcircuitPortNames.end(); ) {
1489  if(*it_name == " ") {
1490  it_name = SubcircuitPortNames.remove(it_name);
1491  it_type = SubcircuitPortTypes.remove(it_type);
1492  } else {
1493  PortTypes.append(*it_type);
1494  it_name++;
1495  it_type++;
1496  }
1497  }
1498 
1499  QString f = properFileName(DocName);
1500  QString Type = properName(f);
1501 
1502  Painting *pi;
1503  if(isAnalog) {
1504  // ..... analog subcircuit ...................................
1505  (*tstream) << "\n.Def:" << Type << " " << SubcircuitPortNames.join(" ");
1506  for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
1507  if(pi->Name == ".ID ") {
1508  SubParameter *pp;
1509  ID_Text *pid = (ID_Text*)pi;
1510  for(pp = pid->Parameter.first(); pp != 0; pp = pid->Parameter.next()) {
1511  s = pp->Name; // keep 'Name' unchanged
1512  (*tstream) << " " << s.replace("=", "=\"") << '"';
1513  }
1514  break;
1515  }
1516  (*tstream) << '\n';
1517 
1518  // write all components with node names into netlist file
1519  for(pc = DocComps.first(); pc != 0; pc = DocComps.next())
1520  (*tstream) << pc->getNetlist();
1521 
1522  (*tstream) << ".Def:End\n";
1523 
1524  }
1525  else {
1526  if (isVerilog) {
1527  // ..... digital subcircuit ...................................
1528  (*tstream) << "\nmodule Sub_" << Type << " ("
1529  << SubcircuitPortNames.join(", ") << ");\n";
1530 
1531  // subcircuit in/out connections
1532  if(!InPorts.isEmpty())
1533  (*tstream) << " input " << InPorts.join(", ") << ";\n";
1534  if(!OutPorts.isEmpty())
1535  (*tstream) << " output " << OutPorts.join(", ") << ";\n";
1536  if(!InOutPorts.isEmpty())
1537  (*tstream) << " inout " << InOutPorts.join(", ") << ";\n";
1538 
1539  // subcircuit connections
1540  if(!Signals.isEmpty()) {
1541  Q3ValueList<DigSignal> values = Signals.values();
1542  Q3ValueList<DigSignal>::iterator it;
1543  for (it = values.begin(); it != values.end(); ++it) {
1544  (*tstream) << " wire " << (*it).Name << ";\n";
1545  }
1546  }
1547  (*tstream) << "\n";
1548 
1549  // subcircuit parameters
1550  for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
1551  if(pi->Name == ".ID ") {
1552  SubParameter *pp;
1553  ID_Text *pid = (ID_Text*)pi;
1554  if(pid->Parameter.first()) {
1555  for(pp = pid->Parameter.first(); pp != 0;) {
1556  s = pp->Name.section('=', 0,0);
1557  QString v = Verilog_Param(pp->Name.section('=', 1,1));
1558  (*tstream) << " parameter " << s << " = " << v << ";\n";
1559  pp = pid->Parameter.next();
1560  }
1561  (*tstream) << "\n";
1562  }
1563  break;
1564  }
1565 
1566  // write all equations into netlist file
1567  for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1568  if(pc->Model == "Eqn") {
1569  (*tstream) << pc->get_Verilog_Code(NumPorts);
1570  }
1571  }
1572 
1573  if(Signals.find("gnd") != Signals.end())
1574  (*tstream) << " assign gnd = 0;\n"; // should appear only once
1575 
1576  // write all components into netlist file
1577  for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1578  if(pc->Model != "Eqn") {
1579  s = pc->get_Verilog_Code(NumPorts);
1580  if(s.length()>0 && s.at(0) == '\xA7') { //section symbol
1581  ErrText->insert(s.mid(1));
1582  }
1583  else (*tstream) << s;
1584  }
1585  }
1586 
1587  (*tstream) << "endmodule\n";
1588  } else {
1589  // ..... digital subcircuit ...................................
1590  (*tstream) << VHDL_LIBRARIES;
1591  (*tstream) << "entity Sub_" << Type << " is\n"
1592  << " port ("
1593  << SubcircuitPortNames.join(";\n ") << ");\n";
1594 
1595  for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next())
1596  if(pi->Name == ".ID ") {
1597  SubParameter *pp;
1598  ID_Text *pid = (ID_Text*)pi;
1599  if(pid->Parameter.first()) {
1600  (*tstream) << " generic (";
1601  for(pp = pid->Parameter.first(); pp != 0;) {
1602  s = pp->Name;
1603  QString t = pp->Type.isEmpty() ? "real" : pp->Type;
1604  (*tstream) << s.replace("=", " : "+t+" := ");
1605  pp = pid->Parameter.next();
1606  if(pp) (*tstream) << ";\n ";
1607  }
1608  (*tstream) << ");\n";
1609  }
1610  break;
1611  }
1612 
1613  (*tstream) << "end entity;\n"
1614  << "use work.all;\n"
1615  << "architecture Arch_Sub_" << Type << " of Sub_" << Type
1616  << " is\n";
1617 
1618  if(!Signals.isEmpty()) {
1619  Q3ValueList<DigSignal> values = Signals.values();
1620  Q3ValueList<DigSignal>::iterator it;
1621  for (it = values.begin(); it != values.end(); ++it) {
1622  (*tstream) << " signal " << (*it).Name << " : "
1623  << ((*it).Type.isEmpty() ?
1624  VHDL_SIGNAL_TYPE : (*it).Type) << ";\n";
1625  }
1626  }
1627 
1628  // write all equations into netlist file
1629  for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1630  if(pc->Model == "Eqn") {
1631  ErrText->insert(
1632  QObject::tr("WARNING: Equations in \"%1\" are 'time' typed.").
1633  arg(pc->Name));
1634  (*tstream) << pc->get_VHDL_Code(NumPorts);
1635  }
1636  }
1637 
1638  (*tstream) << "begin\n";
1639 
1640  if(Signals.find("gnd") != Signals.end())
1641  (*tstream) << " gnd <= '0';\n"; // should appear only once
1642 
1643  // write all components into netlist file
1644  for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1645  if(pc->Model != "Eqn") {
1646  s = pc->get_VHDL_Code(NumPorts);
1647  if(s.length()>0 && s.at(0) == '\xA7') { //section symbol
1648  ErrText->insert(s.mid(1));
1649  }
1650  else (*tstream) << s;
1651  }
1652  }
1653 
1654  (*tstream) << "end architecture;\n";
1655  }
1656  }
1657 
1658  // close file
1659  if(creatingLib) {
1660  ofile.close();
1661  delete tstream;
1662  }
1663 }
1664 // ---------------------------------------------------
1665 // Write the netlist as subcircuit to the text stream 'stream'.
1666 bool Schematic::createSubNetlist(QTextStream *stream, int& countInit,
1667  QStringList& Collect, QTextEdit *ErrText, int NumPorts)
1668 {
1669 // int Collect_count = Collect.count(); // position for this subcircuit
1670 
1671  // TODO: NodeSets have to be put into the subcircuit block.
1672  if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts))
1673  return false;
1674 
1675 /* Example for TODO
1676  for(it = Collect.at(Collect_count); it != Collect.end(); )
1677  if((*it).left(4) == "use ") { // output all subcircuit uses
1678  (*stream) << (*it);
1679  it = Collect.remove(it);
1680  }
1681  else it++;*/
1682 
1683  // Emit subcircuit components
1684  createSubNetlistPlain(stream, ErrText, NumPorts);
1685 
1686  Signals.clear(); // was filled in "giveNodeNames()"
1687  return true;
1688 }
1689 
1690 // ---------------------------------------------------
1691 // Determines the node names and writes subcircuits into netlist file.
1692 int Schematic::prepareNetlist(QTextStream& stream, QStringList& Collect,
1693  QTextEdit *ErrText)
1694 {
1695  if(showBias > 0) showBias = -1; // do not show DC bias anymore
1696 
1697  isVerilog = false;
1698  isAnalog = true;
1699  bool isTruthTable = false;
1700  int allTypes = 0, NumPorts = 0;
1701 
1702  // Detect simulation domain (analog/digital) by looking at component types.
1703  for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1704  if(pc->isActive == COMP_IS_OPEN) continue;
1705  if(pc->Model.at(0) == '.') {
1706  if(pc->Model == ".Digi") {
1707  if(allTypes & isDigitalComponent) {
1708  ErrText->insert(
1709  QObject::tr("ERROR: Only one digital simulation allowed."));
1710  return -10;
1711  }
1712  if(pc->Props.getFirst()->Value != "TimeList")
1713  isTruthTable = true;
1714  if(pc->Props.getLast()->Value != "VHDL")
1715  isVerilog = true;
1716  allTypes |= isDigitalComponent;
1717  isAnalog = false;
1718  }
1719  else allTypes |= isAnalogComponent;
1720  if((allTypes & isComponent) == isComponent) {
1721  ErrText->insert(
1722  QObject::tr("ERROR: Analog and digital simulations cannot be mixed."));
1723  return -10;
1724  }
1725  }
1726  else if(pc->Model == "DigiSource") NumPorts++;
1727  }
1728 
1729  if((allTypes & isAnalogComponent) == 0) {
1730  if(allTypes == 0) {
1731  // If no simulation exists, assume analog simulation. There may
1732  // be a simulation within a SPICE file. Otherwise Qucsator will
1733  // output an error.
1734  isAnalog = true;
1735  allTypes |= isAnalogComponent;
1736  NumPorts = -1;
1737  }
1738  else {
1739  if(NumPorts < 1 && isTruthTable) {
1740  ErrText->insert(
1741  QObject::tr("ERROR: Digital simulation needs at least one digital source."));
1742  return -10;
1743  }
1744  if(!isTruthTable) NumPorts = 0;
1745  }
1746  }
1747  else {
1748  NumPorts = -1;
1749  isAnalog = true;
1750  }
1751 
1752  // first line is documentation
1753  if(allTypes & isAnalogComponent)
1754  stream << "#";
1755  else if (isVerilog)
1756  stream << "//";
1757  else
1758  stream << "--";
1759  stream << " Qucs " << PACKAGE_VERSION << " " << DocName << "\n";
1760 
1761  // set timescale property for verilog schematics
1762  if (isVerilog) {
1763  stream << "\n`timescale 1ps/100fs\n";
1764  }
1765 
1766  int countInit = 0; // counts the nodesets to give them unique names
1767  if(!giveNodeNames(&stream, countInit, Collect, ErrText, NumPorts))
1768  return -10;
1769 
1770  if(allTypes & isAnalogComponent)
1771  return NumPorts;
1772 
1773  if (!isVerilog) {
1774  stream << VHDL_LIBRARIES;
1775  stream << "entity TestBench is\n"
1776  << "end entity;\n"
1777  << "use work.all;\n";
1778  }
1779  return NumPorts;
1780 }
1781 
1782 // ---------------------------------------------------
1783 // Write the beginning of digital netlist to the text stream 'stream'.
1784 void Schematic::beginNetlistDigital(QTextStream& stream)
1785 {
1786  if (isVerilog) {
1787  stream << "module TestBench ();\n";
1788  Q3ValueList<DigSignal> values = Signals.values();
1789  Q3ValueList<DigSignal>::iterator it;
1790  for (it = values.begin(); it != values.end(); ++it) {
1791  stream << " wire " << (*it).Name << ";\n";
1792  }
1793  stream << "\n";
1794  } else {
1795  stream << "architecture Arch_TestBench of TestBench is\n";
1796  Q3ValueList<DigSignal> values = Signals.values();
1797  Q3ValueList<DigSignal>::iterator it;
1798  for (it = values.begin(); it != values.end(); ++it) {
1799  stream << " signal " << (*it).Name << " : "
1800  << ((*it).Type.isEmpty() ?
1801  VHDL_SIGNAL_TYPE : (*it).Type) << ";\n";
1802  }
1803  stream << "begin\n";
1804  }
1805 
1806  if(Signals.find("gnd") != Signals.end()) {
1807  if (isVerilog) {
1808  stream << " assign gnd = 0;\n";
1809  } else {
1810  stream << " gnd <= '0';\n"; // should appear only once
1811  }
1812  }
1813 }
1814 
1815 // ---------------------------------------------------
1816 // Write the end of digital netlist to the text stream 'stream'.
1817 void Schematic::endNetlistDigital(QTextStream& stream)
1818 {
1819  if (isVerilog) {
1820  } else {
1821  stream << "end architecture;\n";
1822  }
1823 }
1824 
1825 // ---------------------------------------------------
1826 // write all components with node names into the netlist file
1827 QString Schematic::createNetlist(QTextStream& stream, int NumPorts)
1828 {
1829  if(!isAnalog) {
1830  beginNetlistDigital(stream);
1831  }
1832 
1833  Signals.clear(); // was filled in "giveNodeNames()"
1834  FileList.clear();
1835 
1836  QString s, Time;
1837  for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) {
1838  if(isAnalog) {
1839  s = pc->getNetlist();
1840  }
1841  else {
1842  if(pc->Model == ".Digi" && pc->isActive) { // simulation component ?
1843  if(NumPorts > 0) { // truth table simulation ?
1844  if (isVerilog)
1845  Time = QString::number((1 << NumPorts));
1846  else
1847  Time = QString::number((1 << NumPorts) - 1) + " ns";
1848  } else {
1849  Time = pc->Props.at(1)->Value;
1850  if (isVerilog) {
1851  if(!Verilog_Time(Time, pc->Name)) return Time;
1852  } else {
1853  if(!VHDL_Time(Time, pc->Name)) return Time; // wrong time format
1854  }
1855  }
1856  }
1857  if (isVerilog) {
1858  s = pc->get_Verilog_Code(NumPorts);
1859  } else {
1860  s = pc->get_VHDL_Code(NumPorts);
1861  }
1862  if (s.length()>0 && s.at(0) == '\xA7'){
1863  return s; // return error
1864  }
1865  }
1866  stream << s;
1867  }
1868 
1869  if(!isAnalog) {
1870  endNetlistDigital(stream);
1871  }
1872 
1873  return Time;
1874 }
QDir AdmsXmlBinDir
Definition: main.h:67
static void createNodeSet(QStringList &, int &, Conductor *, Node *)
int saveDocument()
bool createSubNetlist(QTextStream *, int &, QStringList &, QTextEdit *, int)
QString save()
Definition: component.cpp:704
Q3PtrList< Painting > DocPaints
Definition: schematic.h:122
QDir QucsWorkDir
Definition: main.h:65
QString getErrorText()
Definition: vhdlfile.h:34
int Type
Definition: element.h:152
void createSubNetlistPlain(QTextStream *, QTextEdit *, int)
QString Frame_Text0
Definition: schematic.h:136
QString Script
Definition: qucsdoc.h:54
bool load(const QString &, QTextStream *)
Definition: diagram.cpp:1243
bool GridOn
Definition: qucsdoc.h:64
Definition: node.h:30
QString properFileName(const QString &Name)
Definition: main.cpp:468
int y1
Definition: element.h:153
bool SimOpenDpl
Definition: qucsdoc.h:61
QString DType
Definition: node.h:41
QString get_Verilog_Code(int)
Definition: component.cpp:660
Definition: wire.h:31
bool createSubNetlist(QTextStream *)
Definition: spicefile.cpp:247
void simpleInsertWire(Wire *)
label for Node and Wire classes
Definition: element.h:161
int tmpViewX2
Definition: schematic.h:141
#define isNodeLabel
Definition: element.h:126
float Scale
Definition: qucsdoc.h:58
int isActive
Definition: component.h:77
bool loadComponents(QTextStream *, Q3PtrList< Component > *List=0)
int State
Definition: node.h:42
QString Verilog_Param(const QString Value)
Definition: main.cpp:540
tQucsSettings QucsSettings
Definition: main.cpp:52
int tmpViewY1
Definition: schematic.h:141
bool giveNodeNames(QTextStream *, int &, QStringList &, QTextEdit *, int)
virtual QString save()
Definition: painting.cpp:39
Component * getComponentFromName(QString &Line, Schematic *p)
Definition: component.cpp:1532
QString createSymbolUndoString(char)
int showBias
Definition: qucsdoc.h:63
int y2
Definition: element.h:153
Definition: element.h:72
int x1
Definition: element.h:153
bool checkVersion(QString &Line)
Definition: main.cpp:602
QString getErrorText()
Definition: spicefile.h:42
void convert2Unicode(QString &Text)
Definition: main.cpp:416
QString createClipboardFile()
bool creatingLib
Definition: schematic.h:298
QString fileSuffix(void)
Definition: qucsdoc.cpp:107
virtual QString saveJSON()
Definition: painting.cpp:49
bool isVerilog
Definition: schematic.h:297
QMap< QString, SubFile > SubMap
Definition: schematic.h:67
bool SimRunScript
Definition: qucsdoc.h:62
void collectDigitalSignals(void)
#define isDigitalComponent
Definition: element.h:113
SubMap FileList
Q3PtrList< Diagram > * Diagrams
Definition: schematic.h:121
QString BinDir
Definition: main.h:57
int ViewY1
Definition: schematic.h:132
Definitions and declarations for the main application.
bool loadWires(QTextStream *, Q3PtrList< Element > *List=0)
QucsApp * QucsMain
Definition: main.cpp:54
int tmpViewY2
Definition: schematic.h:141
int cx
Definition: element.h:153
QString properAbsFileName(const QString &Name)
Definition: main.cpp:452
QString getErrorText()
Definition: verilogfile.h:34
QString createNetlist(QTextStream &, int)
Q3PtrList< Component > * Components
Definition: schematic.h:123
Q3PtrList< Property > Props
Definition: component.h:72
bool createSubNetlist(QTextStream *)
Definition: vhdlfile.cpp:212
void throughAllNodes(bool, QStringList &, int &)
bool symbolMode
Definition: schematic.h:128
QString save()
Definition: wire.cpp:151
bool isSelected
Definition: element.h:151
void simpleInsertComponent(Component *)
bool isAnalog
Definition: schematic.h:296
void endNetlistDigital(QTextStream &)
Q3PtrList< Diagram > DocDiags
Definition: schematic.h:121
bool loadPaintings(QTextStream *, Q3PtrList< Painting > *)
bool createSubNetlist(QTextStream *)
bool rebuild(QString *)
bool Verilog_Time(QString &t, const QString &Name)
Definition: main.cpp:575
bool VHDL_Time(QString &t, const QString &Name)
Definition: main.cpp:513
Q3PtrList< Element > Connections
Definition: node.h:39
QString createUndoString(char)
Q3PtrList< Node > * Nodes
Definition: schematic.h:120
virtual void setSchematic(Schematic *p)
Definition: component.h:65
int ViewY2
Definition: schematic.h:132
QString Name
Definition: painting.h:55
float tmpScale
Definition: schematic.h:140
bool pasteFromClipboard(QTextStream *, Q3PtrList< Element > *)
int GridX
Definition: schematic.h:131
#define isAnalogComponent
Definition: element.h:112
QString Frame_Text1
Definition: schematic.h:136
int ViewX1
Definition: schematic.h:132
Definition: element.h:48
Superclass of all schematic drawing elements.
Definition: element.h:142
QString save()
Definition: diagram.cpp:1197
DigMap Signals
Definition: schematic.h:292
virtual QString getSubcircuitFile()
Definition: component.h:63
int ViewX2
Definition: schematic.h:132
bool rebuildSymbol(QString *)
QString Frame_Text2
Definition: schematic.h:136
int showFrame
Definition: schematic.h:135
QDir QucsHomeDir
Definition: main.h:66
QString Type
Definition: id_text.h:34
Q3PtrList< Port > Ports
Definition: component.h:70
void convert2ASCII(QString &Text)
Definition: main.cpp:433
QString DataSet
Definition: qucsdoc.h:52
QString fileBase(void)
Definition: qucsdoc.cpp:116
#define VHDL_LIBRARIES
bool load(const QString &)
Definition: wire.cpp:167
QString Name
Definition: id_text.h:34
int GridY
Definition: schematic.h:131
QString Name
Definition: component.h:80
bool createLibNetlist(QTextStream *, QTextEdit *, int)
QStringList PortTypes
Definition: schematic.h:293
QString Model
Definition: component.h:80
Schematic(QucsApp *, const QString &)
Definition: schematic.cpp:70
QString Name
Definition: node.h:40
bool throughAllComps(QTextStream *, int &, QStringList &, QTextEdit *, int)
int saveSymbolCpp(void)
Conductor * pOwner
Definition: wirelabel.h:42
int cy
Definition: element.h:153
int prepareNetlist(QTextStream &, QStringList &, QTextEdit *)
Q3PtrList< Painting > SymbolPaints
Definition: schematic.h:125
WireLabel * Label
Definition: element.h:163
QString DocName
Definition: qucsdoc.h:51
int tmpPosY
Definition: qucsdoc.h:65
Q3PtrList< SubParameter > Parameter
Definition: id_text.h:60
void propagateNode(QStringList &, int &, Node *)
#define isMovingLabel
Definition: element.h:127
#define isComponent
Definition: element.h:110
Node * Port1
Definition: wire.h:43
Q3PtrList< Wire > DocWires
Definition: schematic.h:119
QString properName(const QString &Name)
Definition: main.cpp:476
virtual QString saveCpp()
Definition: painting.cpp:44
int tmpPosX
Definition: qucsdoc.h:65
bool loadProperties(QTextStream *)
#define isWire
Definition: element.h:118
QString Frame_Text3
Definition: schematic.h:136
void beginNetlistDigital(QTextStream &)
int x2
Definition: element.h:153
void setName(const QString &)
Definition: schematic.cpp:260
Q3PtrList< Node > DocNodes
Definition: schematic.h:120
Q3PtrList< Painting > * Paintings
Definition: schematic.h:122
#define COMP_IS_ACTIVE
Definition: component.h:75
Node * Port2
Definition: wire.h:43
bool loadDocument()
bool loadIntoNothing(QTextStream *)
Q3PtrList< Wire > * Wires
Definition: schematic.h:119
virtual void Bounding(int &, int &, int &, int &)
Definition: painting.cpp:33
QStringList PortTypes
Definition: schematic.h:65
bool loadDiagrams(QTextStream *, Q3PtrList< Diagram > *)
QString getNetlist()
Definition: component.cpp:634
Definition: arrow.h:26
QString DataDisplay
Definition: qucsdoc.h:53
QString initValue
Definition: wirelabel.h:46
QString get_VHDL_Code(int)
Definition: component.cpp:685
virtual bool load(const QString &)
Definition: painting.h:36
#define VHDL_SIGNAL_TYPE
int tmpViewX1
Definition: schematic.h:141
int saveSymbolJSON(void)
#define COMP_IS_OPEN
Definition: component.h:74
Q3PtrList< Component > DocComps
Definition: schematic.h:123