Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/dialogs/simmessage.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               simmessage.cpp
00003                              ----------------
00004     begin                : Sat Sep 6 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 
00024 #include <stdlib.h>
00025 #include <iostream>
00026 using namespace std;
00027 #include <QLabel>
00028 #include <QGroupBox>
00029 #include <QTimer>
00030 #include <QPushButton>
00031 #include <QPlainTextEdit>
00032 #include <QDateTime>
00033 #include <QRegExp>
00034 #include <QTextStream>
00035 #include <QVBoxLayout>
00036 #include <QHBoxLayout>
00037 #include <QProcess>
00038 #include <QProgressBar>
00039 #include <QDebug>
00040 #include <QMessageBox>
00041 
00042 #include "simmessage.h"
00043 #include "main.h"
00044 #include "module.h"
00045 #include "qucs.h"
00046 #include "textdoc.h"
00047 #include "schematic.h"
00048 #include "components/opt_sim.h"
00049 #include "components/vhdlfile.h"
00050 #include "misc.h"
00051 
00052 #ifdef __MINGW32__
00053 #define executableSuffix ".exe"
00054 #else
00055 #define executableSuffix ""
00056 #endif
00057 
00064 SimMessage::SimMessage(QWidget *w, QWidget *parent)
00065     : QDialog(parent) 
00066 {
00067   setWindowTitle(tr("Qucs Simulation Messages"));
00068   QucsDoc *Doc;
00069   DocWidget = w;
00070   if(DocWidget->inherits("QTextEdit"))
00071     Doc = (QucsDoc*) ((TextDoc*)DocWidget);
00072   else
00073     Doc = (QucsDoc*) ((Schematic*)DocWidget);
00074 
00075   DocName = Doc->DocName;
00076   DataDisplay = Doc->DataDisplay;
00077   Script = Doc->Script;
00078   QFileInfo Info(DocName);
00079   DataSet = QDir::convertSeparators(Info.path()) +
00080     QDir::separator() + Doc->DataSet;
00081   showBias = Doc->showBias;     // save some settings as the document...
00082   SimOpenDpl = Doc->SimOpenDpl; // ...could be closed during the simulation.
00083   SimRunScript = Doc->SimRunScript;
00084 
00085   all = new QVBoxLayout(this);
00086   all->setSpacing(5);
00087   all->setMargin(5);
00088   QGroupBox *Group1 = new QGroupBox(tr("Progress:"));
00089   all->addWidget(Group1);
00090   QVBoxLayout *vbox1 = new QVBoxLayout();
00091   Group1->setLayout(vbox1);
00092 
00093   ProgText = new QPlainTextEdit();
00094   vbox1->addWidget(ProgText);
00095   ProgText->setReadOnly(true);
00096   //ProgText->setWordWrapMode(QTextOption::NoWrap);
00097   ProgText->setMinimumSize(400,80);
00098   wasLF = false;
00099   simKilled = false;
00100 
00101   QGroupBox *HGroup = new QGroupBox();
00102   QHBoxLayout *hbox = new QHBoxLayout();
00103   //HGroup->setInsideMargin(5);
00104   //HGroup->setInsideSpacing(5);
00105   all->addWidget(HGroup);
00106   QLabel *progr = new QLabel(tr("Progress:"));
00107   hbox->addWidget(progr);
00108   SimProgress = new QProgressBar();
00109   hbox->addWidget(SimProgress);
00110 //  SimProgress->setPercentageVisible(false);
00111   HGroup->setLayout(hbox);
00112 
00113   QGroupBox *Group2 = new QGroupBox(tr("Errors and Warnings:"));
00114   all->addWidget(Group2);
00115   QVBoxLayout *vbox2 = new QVBoxLayout();
00116 
00117   ErrText = new QPlainTextEdit();
00118   vbox2->addWidget(ErrText);
00119   ErrText->setReadOnly(true);
00120   ErrText->setWordWrapMode(QTextOption::NoWrap);
00121   ErrText->setMinimumSize(400,80);
00122   Group2->setLayout(vbox2);
00123 
00124   QHBoxLayout *Butts = new QHBoxLayout();
00125   all->addLayout(Butts);
00126 
00127   Display = new QPushButton(tr("Goto display page"));
00128   Butts->addWidget(Display);
00129   Display->setDisabled(true);
00130   connect(Display,SIGNAL(clicked()),SLOT(slotDisplayButton()));
00131 
00132   Abort = new QPushButton(tr("Abort simulation"));
00133   Butts->addWidget(Abort);
00134   // Abort will close the window, which in turn will abort the simulation
00135   connect(Abort,SIGNAL(clicked()),SLOT(reject()));
00136   connect(this,SIGNAL(rejected()),SLOT(AbortSim()));
00137 }
00138 
00145 SimMessage::~SimMessage()
00146 {
00147   if(SimProcess.state()==QProcess::Running)  SimProcess.kill();
00148   delete all;
00149 }
00150 
00151 // ------------------------------------------------------------------------
00152 bool SimMessage::startProcess()
00153 {
00154   Abort->setText(tr("Abort simulation"));
00155   Display->setDisabled(true);
00156 
00157   QString txt = tr("Starting new simulation on %1 at %2").
00158     arg(QDate::currentDate().toString("ddd dd. MMM yyyy")).
00159     arg(QTime::currentTime().toString("hh:mm:ss:zzz"));
00160   ProgText->appendPlainText(txt + "\n");
00161 
00162   SimProcess.blockSignals(false);
00163  /* On Qt4 it shows as running even before we .start it. FIXME*/
00164   if(SimProcess.state()==QProcess::Running ||SimProcess.state()==QProcess::Starting) {
00165     qDebug() << "running!";
00166     ErrText->appendPlainText(tr("ERROR: Simulator is still running!"));
00167     FinishSimulation(-1);
00168     return false;
00169   }
00170 
00171   Collect.clear();  // clear list for NodeSets, SPICE components etc.
00172   ProgText->appendPlainText(tr("creating netlist... "));
00173   NetlistFile.setFileName(QucsSettings.QucsHomeDir.filePath("netlist.txt"));
00174    if(!NetlistFile.open(QIODevice::WriteOnly)) {
00175     ErrText->appendPlainText(tr("ERROR: Cannot write netlist file!"));
00176     FinishSimulation(-1);
00177     return false;
00178   }
00179 
00180   Stream.setDevice(&NetlistFile);
00181 
00182   if(!DocWidget->inherits("QTextEdit")) {
00183     SimPorts =
00184        ((Schematic*)DocWidget)->prepareNetlist(Stream, Collect, ErrText);
00185     if(SimPorts < -5) {
00186       NetlistFile.close();
00187       ErrText->appendPlainText(tr("ERROR: Cannot simulate a text file!"));
00188       FinishSimulation(-1);
00189       return false;
00190     }
00191   }
00192   Collect.append("*");   // mark the end
00193 
00194 
00195   disconnect(&SimProcess, 0, 0, 0);
00196   connect(&SimProcess, SIGNAL(readyReadStandardError()), SLOT(slotDisplayErr()));
00197   connect(&SimProcess, SIGNAL(readyReadStandardOutput()),
00198                        SLOT(slotReadSpiceNetlist()));
00199   connect(&SimProcess, SIGNAL(finished(int)),
00200                        SLOT(slotFinishSpiceNetlist(int)));
00201 
00202   nextSPICE();
00203   return true;
00204   // Since now, the Doc pointer may be obsolete, as the user could have
00205   // closed the schematic !!!
00206 }
00207 
00211 void SimMessage::nextSPICE()
00212 {
00213   QString Line;
00214   for(;;) {  // search for next SPICE component
00215     Line = *(Collect.begin());
00216     Collect.erase(Collect.begin());
00217     if(Line == "*") {  // worked on all components ?
00218       startSimulator(); // <<<<<================== go on ===
00219       return;
00220     }
00221 // FIXME #warning SPICE section below not being covered?
00222     qDebug() << "goin thru SPICE branch on simmmessage.cpp";
00223     if(Line.left(5) == "SPICE") {
00224       if(Line.at(5) != 'o') insertSim = true;
00225       else insertSim = false;
00226       break;
00227     }
00228     Collect.append(Line);
00229   }
00230 
00231 
00232   QString FileName = Line.section('"', 1,1);
00233   Line = Line.section('"', 2);  // port nodes
00234   if(Line.isEmpty())  makeSubcircuit = false;
00235   else  makeSubcircuit = true;
00236 
00237   QString prog;
00238   QStringList com;
00239   prog = QucsSettings.Qucsconv;
00240   if(makeSubcircuit)
00241     com << "-g" << "_ref";
00242   com << "-if" << "spice" << "-of" << "qucs";
00243 
00244   QFile SpiceFile;
00245   if(FileName.indexOf(QDir::separator()) < 0)  // add path ?
00246     SpiceFile.setFileName(QucsSettings.QucsWorkDir.path() + QDir::separator() + FileName);
00247   else
00248     SpiceFile.setFileName(FileName);
00249   if(!SpiceFile.open(QIODevice::ReadOnly)) {
00250     ErrText->appendPlainText(tr("ERROR: Cannot open SPICE file \"%1\".").arg(FileName));
00251     FinishSimulation(-1);
00252     return;
00253   }
00254 
00255   if(makeSubcircuit) {
00256     Stream << "\n.Def:" << misc::properName(FileName) << " ";
00257 
00258     Line.replace(',', ' ');
00259     Stream << Line;
00260     if(!Line.isEmpty()) Stream << " _ref";
00261   }
00262   Stream << "\n";
00263 
00264   ProgressText = "";
00265 
00266   qDebug() << "start QucsConv" << prog << com.join(" ");
00267   SimProcess.start(prog, com);
00268 
00269   if(!SimProcess.Running) {
00270     ErrText->appendPlainText(tr("SIM ERROR: Cannot start QucsConv!"));
00271     FinishSimulation(-1);
00272     return;
00273   }
00274 
00275   QByteArray SpiceContent = SpiceFile.readAll();
00276   SpiceFile.close();
00277   QString command(SpiceContent); //to convert byte array to string
00278   SimProcess.setStandardInputFile(command);  //? FIXME works?
00279   qDebug() << command;
00280   connect(&SimProcess, SIGNAL(wroteToStdin()), SLOT(slotCloseStdin()));
00281 }
00282 
00283 // ------------------------------------------------------------------------
00284 void SimMessage::slotCloseStdin()
00285 {
00286   //SimProcess.closeStdin(); //? channel not available in Qt4?
00287   disconnect(&SimProcess, SIGNAL(wroteToStdin()), 0, 0);
00288 }
00289 
00290 // ------------------------------------------------------------------------
00291 void SimMessage::slotReadSpiceNetlist()
00292 {
00293   int i;
00294   QString s;
00295   ProgressText += QString(SimProcess.readAllStandardOutput());
00296 
00297   while((i = ProgressText.indexOf('\n')) >= 0) {
00298 
00299     s = ProgressText.left(i);
00300     ProgressText.remove(0, i+1);
00301 
00302 
00303     s = s.trimmed();
00304     if(s.isEmpty()) continue;
00305     if(s.at(0) == '#') continue;
00306     if(s.at(0) == '.') if(s.left(5) != ".Def:") { // insert simulations later
00307       if(insertSim) Collect.append(s);
00308       continue;
00309     }
00310     Stream << "  " << s << '\n';
00311   }
00312 }
00313 
00314 // ------------------------------------------------------------------------
00315 void SimMessage::slotFinishSpiceNetlist(int status )
00316 {
00317   Q_UNUSED(status);
00318 
00319   if(makeSubcircuit)
00320     Stream << ".Def:End\n\n";
00321 
00322   nextSPICE();
00323 }
00324 
00325 // ------------------------------------------------------------------------
00326 #ifdef __MINGW32__
00327 #include <windows.h>
00328 static QString pathName(QString longpath) {
00329   const char * lpath = QDir::convertSeparators(longpath).ascii();
00330   char spath[2048];
00331   int len = GetShortPathNameA(lpath,spath,sizeof(spath)-1);
00332   spath[len] = '\0';
00333   return QString(spath);
00334 }
00335 #else
00336 static QString pathName(QString longpath) {
00337   return longpath;
00338 }
00339 #endif
00340 
00341 
00345 void SimMessage::startSimulator()
00346 {
00347   // Using the Doc pointer here is risky as the user may have closed
00348   // the schematic, but converting the SPICE netlists is (hopefully)
00349   // faster than the user (I have no other idea).
00350 
00351   QString SimTime;
00352   QStringList Arguments;
00353   QString SimPath = QDir::convertSeparators (QucsSettings.QucsHomeDir.absolutePath());
00354 #ifdef __MINGW32__
00355   QString QucsDigiLib = "qucsdigilib.bat";
00356   QString QucsDigi = "qucsdigi.bat";
00357   QString QucsVeri = "qucsveri.bat";
00358 #else
00359   QString QucsDigiLib = "qucsdigilib";
00360   QString QucsDigi = "qucsdigi";
00361   QString QucsVeri = "qucsveri";
00362 #endif
00363   SimOpt = NULL;
00364   bool isVerilog = false;
00365   QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
00366 
00367   // Simulate text window.
00368   if(DocWidget->inherits("QTextEdit")) {
00369 
00370     TextDoc * Doc = (TextDoc*)DocWidget;
00371 
00372     // Take VHDL file in memory as it could contain unsaved changes.
00373     Stream << Doc->toPlainText();
00374     NetlistFile.close();
00375     ProgText->insertPlainText(tr("done.\n"));  // of "creating netlist...
00376 
00377     // Simulation.
00378     if (Doc->simulation) {
00379       SimTime = Doc->SimTime;
00380       QString libs = Doc->Libraries.toLower();
00382 #ifdef __MINGW32__
00383       if(libs.isEmpty()) {
00384         libs = "";
00385       }
00386       else {
00387         libs.replace(" ",",-l");
00388         libs = "-Wl,-l" + libs;
00389       }
00390 #else
00391       if(libs.isEmpty()) {
00392         libs = "-c";
00393       }
00394       else {
00395         libs.replace(" ",",-l");
00396         libs = "-c,-l" + libs;
00397       }
00398 #endif
00399       Program = pathName(QucsSettings.BinDir + QucsDigi);
00400       Arguments  << QucsSettings.QucsHomeDir.filePath("netlist.txt")
00401                  << DataSet << SimTime << pathName(SimPath)
00402                  << pathName(QucsSettings.BinDir) << libs;
00403     }
00404     // Module.
00405     else {
00406       QString text = Doc->toPlainText();
00407       VHDL_File_Info VInfo (text);
00408       QString entity = VInfo.EntityName.toLower();
00409       QString lib = Doc->Library.toLower();
00410       if (lib.isEmpty()) lib = "work";
00411       QString dir = QDir::convertSeparators (QucsSettings.QucsHomeDir.path());
00412       QDir vhdlDir(dir);
00413       if(!vhdlDir.exists("vhdl"))
00414   if(!vhdlDir.mkdir("vhdl")) {
00415     ErrText->appendPlainText(tr("ERROR: Cannot create VHDL directory \"%1\"!")
00416         .arg(vhdlDir.path()+"/vhdl"));
00417     return;
00418   }
00419       vhdlDir.setPath(vhdlDir.path()+"/vhdl");
00420       if(!vhdlDir.exists(lib))
00421   if(!vhdlDir.mkdir(lib)) {
00422     ErrText->appendPlainText(tr("ERROR: Cannot create VHDL directory \"%1\"!")
00423         .arg(vhdlDir.path()+"/"+lib));
00424     return;
00425   }
00426       vhdlDir.setPath(vhdlDir.path()+"/"+lib);
00427       QFile destFile;
00428       destFile.setFileName(vhdlDir.filePath(entity+".vhdl"));
00429       if(!destFile.open(QIODevice::WriteOnly)) {
00430   ErrText->appendPlainText(tr("ERROR: Cannot create \"%1\"!")
00431       .arg(destFile.fileName()));
00432   return;
00433       }
00434       destFile.write(text.toAscii(), text.length());
00435       destFile.close();
00436       Program = pathName(QucsSettings.BinDir + QucsDigiLib);
00437       Arguments << QucsSettings.QucsHomeDir.filePath("netlist.txt")
00438                 << pathName(SimPath)
00439                 << entity
00440                 << lib;
00441     }
00442   }
00443   // Simulate schematic window.
00444   else {
00445     // output NodeSets, SPICE simulations etc.
00446     for(QStringList::Iterator it = Collect.begin();
00447   it != Collect.end(); ++it) {
00448       // don't put library includes into netlist...
00449       if ((*it).right(4) != ".lst" &&
00450     (*it).right(5) != ".vhdl" &&
00451     (*it).right(4) != ".vhd" &&
00452     (*it).right(2) != ".v") {
00453   Stream << *it << '\n';
00454       }
00455     }
00456     Stream << '\n';
00457 
00458     isVerilog = ((Schematic*)DocWidget)->isVerilog;
00459     SimTime = ((Schematic*)DocWidget)->createNetlist(Stream, SimPorts);
00460     if(SimTime.length()>0&&SimTime.at(0) == '\xA7') {
00461       NetlistFile.close();
00462       ErrText->insertPlainText(SimTime.mid(1));
00463       FinishSimulation(-1);
00464       return;
00465     }
00466     if (isVerilog) {
00467       Stream << "\n"
00468        << "  initial begin\n"
00469        << "    $dumpfile(\"digi.vcd\");\n"
00470        << "    $dumpvars();\n"
00471        << "    #" << SimTime << " $finish;\n"
00472        << "  end\n\n"
00473        << "endmodule // TestBench\n";
00474     }
00475     NetlistFile.close();
00476     ProgText->insertPlainText(tr("done.\n"));  // of "creating netlist...
00477 
00478     if(SimPorts < 0) {
00479 
00480       // append command arguments
00481       // append netlist with same arguments
00482       if (! Module::vaComponents.isEmpty()) {
00483 
00493           QStringList usedComponents;
00494 
00495           if (!NetlistFile.open(QIODevice::ReadOnly))
00496              QMessageBox::critical(this, tr("Error"), tr("Cannot read netlist!"));
00497           else {
00498              QString net = QString(NetlistFile.readAll());
00499 
00500              QMapIterator<QString, QString> i(Module::vaComponents);
00501              while (i.hasNext()) {
00502                  i.next();
00503                  if (net.contains(i.key()))
00504                      usedComponents << i.key();
00505              }
00506              NetlistFile.close();
00507           }
00508 
00509           if (! usedComponents.isEmpty()) {
00510 
00511 
00513             //Arguments << "-p" << QucsSettings.QucsWorkDir.absolutePath()
00514             //          << "-m" << usedComponents;
00515             //qDebug() << "Command :" << Program << Arguments.join(" ");
00516 
00519             if (!NetlistFile.open(QFile::Append | QFile::Text))
00520                QMessageBox::critical(this, tr("Error"), tr("Cannot read netlist!"));
00521             else {
00522                QTextStream out(&NetlistFile);
00523                out << "\n";
00524                out << "# --path=" << QucsSettings.QucsWorkDir.absolutePath() << "\n";
00525                out << "# --module=" << usedComponents.join(" ") << "\n";
00526 
00527                NetlistFile.close();
00528             }
00529           }
00530       } // vaComponents not empty
00531 
00532       if((SimOpt = findOptimization((Schematic*)DocWidget))) {
00533       ((Optimize_Sim*)SimOpt)->createASCOnetlist();
00534 
00535         Program = QucsSettings.AscoBinDir.canonicalPath();
00536         Program = QDir::toNativeSeparators(Program+"/"+"asco"+QString(executableSuffix));
00537         Arguments << "-qucs" << QucsSettings.QucsHomeDir.filePath("asco_netlist.txt")
00538                   << "-o" << "asco_out";
00539       }
00540       else {
00541         Program = QucsSettings.Qucsator;
00542         Arguments << "-b" << "-g" << "-i"
00543                   << QucsSettings.QucsHomeDir.filePath("netlist.txt")
00544                   << "-o" << DataSet;
00545       }
00546     }
00547     else {
00548       if (isVerilog) {
00549           Program = QDir::toNativeSeparators(QucsSettings.BinDir + QucsVeri);
00550           Arguments << QDir::toNativeSeparators(QucsSettings.QucsHomeDir.filePath("netlist.txt"))
00551                     << DataSet
00552                     << SimTime
00553                     << QDir::toNativeSeparators(SimPath)
00554                     << QDir::toNativeSeparators(QucsSettings.BinDir)
00555                     << "-c";
00556       } else {
00558 #ifdef __MINGW32__
00559     Program = QDir::toNativeSeparators(pathName(QucsSettings.BinDir + QucsDigi));
00560     Arguments << QDir::toNativeSeparators(QucsSettings.QucsHomeDir.filePath("netlist.txt"))
00561               << DataSet
00562               << SimTime
00563               << QDir::toNativeSeparators(SimPath)
00564               << QDir::toNativeSeparators(QucsSettings.BinDir) << "-Wall" << "-c";
00565 #else
00566     Program = QDir::toNativeSeparators(pathName(QucsSettings.BinDir + QucsDigi));
00567     Arguments << QucsSettings.QucsHomeDir.filePath("netlist.txt")
00568               << DataSet << SimTime << pathName(SimPath)
00569           << pathName(QucsSettings.BinDir) << "-Wall" << "-c";
00570 
00571 #endif
00572       }
00573     }
00574   }
00575 
00576   disconnect(&SimProcess, 0, 0, 0);
00577   connect(&SimProcess, SIGNAL(readyReadStandardError()), SLOT(slotDisplayErr()));
00578   connect(&SimProcess, SIGNAL(readyReadStandardOutput()), SLOT(slotDisplayMsg()));
00579   connect(&SimProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00580                        SLOT(slotSimEnded(int, QProcess::ExitStatus)));
00581   connect(&SimProcess, SIGNAL(stateChanged(QProcess::ProcessState)),
00582                        SLOT(slotStateChanged(QProcess::ProcessState)));
00583 
00584 #ifdef SPEEDUP_PROGRESSBAR
00585   waitForUpdate = false;
00586 #endif
00587   wasLF = false;
00588 
00589   ProgressText = "";
00590 
00591 #ifdef __MINGW32__
00592   QString sep(";"); // path separator
00593 #else
00594   QString sep(":");
00595 #endif
00596 
00597   // append process PATH
00598   // insert Qucs bin dir, so ASCO can find qucsator
00599   env.insert("PATH", env.value("PATH") + sep + QucsSettings.BinDir );
00600   SimProcess.setProcessEnvironment(env);
00601 
00602   qDebug() << "Command :" << Program << Arguments.join(" ");
00603   SimProcess.start(Program, Arguments); // launch the program
00604 
00605 }
00606 
00607 // ------------------------------------------------------------------------
00608 Component * SimMessage::findOptimization(Schematic *Doc) {
00609   Component *pc;
00610   for(pc=Doc->Components->first(); pc!=0; pc=Doc->Components->next())
00611     if(pc->isActive)
00612       if(pc->Model == ".Opt")
00613   return pc;
00614   return NULL;
00615 }
00616 
00617 
00621 void SimMessage::slotDisplayMsg()
00622 {
00623   int i;
00624   ProgressText += QString(SimProcess.readAllStandardOutput());
00625   if(wasLF) {
00626     i = ProgressText.lastIndexOf('\r');
00627     if(i > 1) {
00628 #ifdef SPEEDUP_PROGRESSBAR
00629       iProgress = 10*int(ProgressText.at(i-2).toLatin1()-'0') +
00630                      int(ProgressText.at(i-1).toLatin1()-'0');
00631       if(!waitForUpdate) {
00632         QTimer::singleShot(20, this, SLOT(slotUpdateProgressBar()));
00633         waitForUpdate = true;
00634       }
00635 #else
00636       SimProgress->setMaximum(100);
00637       SimProgress->setValue(
00638          10*int(ProgressText.at(i-2).toLatin1()-'0') +
00639             int(ProgressText.at(i-1).toLatin1()-'0'));
00640 #endif
00641       ProgressText.remove(0, i+1);
00642     }
00643 
00644     if(ProgressText.size()>0&&ProgressText.at(0).toLatin1() <= '\t')
00645       return;
00646   }
00647   else {
00648     i = ProgressText.indexOf('\t'); // marker for progress indicator
00649     if(i >= 0) {
00650       wasLF = true;
00651       QString tmps = ProgressText.left(i).trimmed();
00652       if (!tmps.isEmpty()) // avoid adding a newline if no text to show
00653   ProgText->appendPlainText(tmps);
00654       ProgressText.remove(0, i+1);
00655       return;
00656     }
00657   }
00658 
00659   QString tmps = ProgressText.trimmed();
00660   if (!tmps.isEmpty()) // avoid adding a newline if no text to show
00661     ProgText->appendPlainText(tmps);
00662   ProgressText = "";
00663   wasLF = false;
00664 }
00665 
00666 #ifdef SPEEDUP_PROGRESSBAR
00667 // ------------------------------------------------------------------------
00668 void SimMessage::slotUpdateProgressBar()
00669 {
00670   SimProgress->setProgress(iProgress, 100);
00671   waitForUpdate = false;
00672 }
00673 #endif
00674 
00680 void SimMessage::slotDisplayErr()
00681 {
00682   ErrText->appendPlainText(QString(SimProcess.readAllStandardError()));
00683 }
00684 
00691 void SimMessage::slotStateChanged(QProcess::ProcessState newState)
00692 {
00693   static QProcess::ProcessState oldState;
00694   qDebug() << "SimMessage::slotStateChanged() : newState = " << newState 
00695            << " " << SimProcess.error();
00696   switch(newState){
00697     case QProcess::NotRunning:
00698       switch(SimProcess.error()){
00699         case QProcess::FailedToStart: // does not happen (?)
00700         case QProcess::UnknownError: // getting here instead
00701           switch(oldState){
00702             case QProcess::Starting: // failed to start.
00703               ErrText->insertPlainText(tr("ERROR: Cannot start ") + Program +
00704                   " (" + SimProcess.errorString() + ")\n");
00705               FinishSimulation(-1);
00706               break;
00707             case QProcess::Running:
00708               // process ended without trouble.
00709               // slotSimEnded will be invoked soon.
00710               break;
00711             case QProcess::NotRunning:
00712               // impossible.
00713               break;
00714           }
00715           break;
00716         // note that on Windows negative exit codes are treated as 'crash'
00717         //   see comments in slotSimEnded() to handle this properly
00718         case QProcess::Crashed:
00719         case QProcess::Timedout:
00720         case QProcess::WriteError:
00721         case QProcess::ReadError:
00722           // nothing (yet)
00723           break;
00724       }
00725     break;
00726     case QProcess::Starting:
00727           ProgText->insertPlainText(tr("Starting ") + Program + "\n");
00728     break;
00729     case QProcess::Running:
00730     break;
00731   }
00732   oldState = newState;
00733 }
00734 
00745 void SimMessage::slotSimEnded(int exitCode, QProcess::ExitStatus exitStatus )
00746 {
00747   int stat = exitCode;
00748 
00749   if ((exitStatus != QProcess::NormalExit) &&
00750 #ifdef _WIN32
00751 // due to a bug in Qt, negative error codes are erroneously interpreted
00752 //   as "program crashed", see https://bugreports.qt.io/browse/QTBUG-28735
00753 // When we will switch to Qt5(.1) this code can be removed...
00754       (uint)stat >= 0x80000000U && (uint)stat < 0xD0000000U &&
00755 #endif
00756       !simKilled) { // as when killed by user exitStatus will be QProcess::CrashExit
00757     stat = -1;
00758     ErrText->appendPlainText(tr("ERROR: Simulator crashed!"));
00759     ErrText->appendPlainText(tr("Please report this error to qucs-bugs@lists.sourceforge.net"));
00760   }
00761   FinishSimulation(stat); // 0 = normal , !=0 = error
00762 }
00763 
00771 void SimMessage::FinishSimulation(int Status)
00772 {
00773   Abort->setText(tr("Close window"));
00774   Display->setDisabled(false);
00775   SimProgress->setValue(100);  // progress bar to 100%
00776 
00777   QDate d = QDate::currentDate();   // get date of today
00778   QTime t = QTime::currentTime();   // get time
00779 
00780   if(Status == 0) {
00781     QString txt = tr("Simulation ended on %1 at %2").
00782       arg(d.toString("ddd dd. MMM yyyy")).
00783       arg(t.toString("hh:mm:ss:zzz"));
00784     ProgText->appendPlainText("\n" + txt + "\n" + tr("Ready."));
00785   }
00786   else {
00787     QString txt = tr("Errors occurred during simulation on %1 at %2").
00788       arg(d.toString("ddd dd. MMM yyyy")).
00789       arg(t.toString("hh:mm:ss:zzz"));
00790     ProgText->appendPlainText("\n" + txt + "\n" + tr("Aborted."));
00791   }
00792 
00793   QFile file(QucsSettings.QucsHomeDir.filePath("log.txt"));  // save simulator messages
00794   if(file.open(QIODevice::WriteOnly)) {
00795     QTextStream stream(&file);
00796     stream << tr("Output:\n-------") << "\n\n";
00797     for(int z=0; z<ProgText->document()->blockCount(); z++)
00798       stream << ProgText->document()->findBlockByNumber(z).text() << "\n";
00799     stream << "\n\n\n" << 
00800       tr("Errors and Warnings:\n--------------------") << "\n\n";
00801     for(int z=0; z<ErrText->document()->blockCount(); z++)
00802       stream << ErrText->document()->findBlockByNumber(z).text() << "\n";
00803     file.close();
00804   }
00805 
00806   if(Status == 0) {
00807     if(SimOpt) { // save optimization data
00808       QFile ifile(QucsSettings.QucsHomeDir.filePath("asco_out.dat"));
00809       QFile ofile(DataSet);
00810       if(ifile.open(QIODevice::ReadOnly)) {
00811   if(ofile.open(QIODevice::WriteOnly)) {
00812     QByteArray data = ifile.readAll();
00813     ofile.write(data);
00814     ofile.close();
00815   }
00816   ifile.close();
00817       }
00818       if(((Optimize_Sim*)SimOpt)->loadASCOout())
00819   ((Schematic*)DocWidget)->setChanged(true,true);
00820     }
00821   }
00822 
00823   emit SimulationEnded(Status, this);
00824 }
00825 
00832 void SimMessage::slotClose()
00833 {
00834   accept();
00835 }
00836 
00837 // ------------------------------------------------------------------------
00838 void SimMessage::slotDisplayButton()
00839 {
00840   emit displayDataPage(DocName, DataDisplay);
00841   accept();
00842 }
00843 
00844 void SimMessage::AbortSim()
00845 {
00846   ErrText->appendPlainText(tr("Simulation aborted by the user!"));
00847   simKilled = true;
00848   SimProcess.kill();
00849 }
00850 // vim:ts=8:sw=2:et
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines