Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
spicedialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  spicedialog.cpp
3  -----------------
4  begin : Tue May 3 2005
5  copyright : (C) 2005 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 #include <QtGui>
18 #include "spicedialog.h"
19 #include "spicefile.h"
20 #include "main.h"
21 #include "qucs.h"
22 //Added by qt3to4:
23 #include <QTextStream>
24 #include <Q3GridLayout>
25 #include <Q3VBoxLayout>
26 #include "schematic.h"
27 
28 #include <QLabel>
29 #include <QLayout>
30 #include <Q3HBox>
31 #include <Q3VBox>
32 #include <QLineEdit>
33 #include <QValidator>
34 #include <QFileDialog>
35 #include <QPushButton>
36 #include <Q3ListBox>
37 #include <QCheckBox>
38 #include <QProcess>
39 #include <QMessageBox>
40 #include <QComboBox>
41 
42 
44  : QDialog(d, 0, TRUE, Qt::WDestructiveClose)
45 {
46  App = App_; // pointer to main application
47 
48  resize(400, 250);
49  setCaption(tr("Edit SPICE Component Properties"));
50  Comp = c;
51  Doc = d;
52 
53  all = new Q3VBoxLayout(this); // to provide neccessary size
54  QWidget *myParent = this;
55 
56  Expr.setPattern("[^\"=]+"); // valid expression for property 'edit' etc
57  Validator = new QRegExpValidator(Expr, this);
58  Expr.setPattern("[\\w_]+"); // valid expression for property 'NameEdit' etc
59  ValRestrict = new QRegExpValidator(Expr, this);
60 
61 
62  // ...........................................................
63  Q3GridLayout *topGrid = new Q3GridLayout(0, 4,3,3,3);
64  all->addLayout(topGrid);
65 
66  topGrid->addWidget(new QLabel(tr("Name:"), myParent), 0,0);
67  CompNameEdit = new QLineEdit(myParent);
68  CompNameEdit->setValidator(ValRestrict);
69  topGrid->addWidget(CompNameEdit, 0,1);
70  connect(CompNameEdit, SIGNAL(returnPressed()), SLOT(slotButtOK()));
71 
72  topGrid->addWidget(new QLabel(tr("File:"), myParent), 1,0);
73  FileEdit = new QLineEdit(myParent);
74  FileEdit->setValidator(ValRestrict);
75  topGrid->addWidget(FileEdit, 1,1);
76  connect(FileEdit, SIGNAL(returnPressed()), SLOT(slotButtOK()));
77 
78  ButtBrowse = new QPushButton(tr("Browse"), myParent);
79  topGrid->addWidget(ButtBrowse, 1,2);
80  connect(ButtBrowse, SIGNAL(clicked()), SLOT(slotButtBrowse()));
81 
82  ButtEdit = new QPushButton(tr("Edit"), myParent);
83  topGrid->addWidget(ButtEdit, 2,2);
84  connect(ButtEdit, SIGNAL(clicked()), SLOT(slotButtEdit()));
85 
86  FileCheck = new QCheckBox(tr("show file name in schematic"), myParent);
87  topGrid->addWidget(FileCheck, 2,1);
88 
89  SimCheck = new QCheckBox(tr("include SPICE simulations"), myParent);
90  topGrid->addWidget(SimCheck, 3,1);
91 
92  Q3HBox *h1 = new Q3HBox(myParent);
93  h1->setSpacing(5);
94  PrepCombo = new QComboBox(h1);
95  PrepCombo->insertItem("none");
96  PrepCombo->insertItem("ps2sp");
97  PrepCombo->insertItem("spicepp");
98  PrepCombo->insertItem("spiceprm");
99  QLabel * PrepLabel = new QLabel(tr("preprocessor"), h1);
100  PrepLabel->setMargin(5);
101  topGrid->addWidget(h1, 4,1);
102  connect(PrepCombo, SIGNAL(activated(int)), SLOT(slotPrepChanged(int)));
103 
104  // ...........................................................
105  Q3GridLayout *midGrid = new Q3GridLayout(0, 2,3,5,5);
106  all->addLayout(midGrid);
107 
108  midGrid->addWidget(new QLabel(tr("SPICE net nodes:"), myParent), 0,0);
109  NodesList = new Q3ListBox(myParent);
110  midGrid->addWidget(NodesList, 1,0);
111  connect(NodesList, SIGNAL(doubleClicked(Q3ListBoxItem*)),
112  SLOT(slotAddPort(Q3ListBoxItem*)));
113 
114  Q3VBox *v0 = new Q3VBox(myParent);
115  v0->setSpacing(5);
116  midGrid->addWidget(v0, 1,1);
117  ButtAdd = new QPushButton(tr("Add >>"), v0);
118  connect(ButtAdd, SIGNAL(clicked()), SLOT(slotButtAdd()));
119  ButtRemove = new QPushButton(tr("<< Remove"), v0);
120  connect(ButtRemove, SIGNAL(clicked()), SLOT(slotButtRemove()));
121  v0->setStretchFactor(new QWidget(v0), 5); // stretchable placeholder
122 
123  midGrid->addWidget(new QLabel(tr("Component ports:"), myParent), 0,2);
124  PortsList = new Q3ListBox(myParent);
125  midGrid->addWidget(PortsList, 1,2);
126  connect(PortsList, SIGNAL(doubleClicked(Q3ListBoxItem*)),
127  SLOT(slotRemovePort(Q3ListBoxItem*)));
128 
129 
130  // ...........................................................
131  Q3HBox *h0 = new Q3HBox(this);
132  h0->setSpacing(5);
133  all->addWidget(h0);
134  connect(new QPushButton(tr("OK"),h0), SIGNAL(clicked()),
135  SLOT(slotButtOK()));
136  connect(new QPushButton(tr("Apply"),h0), SIGNAL(clicked()),
137  SLOT(slotButtApply()));
138  connect(new QPushButton(tr("Cancel"),h0), SIGNAL(clicked()),
139  SLOT(slotButtCancel()));
140 
141  // ------------------------------------------------------------
142  CompNameEdit->setText(Comp->Name);
143  changed = false;
144 
145  // insert all properties into the ListBox
146  Property *pp = Comp->Props.first();
147  FileEdit->setText(pp->Value);
148  FileCheck->setChecked(pp->display);
149  SimCheck->setChecked(Comp->Props.at(2)->Value == "yes");
150  for(int i=0; i<PrepCombo->count(); i++)
151  {
152  if(PrepCombo->text(i) == Comp->Props.at(3)->Value)
153  {
154  PrepCombo->setCurrentItem(i);
155  currentPrep = i;
156  break;
157  }
158  }
159 
160  loadSpiceNetList(pp->Value); // load netlist nodes
161 }
162 
164 {
165  delete all;
166  delete Validator;
167  delete ValRestrict;
168 }
169 
170 // -------------------------------------------------------------------------
171 // Is called if the "OK"-button is pressed.
173 {
174  slotButtApply();
175  slotButtCancel();
176 }
177 
178 // -------------------------------------------------------------------------
179 // Is called if the "Cancel"-button is pressed.
181 {
182  if(changed) done(1); // changed could have been done before
183  else done(0); // (by "Apply"-button)
184 }
185 
186 //-----------------------------------------------------------------
187 // To get really all close events (even <Escape> key).
189 {
190  slotButtCancel();
191 }
192 
193 // -------------------------------------------------------------------------
194 // Is called, if the "Apply"-button is pressed.
196 {
197  Component *pc;
198  if(CompNameEdit->text().isEmpty()) CompNameEdit->setText(Comp->Name);
199  else if(CompNameEdit->text() != Comp->Name)
200  {
201  for(pc = Doc->Components->first(); pc!=0; pc = Doc->Components->next())
202  if(pc->Name == CompNameEdit->text())
203  break; // found component with the same name ?
204  if(pc) CompNameEdit->setText(Comp->Name);
205  else
206  {
207  Comp->Name = CompNameEdit->text();
208  changed = true;
209  }
210  }
211 
212  // apply all the new property values
213  Property *pp = Comp->Props.first();
214  if(pp->Value != FileEdit->text())
215  {
216  pp->Value = FileEdit->text();
217  changed = true;
218  }
219  if(pp->display != FileCheck->isChecked())
220  {
221  pp->display = FileCheck->isChecked();
222  changed = true;
223  }
224 
225  QString tmp;
226  for(unsigned int i=0; i<PortsList->count(); i++)
227  {
228  if(!tmp.isEmpty()) tmp += ',';
229  tmp += "_net" + PortsList->text(i); // chosen ports
230  }
231  pp = Comp->Props.next();
232  if(pp->Value != tmp)
233  {
234  pp->Value = tmp;
235  changed = true;
236  }
237  pp = Comp->Props.next();
238  if((pp->Value=="yes") != SimCheck->isChecked())
239  {
240  if(SimCheck->isChecked()) pp->Value = "yes";
241  else pp->Value = "no";
242  changed = true;
243  }
244  if(pp->Value != "yes") Comp->withSim = false;
245 
246  pp = Comp->Props.next();
247  if(pp->Value != PrepCombo->currentText())
248  {
249  pp->Value = PrepCombo->currentText();
250  changed = true;
251  }
252 
253  if(changed || Comp->withSim) // because of "sim" text
254  {
255  Doc->recreateComponent(Comp); // to apply changes to the schematic symbol
256  Doc->viewport()->repaint();
257  }
258 }
259 
260 // -------------------------------------------------------------------------
262 {
263  QString s = QFileDialog::getOpenFileName(this,
264  tr("Select a file"),
265  lastDir.isEmpty() ? QString(".") : lastDir,
266  tr("SPICE netlist") + App->getSpiceFileFilter ()
267  + tr("All Files") + " (*.*)");
268 
269  if(s.isEmpty()) return;
270 
271  QFileInfo Info(s);
272  lastDir = Info.dirPath(true); // remember last directory
273 
274  // snip path if file in current directory
275  if(QucsSettings.QucsWorkDir.exists(Info.fileName()) &&
276  QucsSettings.QucsWorkDir.absPath() == Info.dirPath(true)) s = Info.fileName();
277  FileEdit->setText(s);
278 
279  Comp->Props.at(1)->Value = "";
280  loadSpiceNetList(s);
281 }
282 
283 // -------------------------------------------------------------------------
285 {
286  if(currentPrep != i)
287  {
288  currentPrep = i;
289  PrepCombo->setCurrentItem(i);
290  loadSpiceNetList(FileEdit->text()); // reload netlist nodes
291  }
292 }
293 
294 // -------------------------------------------------------------------------
295 bool SpiceDialog::loadSpiceNetList(const QString& s)
296 {
297  Comp->withSim = false;
298  if(s.isEmpty()) return false;
299  QFileInfo FileInfo(QucsSettings.QucsWorkDir, s);
300 
301  NodesList->clear();
302  PortsList->clear();
303  textStatus = 0;
304  Line = Error = "";
305 
306  QString preprocessor = PrepCombo->currentText();
307  if (preprocessor != "none")
308  {
309  qDebug() << "Run spice preprocessor (perl)";
310  bool piping = true;
311  QString script;
312 #ifdef __MINGW32__
313  QString interpreter = "tinyperl.exe";
314 #else
315  QString interpreter = "perl";
316 #endif
317  if (preprocessor == "ps2sp")
318  {
319  script = "ps2sp";
320  }
321  else if (preprocessor == "spicepp")
322  {
323  script = "spicepp.pl";
324  }
325  else if (preprocessor == "spiceprm")
326  {
327  script = "spiceprm";
328  piping = false;
329  }
330  script = QucsSettings.BinDir + script;
331  QString spiceCommand;
332  SpicePrep = new QProcess(this);
333  spiceCommand+=interpreter + " ";
334  spiceCommand+=script + " ";
335  spiceCommand+=FileInfo.filePath() + " ";
336 
337  QFile PrepFile;
338  QFileInfo PrepInfo(QucsSettings.QucsWorkDir, s + ".pre");
339  QString PrepName = PrepInfo.filePath();
340 
341  if (!piping)
342  {
343  spiceCommand += PrepName + " ";
344  connect(SpicePrep, SIGNAL(readyReadStandardOutput()), SLOT(slotSkipOut()));
345  connect(SpicePrep, SIGNAL(readyReadStandardError()), SLOT(slotGetPrepErr()));
346  }
347  else
348  {
349  connect(SpicePrep, SIGNAL(readyReadStandardOutput()), SLOT(slotGetPrepOut()));
350  connect(SpicePrep, SIGNAL(readyReadStandardError()), SLOT(slotGetPrepErr()));
351  }
352 
353  QMessageBox *MBox = new QMessageBox(tr("Info"),
354  tr("Preprocessing SPICE file \"%1\".").arg(FileInfo.filePath()),
355  QMessageBox::NoIcon, QMessageBox::Abort,
356  QMessageBox::NoButton, QMessageBox::NoButton, this, 0, true,
357  Qt::WStyle_DialogBorder | Qt::WDestructiveClose);
358 
359  connect(SpicePrep, SIGNAL(finished(int, QProcess::ExitStatus)), MBox, SLOT(close()));
360 
361  if (piping)
362  {
363  PrepFile.setName(PrepName);
364  if(!PrepFile.open(QIODevice::WriteOnly))
365  {
366  QMessageBox::critical(this, tr("Error"),
367  tr("Cannot save preprocessed SPICE file \"%1\".").
368  arg(PrepName));
369  return false;
370  }
371  prestream = new QTextStream(&PrepFile);
372  }
373  SpicePrep->start(spiceCommand);
374  if ((SpicePrep->state() != QProcess::Starting) && (SpicePrep->state() != QProcess::Running))
375  {
376  QMessageBox::critical(this, tr("Error"),
377  tr("Cannot execute \"%1\".").arg(interpreter + " " + script));
378  if (piping)
379  {
380  PrepFile.close();
381  delete prestream;
382  }
383  return false;
384  }
385  //SpicePrep->closeStdin();
386 
387  MBox->exec();
388  delete SpicePrep;
389  if (piping)
390  {
391  PrepFile.close();
392  delete prestream;
393  }
394 
395  if(!Error.isEmpty())
396  {
397  QMessageBox::critical(this, tr("SPICE Preprocessor Error"), Error);
398  return false;
399  }
400  FileInfo = QFileInfo(QucsSettings.QucsWorkDir, s + ".pre");
401  }
402 
403  // Now do the spice->qucs netlist conversion using the qucsconv program ...
404  QucsConv = new QProcess(this);
405 
406  QString executableSuffix = "";
407 #ifdef __MINGW32__
408  executableSuffix = ".exe";
409 #endif
410 
411  QString Program;
412  QStringList Arguments;
413  Program = QucsSettings.BinDir + "qucsconv" + executableSuffix;
414  Arguments << "-if" << "spice"
415  << "-of" << "qucs"
416  << "-i" << FileInfo.filePath();
417 
418  qDebug() << "Command :" << Program << Arguments.join(" ");
419 
420  connect(QucsConv, SIGNAL(readyReadStandardOutput()), SLOT(slotGetNetlist()));
421  connect(QucsConv, SIGNAL(readyReadStandardError()), SLOT(slotGetError()));
422 
423 
424  QMessageBox *MBox = new QMessageBox(tr("Info"),
425  tr("Converting SPICE file \"%1\".").arg(FileInfo.filePath()),
426  QMessageBox::NoIcon, QMessageBox::Abort,
427  QMessageBox::NoButton, QMessageBox::NoButton, this, 0, true,
428  Qt::WStyle_DialogBorder | Qt::WDestructiveClose);
429 
430  connect(QucsConv, SIGNAL(finished(int, QProcess::ExitStatus)), MBox, SLOT(close()));
431 
432  QucsConv->start(Program, Arguments);
433 
434 // if((QucsConv->state() != QProcess::Starting) && (QucsConv->state()!=QProcess::Running))
435  if(!QucsConv->Running)
436  {
437  QMessageBox::critical(this, tr("Error"),
438  tr("Cannot execute \"%1\".").arg(QucsSettings.BinDir + "qucsconv" + executableSuffix));
439  return false;
440  }
441 
442  MBox->exec();
443 
444  if(!Error.isEmpty())
445  QMessageBox::critical(this, tr("QucsConv Error"), Error);
446 
447  Property *pp = Comp->Props.at(1);
448  if(!pp->Value.isEmpty())
449  {
450  PortsList->clear();
451  PortsList->insertStringList(QStringList::split(',', pp->Value));
452  }
453 
454  QString tmp;
455  Q3ListBoxItem *pi;
456  for(unsigned int i=0; i<PortsList->count(); i++)
457  {
458  tmp = PortsList->text(i).remove(0, 4);
459  PortsList->changeItem(tmp, i);
460 
461  pi = NodesList->findItem(tmp, Qt::CaseSensitive | QKeySequence::ExactMatch);
462  if(pi) delete pi;
463  else PortsList->removeItem(i--);
464  }
465  return true;
466 }
467 
468 // -------------------------------------------------------------------------
470 {
471  SpicePrep->readAllStandardError ();
472 }
473 
474 // -------------------------------------------------------------------------
476 {
477  SpicePrep->readAllStandardOutput ();
478 }
479 
480 // -------------------------------------------------------------------------
482 {
483  Error += QString(SpicePrep->readAllStandardError ());
484 }
485 
486 // -------------------------------------------------------------------------
488 {
489  (*prestream) << QString(SpicePrep->readAllStandardOutput ());
490 }
491 
492 // -------------------------------------------------------------------------
494 {
495  Error += QString(QucsConv->readAllStandardError ());
496 }
497 
498 // -------------------------------------------------------------------------
500 {
501  qDebug() << "slotGetNetlist";
502  int i;
503  QString s;
504  Line += QString(QucsConv->readAllStandardOutput ());
505 
506  while((i = Line.find('\n')) >= 0)
507  {
508 
509  s = Line.left(i);
510 
511  Line.remove(0, i+1);
512 
513  s = s.stripWhiteSpace();
514  if (!s.isEmpty ())
515  {
516  if (s.at(0) == '.')
517  {
518  if (s.left(5) != ".Def:")
519  {
520  Comp->withSim = true;
521  }
522  continue;
523  }
524  }
525 
526  switch(textStatus)
527  {
528  case 0:
529  if (s == "### TOPLEVEL NODELIST BEGIN")
530  {
531  textStatus = 1;
532  }
533  else if (s == "### SPICE OUTPUT NODELIST BEGIN")
534  {
535  textStatus = 2;
536  }
537  break;
538 
539  case 1:
540  if (s == "### TOPLEVEL NODELIST END")
541  {
542  textStatus = 0;
543  break;
544  }
545 
546  if (s.left(2) != "# ")
547  {
548  break;
549  }
550  s.remove(0, 2);
551 
552  if(s.left(4) == "_net")
553  {
554  NodesList->insertItem(s.remove(0, 4));
555  }
556  break;
557 
558  case 2:
559  if(s == "### SPICE OUTPUT NODELIST END")
560  {
561  textStatus = 0;
562  break;
563  }
564  if(s.left(2) != "# ")
565  {
566  break;
567  }
568  s.remove(0, 2);
569 
570  if(s.left(4) == "_net")
571  {
572  PortsList->insertItem(s); // prefix "_net" is removed later on
573  }
574  break;
575  }
576  }
577 }
578 
579 // -------------------------------------------------------------------------
581 {
582  Doc->App->editFile(QucsSettings.QucsWorkDir.filePath(FileEdit->text()));
583 }
584 
585 // -------------------------------------------------------------------------
586 // Is called if the add button is pressed.
588 {
589  int i = NodesList->currentItem();
590  if(i < 0) return;
591  PortsList->insertItem(NodesList->currentText());
592  NodesList->removeItem(i);
593 }
594 
595 // -------------------------------------------------------------------------
596 // Is called if the remove button is pressed.
598 {
599  int i = PortsList->currentItem();
600  if(i < 0) return;
601  NodesList->insertItem(PortsList->currentText());
602  PortsList->removeItem(i);
603 }
604 
605 // -------------------------------------------------------------------------
606 // Is called when double-click on NodesList-Box
607 void SpiceDialog::slotAddPort(Q3ListBoxItem *Item)
608 {
609  if(Item) slotButtAdd();
610 }
611 
612 // -------------------------------------------------------------------------
613 // Is called when double-click on PortsList-Box
614 void SpiceDialog::slotRemovePort(Q3ListBoxItem *Item)
615 {
616  if(Item) slotButtRemove();
617 }
void slotButtApply()
QucsApp * App
Definition: spicedialog.h:94
Schematic * Doc
Definition: spicedialog.h:85
QDir QucsWorkDir
Definition: main.h:65
void slotAddPort(Q3ListBoxItem *)
void slotGetError()
int textStatus
Definition: spicedialog.h:92
void slotButtBrowse()
bool withSim
Definition: spicefile.h:40
Q3ListBox * PortsList
Definition: spicedialog.h:79
tQucsSettings QucsSettings
Definition: main.cpp:52
QPushButton * ButtAdd
Definition: spicedialog.h:82
void slotGetNetlist()
QRegExpValidator * Validator
Definition: spicedialog.h:77
QPushButton * ButtBrowse
Definition: spicedialog.h:82
QProcess * SpicePrep
Definition: spicedialog.h:90
QPushButton * ButtEdit
Definition: spicedialog.h:82
Q3VBoxLayout * all
Definition: spicedialog.h:76
QLineEdit * CompNameEdit
Definition: spicedialog.h:81
QString BinDir
Definition: main.h:57
bool display
Definition: element.h:99
Definitions and declarations for the main application.
QString Value
Definition: element.h:97
void slotGetPrepOut()
QString lastDir
Definition: main.cpp:55
int currentPrep
Definition: spicedialog.h:87
QComboBox * PrepCombo
Definition: spicedialog.h:83
QRegExp Expr
Definition: spicedialog.h:78
Q3PtrList< Component > * Components
Definition: schematic.h:123
Q3PtrList< Property > Props
Definition: component.h:72
QProcess * QucsConv
Definition: spicedialog.h:90
QString Error
Definition: spicedialog.h:91
QucsApp * App
Definition: qucsdoc.h:59
bool changed
Definition: spicedialog.h:86
QCheckBox * FileCheck
Definition: spicedialog.h:80
void slotButtCancel()
void slotButtOK()
Definition: element.h:48
QTextStream * prestream
Definition: spicedialog.h:89
SpiceFile * Comp
Definition: spicedialog.h:84
void slotGetPrepErr()
QString getSpiceFileFilter(void)
Definition: qucs.cpp:3001
SpiceDialog(QucsApp *, SpiceFile *, Schematic *)
Definition: spicedialog.cpp:43
QPushButton * ButtRemove
Definition: spicedialog.h:82
QString Name
Definition: component.h:80
QLineEdit * FileEdit
Definition: spicedialog.h:81
#define executableSuffix
Definition: simmessage.cpp:45
QCheckBox * SimCheck
Definition: spicedialog.h:80
Q3ListBox * NodesList
Definition: spicedialog.h:79
QRegExpValidator * ValRestrict
Definition: spicedialog.h:77
void editFile(const QString &)
void slotButtRemove()
bool loadSpiceNetList(const QString &)
Definition: qucs.h:61
void slotRemovePort(Q3ListBoxItem *)
void recreateComponent(Component *)
void slotButtAdd()
void slotPrepChanged(int)
void slotSkipOut()
void slotSkipErr()
void slotButtEdit()