/*************************************************************************** main.cpp ---------- begin : Thu Aug 28 2003 copyright : (C) 2003 by Michael Margraf email : michael.margraf@alumni.tu-berlin.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*! * \file main.cpp * \brief Implementation of the main application. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include //#include #include #include #include #include #include #include "qucs.h" #include "main.h" #include "node.h" #include "printerwriter.h" #include "imagewriter.h" #include "schematic.h" #include "settings.h" #include "module.h" #include "misc.h" #include "extsimkernels/ngspice.h" #include "extsimkernels/xyce.h" #if defined(_WIN32) ||defined(__MINGW32__) #include //for OutputDebugString #endif #if defined(_WIN32) ||defined(__MINGW32__) #define executableSuffix ".exe" #else #define executableSuffix "" #endif tQucsSettings QucsSettings; QucsApp *QucsMain = nullptr; // the Qucs application itself QString lastDir; // to remember last directory for several dialogs QStringList qucsPathList; VersionTriplet QucsVersion; // Qucs version string // ######################################################################### // Loads the settings file and stores the settings. bool loadSettings() { QSettings settings("qucs","qucs_s"); QucsSettings.DefaultSimulator = _settings::Get().item("DefaultSimulator"); QucsSettings.firstRun = _settings::Get().item("firstRun"); /*** Temporarily continue to use QucsSettings to make sure all settings convert okay and remain compatible ***/ QucsSettings.font.fromString(_settings::Get().item("font")); QucsSettings.appFont.fromString(_settings::Get().item("appFont")); QucsSettings.textFont.fromString(_settings::Get().item("textFont")); QucsSettings.largeFontSize = _settings::Get().item("LargeFontSize"); QucsSettings.maxUndo = _settings::Get().item("maxUndo"); QucsSettings.NodeWiring = _settings::Get().item("NodeWiring"); QucsSettings.BGColor = _settings::Get().item("BGColor"); QucsSettings.Editor = _settings::Get().item("Editor"); QucsSettings.FileTypes = _settings::Get().item("FileTypes"); QucsSettings.Language = _settings::Get().item("Language"); // Editor syntax highlighting settings. QucsSettings.Comment = _settings::Get().item("Comment"); QucsSettings.String = _settings::Get().item("String"); QucsSettings.Integer = _settings::Get().item("Integer"); QucsSettings.Real = _settings::Get().item("Real"); QucsSettings.Character = _settings::Get().item("Character"); QucsSettings.Type = _settings::Get().item("Type"); QucsSettings.Attribute = _settings::Get().item("Attribute"); QucsSettings.Directive = _settings::Get().item("Directive"); QucsSettings.Task = _settings::Get().item("Task"); // TODO: Convert this to the new settings model. if(settings.contains("Qucsator")) { QucsSettings.Qucsator = settings.value("Qucsator").toString(); QFileInfo inf(QucsSettings.Qucsator); QucsSettings.QucsatorDir = inf.canonicalPath() + QDir::separator(); if (QucsSettings.Qucsconv.isEmpty()) QucsSettings.Qucsconv = QucsSettings.QucsatorDir + QDir::separator() + "qucsconv_rf" + executableSuffix; } else { QucsSettings.Qucsator = QucsSettings.BinDir + "qucsator_rf" + executableSuffix; QucsSettings.QucsatorDir = QucsSettings.BinDir; if (QucsSettings.Qucsconv.isEmpty()) QucsSettings.Qucsconv = QucsSettings.BinDir + "qucsconv_rf" + executableSuffix; } QucsSettings.AdmsXmlBinDir.setPath(_settings::Get().item("AdmsXmlBinDir")); QucsSettings.AscoBinDir.setPath(_settings::Get().item("AscoBinDir")); QucsSettings.NgspiceExecutable = _settings::Get().item("NgspiceExecutable"); QucsSettings.XyceExecutable = _settings::Get().item("XyceExecutable"); QucsSettings.XyceParExecutable = _settings::Get().item("XyceParExecutable"); QucsSettings.SpiceOpusExecutable = _settings::Get().item("SpiceOpusExecutable"); QucsSettings.NProcs = _settings::Get().item("Nprocs"); // TODO: Currently the default settings cannot include other settings during initialisation. This is a // problem for this setting as it needs to include the QucsWorkDir setting. Therefore, set the default to an // empty string and populate it here by brute force. QucsSettings.S4Qworkdir = _settings::Get().item("S4Q_workdir"); if (QucsSettings.S4Qworkdir == "") QucsSettings.S4Qworkdir = QDir::toNativeSeparators(QucsSettings.QucsWorkDir.absolutePath()+"/spice4qucs"); QucsSettings.SimParameters = _settings::Get().item("SimParameters"); QucsSettings.OctaveExecutable = _settings::Get().item("OctaveExecutable"); QucsSettings.OpenVAFExecutable = _settings::Get().item("OpenVAFExecutable"); QucsSettings.RFLayoutExecutable = _settings::Get().item("RFLayoutExecutable"); QucsSettings.qucsWorkspaceDir.setPath(_settings::Get().item("QucsHomeDir")); QucsSettings.QucsWorkDir = QucsSettings.qucsWorkspaceDir; QucsSettings.tempFilesDir.setPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); QucsSettings.IgnoreFutureVersion = _settings::Get().item("IgnoreVersion"); QucsSettings.GraphAntiAliasing = _settings::Get().item("GraphAntiAliasing"); QucsSettings.TextAntiAliasing = _settings::Get().item("TextAntiAliasing"); QucsSettings.fullTraceName = _settings::Get().item("fullTraceName"); QucsSettings.RecentDocs = _settings::Get().item("RecentDocs").split("*",qucs::SkipEmptyParts); QucsSettings.numRecentDocs = QucsSettings.RecentDocs.count(); QucsSettings.spiceExtensions << "*.sp" << "*.cir" << "*.spc" << "*.spi"; // If present read in the list of directory paths in which Qucs should // search for subcircuit schematics int npaths = settings.beginReadArray("Paths"); for (int i = 0; i < npaths; ++i) { settings.setArrayIndex(i); QString apath = settings.value("path").toString(); qucsPathList.append(apath); } settings.endArray(); QucsSettings.numRecentDocs = 0; return true; } // ######################################################################### // Saves the settings in the settings file. bool saveApplSettings() { QSettings settings ("qucs","qucs_s"); // Note: It is not really necessary to take the following reference, but it // arguably makes the code slightly cleaner - thoughts? To be clear: // qs.item() is identical to _settings::get().item() settingsManager& qs = _settings::Get(); qs.setItem("DefaultSimulator", QucsSettings.DefaultSimulator); qs.setItem("firstRun", false); qs.setItem("font", QucsSettings.font.toString()); qs.setItem("appFont", QucsSettings.appFont.toString()); qs.setItem("textFont", QucsSettings.textFont.toString()); if (QucsMain != nullptr) { qs.setItem("MainWindowGeometry", QucsMain->saveGeometry()); } // store LargeFontSize as a string, so it will be also human-readable in the settings file (will be a @Variant() otherwise) qs.setItem("LargeFontSize", QString::number(QucsSettings.largeFontSize)); qs.setItem("maxUndo", QucsSettings.maxUndo); qs.setItem("NodeWiring", QucsSettings.NodeWiring); qs.setItem("BGColor", QucsSettings.BGColor.name()); qs.setItem("Editor", QucsSettings.Editor); qs.setItem("FileTypes", QucsSettings.FileTypes); qs.setItem("Language", QucsSettings.Language); qs.setItem("Comment", QucsSettings.Comment.name()); qs.setItem("String", QucsSettings.String.name()); qs.setItem("Integer", QucsSettings.Integer.name()); qs.setItem("Real", QucsSettings.Real.name()); qs.setItem("Character", QucsSettings.Character.name()); qs.setItem("Type", QucsSettings.Type.name()); qs.setItem("Attribute", QucsSettings.Attribute.name()); qs.setItem("Directive", QucsSettings.Directive.name()); qs.setItem("Task", QucsSettings.Task.name()); qs.setItem("AdmsXmlBinDir", QucsSettings.AdmsXmlBinDir.canonicalPath()); qs.setItem("AscoBinDir", QucsSettings.AscoBinDir.canonicalPath()); qs.setItem("NgspiceExecutable",QucsSettings.NgspiceExecutable); qs.setItem("XyceExecutable",QucsSettings.XyceExecutable); qs.setItem("XyceParExecutable",QucsSettings.XyceParExecutable); qs.setItem("SpiceOpusExecutable",QucsSettings.SpiceOpusExecutable); qs.setItem("Qucsator",QucsSettings.Qucsator); qs.setItem("Nprocs",QucsSettings.NProcs); qs.setItem("S4Q_workdir",QucsSettings.S4Qworkdir); qs.setItem("SimParameters",QucsSettings.SimParameters); qs.setItem("OctaveExecutable",QucsSettings.OctaveExecutable); qs.setItem("OpenVAFExecutable",QucsSettings.OpenVAFExecutable); qs.setItem("QucsHomeDir", QucsSettings.qucsWorkspaceDir.canonicalPath()); qs.setItem("IgnoreVersion", QucsSettings.IgnoreFutureVersion); qs.setItem("GraphAntiAliasing", QucsSettings.GraphAntiAliasing); qs.setItem("TextAntiAliasing", QucsSettings.TextAntiAliasing); qs.setItem("fullTraceName",QucsSettings.fullTraceName); // Copy the list of directory paths in which Qucs should // search for subcircuit schematics from qucsPathList settings.remove("Paths"); settings.beginWriteArray("Paths"); int i = 0; for (QString& path: qucsPathList) { settings.setArrayIndex(i); settings.setValue("path", path); i++; } settings.endArray(); return true; } /*! * \brief qucsMessageOutput handles qDebug, qWarning, qCritical, qFatal. * \param type Message type (Qt enum) * \param msg Message * * The message handler is used to get control of the messages. * Particularly on Windows, as the messages are sent to the debugger and do not * show on the terminal. The handler could also be extended to create a log * mechanism. * * */ void qucsMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QByteArray localMsg = msg.toLocal8Bit(); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; switch (type) { case QtDebugMsg: fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function); break; case QtInfoMsg: fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function); break; case QtWarningMsg: fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function); break; case QtCriticalMsg: fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function); break; case QtFatalMsg: fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function); break; } fflush(stderr); } Schematic *openSchematic(QString schematic) { qDebug() << "*** try to load schematic :" << schematic; QFile file(schematic); // save simulator messages if(file.open(QIODevice::ReadOnly)) { file.close(); } else { fprintf(stderr, "Error: Could not load schematic %s\n", schematic.toLatin1().data()); return NULL; } // populate Modules list //Module::registerModules (); // new schematic from file Schematic *sch = new Schematic(0, schematic); // load schematic file if possible if(!sch->loadDocument()) { fprintf(stderr, "Error: Could not load schematic %s\n", schematic.toLatin1().data()); delete sch; return NULL; } return sch; } int doNetlist(QString schematic, QString netlist) { QucsSettings.DefaultSimulator = spicecompat::simQucsator; Module::registerModules(); Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } qDebug() << "*** try to write netlist :" << netlist; QStringList Collect; QPlainTextEdit *ErrText = new QPlainTextEdit(); //dummy QFile NetlistFile; QTextStream Stream; Collect.clear(); // clear list for NodeSets, SPICE components etc. NetlistFile.setFileName(netlist); if(!NetlistFile.open(QIODevice::WriteOnly)) { fprintf(stderr, "Error: Could not load netlist %s\n", netlist.toLatin1().data()); return -1; } Stream.setDevice(&NetlistFile); int SimPorts = sch->prepareNetlist(Stream, Collect, ErrText); if(SimPorts < -5) { NetlistFile.close(); QByteArray ba = netlist.toLatin1(); fprintf(stderr, "Error: Could not prepare netlist %s\n", ba.data()); /// \todo better handling for error/warnings qCritical() << ErrText->toPlainText(); return 1; } // output NodeSets, SPICE simulations etc. for(QStringList::Iterator it = Collect.begin(); it != Collect.end(); ++it) { // don't put library includes into netlist... if ((*it).right(4) != ".lst" && (*it).right(5) != ".vhdl" && (*it).right(4) != ".vhd" && (*it).right(2) != ".v") { Stream << *it << '\n'; } } Stream << '\n'; QString SimTime = sch->createNetlist(Stream, SimPorts); delete(sch); NetlistFile.close(); return 0; } int runNgspice(QString schematic, QString dataset) { QucsSettings.DefaultSimulator = spicecompat::simNgspice; Module::registerModules(); Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } Ngspice *ngspice = new Ngspice(sch); ngspice->slotSimulate(); bool ok = ngspice->waitEndOfSimulation(); if (!ok) { fprintf(stderr, "Ngspice timed out or start error!\n"); delete ngspice; return -1; } else { ngspice->convertToQucsData(dataset); } delete ngspice; return 0; } int runXyce(QString schematic, QString dataset) { QucsSettings.DefaultSimulator = spicecompat::simXyce; Module::registerModules(); Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } Xyce *xyce = new Xyce(sch); xyce->slotSimulate(); bool ok = xyce->waitEndOfSimulation(); if (!ok) { fprintf(stderr, "Xyce timed out or start error!\n"); delete xyce; return -1; } else { xyce->convertToQucsData(dataset); } delete xyce; return 0; } int doNgspiceNetlist(QString schematic, QString netlist) { QucsSettings.DefaultSimulator = spicecompat::simNgspice; Module::registerModules(); Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } Ngspice *ngspice = new Ngspice(sch); ngspice->SaveNetlist(netlist); delete ngspice; if (!QFile::exists(netlist)) return -1; else return 0; } int doXyceNetlist(QString schematic, QString netlist) { QucsSettings.DefaultSimulator = spicecompat::simXyce; Module::registerModules(); Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } Xyce *xyce = new Xyce(sch); xyce->SaveNetlist(netlist); delete xyce; if (!QFile::exists(netlist)) return -1; else return 0; } int doPrint(QString schematic, QString printFile, QString page, int dpi, QString color, QString orientation) { QucsSettings.DefaultSimulator = spicecompat::simQucsator; Schematic *sch = openSchematic(schematic); if (sch == NULL) { return 1; } sch->a_Nodes = &(sch->a_DocNodes); sch->a_Wires = &(sch->a_DocWires); sch->a_Diagrams = &(sch->a_DocDiags); sch->a_Paintings = &(sch->a_DocPaints); sch->a_Components = &(sch->a_DocComps); sch->reloadGraphs(); qDebug() << "*** try to print file :" << printFile; // determine filetype if (printFile.endsWith(".pdf")) { //initial printer PrinterWriter *Printer = new PrinterWriter(); Printer->setFitToPage(true); Printer->noGuiPrint(sch, printFile, page, dpi, color, orientation); } else { ImageWriter *Printer = new ImageWriter(""); Printer->noGuiPrint(sch, printFile, color); } return 0; } /*! * \brief createIcons Create component icons (png) from command line. */ void createIcons() { int nCats = 0, nComps = 0; if(!QDir("./bitmaps_generated").exists()){ QDir().mkdir("bitmaps_generated"); } Module::registerModules (); QStringList cats = Category::getCategories (); for (const QString& category: cats) { QList Comps; Comps = Category::getModules(category); // crash with diagrams, skip if(category == "diagrams") break; char * File; QString Name; for (Module *Mod: Comps) { if (Mod->info) { Element *e = (Mod->info) (Name, File, true); Component *c = (Component* ) e; QList Lines = c->Lines; QList Arcs = c-> Arcs; QList Rects = c-> Rects; QList Ellips = c-> Ellipses; QList Ports = c->Ports; QList Texts = c->Texts; QGraphicsScene *scene = new QGraphicsScene(); for (qucs::Line *l : Lines) { scene->addLine(l->x1, l->y1, l->x2, l->y2, l->style); } for (struct qucs::Arc *a: Arcs) { // we need an open item here; QGraphisEllipseItem draws a filled ellipse and doesn't do the job here... QPainterPath *path = new QPainterPath(); // the components do not contain the angles in degrees but in 1/16th degrees -> conversion needed path->arcMoveTo(a->x,a->y,a->w,a->h,a->angle/16); path->arcTo(a->x,a->y,a->w,a->h,a->angle/16,a->arclen/16); scene->addPath(*path); } for(qucs::Rect *a: Rects) { scene->addRect(a->x, a->y, a->w, a->h, a->Pen, a->Brush); } for(qucs::Ellips *a: Ellips) { scene->addEllipse(a->x, a->y, a->w, a->h, a->Pen, a->Brush); } for(Port *p: Ports) { scene->addEllipse(p->x-4, p->y-4, 8, 8, QPen(Qt::red)); } for(Text *t: Texts) { QFont myFont; myFont.setPointSize(10); QGraphicsTextItem* item = new QGraphicsTextItem(t->s); item->setX(t->x); item->setY(t->y); item->setFont(myFont); scene->addItem(item); } // this uses the size of the component as icon size // Qt bug ? The returned sceneRect() is often 1 px short on bottom // and right sides without anti-aliasing. 1 px more missing on top // and left when anti-aliasing is used QRectF rScene = scene->sceneRect().adjusted(-1,-1,1,1); // image and scene need to be the same size, since render() // will fill the entire image, otherwise the scaling will // introduce artifacts QSize sImage = rScene.size().toSize(); // rounding seems not to be an issue // ARGB32_Premultiplied is faster (Qt docs) //QImage image(sImage.toSize(), QImage::Format_ARGB32); QImage image(sImage, QImage::Format_ARGB32_Premultiplied); // this uses a fixed size for the icon (32 x 32) //QImage image(32, 32, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(&image); QPainter::RenderHints hints = QPainter::RenderHints(); // Ask to antialias drawings if requested if (QucsSettings.GraphAntiAliasing) hints |= QPainter::Antialiasing; // Ask to antialias text if requested if (QucsSettings.TextAntiAliasing) hints |= QPainter::TextAntialiasing; painter.setRenderHints(hints); // pass target and source size eplicitly, otherwise sceneRect() is used // for the source size, which is often wrong (see comment above) scene->render(&painter, image.rect(), rScene); image.save("./bitmaps_generated/" + QString(File) + ".png"); fprintf(stdout, "[%s] %s\n", category.toLatin1().data(), File); } nComps++; } // module nCats++; } // category fprintf(stdout, "Created %i component icons from %i categories\n", nComps, nCats); } /*! * \brief createDocData Create data used for documentation. * * It creates the following: * - list of categories: categories.txt * - category directory, ex.: ./lumped components/ * - CSV with component data fields. Ex [component#]_data.csv * - CSV with component properties. Ex [component#]_props.csv */ void createDocData() { QMap typeMap; typeMap.insert(0x30000, "Component"); typeMap.insert(0x30002, "ComponentText"); typeMap.insert(0x10000, "AnalogComponent"); typeMap.insert(0x20000, "DigitalComponent") ; Module::registerModules (); QStringList cats = Category::getCategories (); int nCats = cats.size(); QStringList catHeader; catHeader << "# Note: auto-generated file (changes will be lost on update)"; QFile file("categories.txt"); if (!file.open(QFile::WriteOnly | QFile::Text)) return; QTextStream out(&file); out << cats.join("\n"); file.close(); int nComps = 0; // table for quick reference, schematic and netlist entry for (const QString& category: cats) { QList Comps; Comps = Category::getModules(category); // \fixme, crash with diagrams, skip if(category == "diagrams") break; // one dir per category QString curDir = "./"+category+"/"; qDebug() << "Creating dir:" << curDir; if(!QDir(curDir).exists()){ QDir().mkdir(curDir); } char * File; QString Name; int num = 0; // component id inside category for (Module *Mod: Comps) { num += 1; nComps += 1; Element *e = (Mod->info) (Name, File, true); Component *c = (Component* ) e; // object info QStringList compData; compData << "# Note: auto-generated file (changes will be lost on update)"; compData << "Caption; " + Name; compData << "Description; " + c->Description; compData << "Identifier; ``" + c->Model + "``"; // backticks for reST verbatim compData << "Default name; ``" + c->Name + "``"; compData << "Type; " + typeMap.value(c->Type); compData << "Bitmap file; " + QString(File); compData << "Properties; " + QString::number(c->Props.count()); compData << "Category; " + category; // 001_data.csv - CSV file with component data QString ID = QStringLiteral("%1").arg(num,3,'d',0,'0'); QString objDataFile; objDataFile = QStringLiteral("%1_data.csv").arg( ID ) ; QFile file(curDir + objDataFile); if (!file.open(QFile::WriteOnly | QFile::Text)) return; QTextStream out(&file); out << compData.join("\n"); file.close(); fprintf(stdout, "[%s] %s %s \n", category.toLatin1().data(), c->Model.toLatin1().data(), file.fileName().toLatin1().data()); QStringList compProps; compProps << "# Note: auto-generated file (changes will be lost on update)"; compProps << QStringLiteral("# %1; %2; %3; %4").arg( "Name", "Value", "Display", "Description"); for (Property *prop : c->Props) { compProps << QStringLiteral("%1; \"%2\"; %3; \"%4\"").arg( prop->Name, prop->Value, prop->display?"yes":"no", prop->Description.replace("\"","\"\"")); // escape quote in quote } // 001_props.csv - CSV file with component properties QString objPropFile = QStringLiteral("%1_prop.csv").arg( ID ) ; QFile fileProps(curDir + objPropFile ); if (!fileProps.open(QFile::WriteOnly | QFile::Text)) return; QTextStream outProps(&fileProps); outProps << compProps.join("\n"); compProps.clear(); file.close(); fprintf(stdout, "[%s] %s %s \n", category.toLatin1().data(), c->Model.toLatin1().data(), fileProps.fileName().toLatin1().data()); } // module } // category fprintf(stdout, "Created data for %i components from %i categories\n", nComps, nCats); } /*! * \brief createListNetEntry prints to stdout the available netlist formats * * Prints the default component entries format for: * - Qucs schematic * - Qucsator netlist */ void createListComponentEntry(){ Module::registerModules (); QStringList cats = Category::getCategories (); // table for quick reference, schematic and netlist entry for (QString category: cats) { QList Comps; Comps = Category::getModules(category); // \fixme, crash with diagrams, skip if(category == "diagrams") break; char * File; QString Name; for (Module *Mod: Comps) { Element *e = (Mod->info) (Name, File, true); Component *c = (Component* ) e; QString qucsEntry = c->save(); fprintf(stdout, "%s; qucs ; %s\n", c->Model.toLatin1().data(), qucsEntry.toLatin1().data()); // add dummy ports/wires, avoid segfault int port = 0; for (Port *p: c->Ports) { Node *n = new Node(0,0); n->Name="_net"+QString::number(port); p->Connection = n; port +=1; } // skip Subcircuit, segfault, there is nothing to netlist if (c->Model == "Sub" or c->Model == ".Opt") { fprintf(stdout, "WARNING, qucsator netlist not generated for %s\n\n", c->Model.toLatin1().data()); continue; } QString qucsatorEntry = c->getNetlist(); fprintf(stdout, "%s; qucsator; %s\n", c->Model.toLatin1().data(), qucsatorEntry.toLatin1().data()); } // module } // category } // ######################################################################### // ########## ########## // ########## Program Start ########## // ########## ########## // ######################################################################### int main(int argc, char *argv[]) { qInstallMessageHandler(qucsMessageOutput); // set the Qucs version string QucsVersion = VersionTriplet(PACKAGE_VERSION); // apply default settings //QucsSettings.font = QFont("Helvetica", 12); QucsSettings.largeFontSize = 16.0; QucsSettings.maxUndo = 20; QucsSettings.NodeWiring = 0; #if QT_VERSION < 0x060000 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling,true); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps,true); #endif // initially center the application QApplication a(argc, argv); //QDesktopWidget *d = a.desktop(); QucsSettings.font = QApplication::font(); QucsSettings.appFont = QApplication::font(); QucsSettings.textFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); QucsSettings.font.setPointSize(12); // default QString QucsWorkdirPath = QDir::homePath()+QDir::toNativeSeparators ("/QucsWorkspace"); QucsSettings.qucsWorkspaceDir.setPath(QucsWorkdirPath); QucsSettings.QucsWorkDir.setPath(QucsSettings.qucsWorkspaceDir.canonicalPath()); // load existing settings (if any) loadSettings(); /* restore saved style */ QString savedStyle = _settings::Get().item("AppStyle"); QStyle* style = QStyleFactory::create(savedStyle); if (style) { QApplication::setStyle(style); } /* restore saved style */ QDir().mkpath(QucsSettings.qucsWorkspaceDir.absolutePath()); QDir().mkpath(QucsSettings.tempFilesDir.absolutePath()); // continue to set up overrides or default settings (some are saved on exit) // check for relocation env variable QDir QucsDir; QString QucsApplicationPath = QCoreApplication::applicationDirPath(); #ifdef __APPLE__ QucsDir = QDir(QucsApplicationPath.section("/bin",0,0)); #else QucsDir = QDir(QucsApplicationPath); QucsDir.cdUp(); #endif QucsSettings.BinDir = QucsDir.absolutePath() + "/bin/"; QucsSettings.LangDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/lang/"; QucsSettings.LibDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/library/"; QucsSettings.OctaveDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/octave/"; QucsSettings.ExamplesDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/examples/"; QucsSettings.DocDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/docs/"; QucsSettings.Editor = "qucs"; /// \todo Make the setting up of all executables below more consistent char *var = NULL; // Don't use QUCSDIR with Qucs-S var = getenv("QUCSATOR"); if(var != NULL) { QucsSettings.QucsatorVar = QString(var); } else { QucsSettings.QucsatorVar = ""; } var = getenv("QUCSCONV"); if(var != NULL) { QucsSettings.Qucsconv = QString(var); } var = getenv("ADMSXMLBINDIR"); if(var != NULL) { QucsSettings.AdmsXmlBinDir.setPath(QString(var)); } else { // default admsXml bindir same as Qucs QString admsExec; #if defined(_WIN32) || defined(__MINGW32__) admsExec = QDir::toNativeSeparators(QucsSettings.BinDir+"/"+"admsXml.exe"); #else admsExec = QDir::toNativeSeparators(QucsSettings.BinDir+"/"+"admsXml"); #endif QFile adms(admsExec); if(adms.exists()) QucsSettings.AdmsXmlBinDir.setPath(QucsSettings.BinDir); } var = getenv("ASCOBINDIR"); if(var != NULL) { QucsSettings.AscoBinDir.setPath(QString(var)); } else { // default ASCO bindir same as Qucs QString ascoExec; #if defined(_WIN32) || defined(__MINGW32__) ascoExec = QDir::toNativeSeparators(QucsSettings.BinDir+"/"+"asco.exe"); #else ascoExec = QDir::toNativeSeparators(QucsSettings.BinDir+"/"+"asco"); #endif QFile asco(ascoExec); if(asco.exists()) QucsSettings.AscoBinDir.setPath(QucsSettings.BinDir); } var = getenv("QUCS_OCTAVE"); if (var != NULL) { QucsSettings.QucsOctave = QString(var); } else { QucsSettings.QucsOctave.clear(); } if(!QucsSettings.BGColor.isValid()) QucsSettings.BGColor.setRgb(255, 250, 225); // syntax highlighting if(!QucsSettings.Comment.isValid()) QucsSettings.Comment = Qt::gray; if(!QucsSettings.String.isValid()) QucsSettings.String = Qt::red; if(!QucsSettings.Integer.isValid()) QucsSettings.Integer = Qt::blue; if(!QucsSettings.Real.isValid()) QucsSettings.Real = Qt::darkMagenta; if(!QucsSettings.Character.isValid()) QucsSettings.Character = Qt::magenta; if(!QucsSettings.Type.isValid()) QucsSettings.Type = Qt::darkRed; if(!QucsSettings.Attribute.isValid()) QucsSettings.Attribute = Qt::darkCyan; if(!QucsSettings.Directive.isValid()) QucsSettings.Directive = Qt::darkCyan; if(!QucsSettings.Task.isValid()) QucsSettings.Task = Qt::darkRed; QucsSettings.sysDefaultFont = QApplication::font(); QApplication::setFont(QucsSettings.appFont); QTranslator tor( 0 ); QString lang = QucsSettings.Language; if(lang.isEmpty()) { QLocale loc; lang = loc.name(); // lang = QTextCodec::locale(); } tor.load( QStringLiteral("qucs_") + lang, QucsSettings.LangDir); QApplication::installTranslator( &tor ); // This seems to be necessary on a few system to make strtod() // work properly !???! setlocale (LC_NUMERIC, "C"); QString inputfile; QString outputfile; bool netlist_flag = false; bool print_flag = false; bool ngspice_flag = false; bool xyce_flag = false; bool run_flag = false; QString page = "A4"; int dpi = 96; QString color = "RGB"; QString orientation = "portraid"; // simple command line parser for (int i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { fprintf(stdout, "Usage: %s [-hv] \n" " qucs -n -i FILENAME -o FILENAME\n" " qucs -p -i FILENAME -o FILENAME.[pdf|png|svg|eps] \n\n" " -h, --help display this help and exit\n" " -v, --version display version information and exit\n" " -n, --netlist convert Qucs schematic into netlist\n" " -p, --print print Qucs schematic to file (eps needs inkscape)\n" " --page [A4|A3|B4|B5] set print page size (default A4)\n" " --dpi NUMBER set dpi value (default 96)\n" " --color [RGB|RGB] set color mode (default RGB)\n" " --orin [portraid|landscape] set orientation (default portraid)\n" " -i FILENAME use file as input schematic\n" " -o FILENAME use file as output netlist\n" " --ngspice create Ngspice netlist\n" " --xyce Xyce netlist\n" " --run execute Ngspice/Xyce immediately\n" " -icons create component icons under ./bitmaps_generated\n" " -doc dump data for documentation:\n" " * file with of categories: categories.txt\n" " * one directory per category (e.g. ./lumped components/)\n" " - CSV file with component data ([comp#]_data.csv)\n" " - CSV file with component properties. ([comp#]_props.csv)\n" " -list-entries list component entry formats for schematic and netlist\n" , argv[0]); return 0; } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { #ifdef GIT fprintf(stdout, "qucs s" PACKAGE_VERSION " (" GIT ")" "\n"); #else fprintf(stdout, "Qucs " PACKAGE_VERSION "\n"); #endif return 0; } else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--netlist")) { netlist_flag = true; } else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--print")) { print_flag = true; } else if (!strcmp(argv[i], "--page")) { page = argv[++i]; } else if (!strcmp(argv[i], "--dpi")) { dpi = QString(argv[++i]).toInt(); } else if (!strcmp(argv[i], "--color")) { color = argv[++i]; } else if (!strcmp(argv[i], "--orin")) { orientation = argv[++i]; } else if (!strcmp(argv[i], "-i")) { inputfile = argv[++i]; } else if (!strcmp(argv[i], "-o")) { outputfile = argv[++i]; } else if (!strcmp(argv[i], "--ngspice")) { ngspice_flag = true; } else if (!strcmp(argv[i], "--xyce")) { xyce_flag = true; } else if (!strcmp(argv[i], "--run")) { run_flag = true; } else if(!strcmp(argv[i], "-icons")) { createIcons(); return 0; } else if(!strcmp(argv[i], "-doc")) { createDocData(); return 0; } else if(!strcmp(argv[i], "-list-entries")) { createListComponentEntry(); return 0; } else { fprintf(stderr, "Error: Unknown option: %s\n", argv[i]); return -1; } } // check operation and its required arguments if (netlist_flag and print_flag) { fprintf(stderr, "Error: --print and --netlist cannot be used together\n"); return -1; } else if (((ngspice_flag||xyce_flag) && print_flag)|| (run_flag && print_flag)) { fprintf(stderr, "Error: --print and Ngspice/Xyce cannot be used together\n"); return -1; } else if (netlist_flag or print_flag) { if (inputfile.isEmpty()) { fprintf(stderr, "Error: Expected input file.\n"); return -1; } if (outputfile.isEmpty()) { fprintf(stderr, "Error: Expected output file.\n"); return -1; } // create netlist from schematic if (netlist_flag) { if (!run_flag) { if (ngspice_flag) return doNgspiceNetlist(inputfile, outputfile); else if (xyce_flag) return doXyceNetlist(inputfile, outputfile); else return doNetlist(inputfile, outputfile); } else { if (ngspice_flag) return runNgspice(inputfile, outputfile); else if (xyce_flag) return runXyce(inputfile, outputfile); else return 1; } } else if (print_flag) { return doPrint(inputfile, outputfile, page, dpi, color, orientation); } } QucsMain = new QucsApp(); //1a.setMainWidget(QucsMain); QucsMain->show(); int result = a.exec(); //saveApplSettings(QucsMain); return result; }