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