qucs_s/qucs/main.cpp

1072 lines
38 KiB
C++
Raw Normal View History

2003-10-15 21:32:36 +00:00
/***************************************************************************
2005-06-23 06:06:40 +00:00
main.cpp
----------
begin : Thu Aug 28 2003
2003-10-15 21:32:36 +00:00
copyright : (C) 2003 by Michael Margraf
2004-06-12 12:35:04 +00:00
email : michael.margraf@alumni.tu-berlin.de
2003-10-15 21:32:36 +00:00
***************************************************************************/
/***************************************************************************
* *
* 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.
*/
2003-10-15 21:32:36 +00:00
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
2014-01-31 16:59:40 +00:00
#include <stdlib.h>
#include <ctype.h>
#include <locale.h>
2004-11-06 16:29:51 +00:00
#include <QApplication>
#include <QString>
#include <QStringList>
#include <QTextCodec>
#include <QTranslator>
#include <QFile>
#include <QMessageBox>
#include <QRegExp>
2014-09-27 14:54:24 +09:00
#include <QtSvg>
2003-10-15 21:32:36 +00:00
#include "qucs.h"
#include "main.h"
#include "node.h"
2014-11-25 00:23:22 +08:00
#include "printerwriter.h"
2014-11-25 00:31:33 +08:00
#include "imagewriter.h"
2004-05-25 19:10:00 +00:00
#include "schematic.h"
#include "module.h"
#include "misc.h"
#include "components/components.h"
#include "extsimkernels/ngspice.h"
#include "extsimkernels/xyce.h"
#ifdef _WIN32
#include <windows.h> //for OutputDebugString
#endif
#ifdef __MINGW32__
#define executableSuffix ".exe"
#else
#define executableSuffix ""
#endif
tQucsSettings QucsSettings;
QucsApp *QucsMain = 0; // the Qucs application itself
2006-07-03 06:02:08 +00:00
QString lastDir; // to remember last directory for several dialogs
QStringList qucsPathList;
VersionTriplet QucsVersion; // Qucs version string
2004-05-25 19:10:00 +00:00
// #########################################################################
// Loads the settings file and stores the settings.
bool loadSettings()
{
QSettings settings("qucs","qucs_s");
if(settings.contains("DefaultSimulator"))
QucsSettings.DefaultSimulator = settings.value("DefaultSimulator").toInt();
else QucsSettings.DefaultSimulator = spicecompat::simNotSpecified;
if(settings.contains("x"))QucsSettings.x=settings.value("x").toInt();
if(settings.contains("y"))QucsSettings.y=settings.value("y").toInt();
if(settings.contains("dx"))QucsSettings.dx=settings.value("dx").toInt();
if(settings.contains("dy"))QucsSettings.dy=settings.value("dy").toInt();
if(settings.contains("font"))QucsSettings.font.fromString(settings.value("font").toString());
if(settings.contains("LargeFontSize"))QucsSettings.largeFontSize=settings.value("LargeFontSize").toDouble(); // use toDouble() as it can interpret the string according to the current locale
if(settings.contains("maxUndo"))QucsSettings.maxUndo=settings.value("maxUndo").toInt();
if(settings.contains("NodeWiring"))QucsSettings.NodeWiring=settings.value("NodeWiring").toInt();
if(settings.contains("BGColor"))QucsSettings.BGColor.setNamedColor(settings.value("BGColor").toString());
if(settings.contains("Editor"))QucsSettings.Editor=settings.value("Editor").toString();
if(settings.contains("FileTypes"))QucsSettings.FileTypes=settings.value("FileTypes").toStringList();
if(settings.contains("Language"))QucsSettings.Language=settings.value("Language").toString();
if(settings.contains("Comment"))QucsSettings.Comment.setNamedColor(settings.value("Comment").toString());
if(settings.contains("String"))QucsSettings.String.setNamedColor(settings.value("String").toString());
if(settings.contains("Integer"))QucsSettings.Integer.setNamedColor(settings.value("Integer").toString());
if(settings.contains("Real"))QucsSettings.Real.setNamedColor(settings.value("Real").toString());
if(settings.contains("Character"))QucsSettings.Character.setNamedColor(settings.value("Character").toString());
if(settings.contains("Type"))QucsSettings.Type.setNamedColor(settings.value("Type").toString());
if(settings.contains("Attribute"))QucsSettings.Attribute.setNamedColor(settings.value("Attribute").toString());
if(settings.contains("Directive"))QucsSettings.Directive.setNamedColor(settings.value("Directive").toString());
if(settings.contains("Task"))QucsSettings.Task.setNamedColor(settings.value("Task").toString());
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" + executableSuffix;
} else {
QucsSettings.Qucsator = QucsSettings.BinDir + "qucsator" + executableSuffix;
QucsSettings.QucsatorDir = QucsSettings.BinDir;
if (QucsSettings.Qucsconv.isEmpty())
QucsSettings.Qucsconv = QucsSettings.BinDir + "qucsconv" + executableSuffix;
}
//if(settings.contains("BinDir"))QucsSettings.BinDir = settings.value("BinDir").toString();
//if(settings.contains("LangDir"))QucsSettings.LangDir = settings.value("LangDir").toString();
//if(settings.contains("LibDir"))QucsSettings.LibDir = settings.value("LibDir").toString();
if(settings.contains("AdmsXmlBinDir"))QucsSettings.AdmsXmlBinDir = settings.value("AdmsXmlBinDir").toString();
if(settings.contains("AscoBinDir"))QucsSettings.AscoBinDir = settings.value("AscoBinDir").toString();
//if(settings.contains("OctaveDir"))QucsSettings.OctaveDir = settings.value("OctaveDir").toString();
//if(settings.contains("ExamplesDir"))QucsSettings.ExamplesDir = settings.value("ExamplesDir").toString();
//if(settings.contains("DocDir"))QucsSettings.DocDir = settings.value("DocDir").toString();
if(settings.contains("NgspiceExecutable")) QucsSettings.NgspiceExecutable = settings.value("NgspiceExecutable").toString();
else QucsSettings.NgspiceExecutable = "ngspice";
if(settings.contains("XyceExecutable")) QucsSettings.XyceExecutable = settings.value("XyceExecutable").toString();
else {
#ifdef Q_OS_WIN
QucsSettings.XyceExecutable = "Xyce.exe";
#else
QucsSettings.XyceExecutable = "/usr/local/Xyce-Release-6.8.0-OPENSOURCE/bin/Xyce";
#endif
}
2015-04-26 11:07:00 +03:00
if(settings.contains("XyceParExecutable")) QucsSettings.XyceParExecutable = settings.value("XyceParExecutable").toString();
else QucsSettings.XyceParExecutable = "mpirun -np %p /usr/local/Xyce-Release-6.8.0-OPENMPI-OPENSOURCE/bin/Xyce";
if(settings.contains("SpiceOpusExecutable")) QucsSettings.SpiceOpusExecutable = settings.value("SpiceOpusExecutable").toString();
else QucsSettings.SpiceOpusExecutable = "spiceopus";
2015-04-26 11:07:00 +03:00
if(settings.contains("Nprocs")) QucsSettings.NProcs = settings.value("Nprocs").toInt();
else QucsSettings.NProcs = 4;
2015-07-12 15:39:48 +03:00
if(settings.contains("S4Q_workdir")) QucsSettings.S4Qworkdir = settings.value("S4Q_workdir").toString();
2022-02-16 22:01:45 +01:00
else QucsSettings.S4Qworkdir = QDir::toNativeSeparators(QucsSettings.QucsWorkDir.absolutePath()+"/spice4qucs");
if(settings.contains("SimParameters")) QucsSettings.SimParameters = settings.value("SimParameters").toString();
else QucsSettings.SimParameters = "";
if(settings.contains("OctaveExecutable")) {
QucsSettings.OctaveExecutable = settings.value("OctaveExecutable").toString();
} else {
if(settings.contains("OctaveBinDir")) {
QucsSettings.OctaveExecutable = settings.value("OctaveBinDir").toString() +
QDir::separator() + "octave" + QString(executableSuffix);
} else QucsSettings.OctaveExecutable = "octave" + QString(executableSuffix);
}
if(settings.contains("QucsHomeDir"))
if(settings.value("QucsHomeDir").toString() != "")
QucsSettings.QucsHomeDir.setPath(settings.value("QucsHomeDir").toString());
QucsSettings.QucsWorkDir = QucsSettings.QucsHomeDir;
if (settings.contains("IgnoreVersion")) QucsSettings.IgnoreFutureVersion = settings.value("IgnoreVersion").toBool();
// check also for old setting name with typo...
else if (settings.contains("IngnoreVersion")) QucsSettings.IgnoreFutureVersion = settings.value("IngnoreVersion").toBool();
else QucsSettings.IgnoreFutureVersion = false;
if (settings.contains("GraphAntiAliasing")) QucsSettings.GraphAntiAliasing = settings.value("GraphAntiAliasing").toBool();
else QucsSettings.GraphAntiAliasing = false;
if (settings.contains("TextAntiAliasing")) QucsSettings.TextAntiAliasing = settings.value("TextAntiAliasing").toBool();
else QucsSettings.TextAntiAliasing = false;
2013-11-08 15:26:22 +04:00
2013-11-08 19:28:40 +04:00
QucsSettings.RecentDocs = settings.value("RecentDocs").toString().split("*",QString::SkipEmptyParts);
QucsSettings.numRecentDocs = QucsSettings.RecentDocs.count();
2013-11-08 15:26:22 +04:00
QucsSettings.spiceExtensions << "*.sp" << "*.cir" << "*.spc" << "*.spi";
// If present read in the list of directory paths in which Qucs should
2013-10-01 12:04:31 +01:00
// search for subcircuit schematics
int npaths = settings.beginReadArray("Paths");
for (int i = 0; i < npaths; ++i)
{
2013-10-01 12:04:31 +01:00
settings.setArrayIndex(i);
QString apath = settings.value("path").toString();
qucsPathList.append(apath);
}
2013-10-01 12:04:31 +01:00
settings.endArray();
2013-11-08 15:26:22 +04:00
QucsSettings.numRecentDocs = 0;
return true;
2004-05-25 19:10:00 +00:00
}
// #########################################################################
// Saves the settings in the settings file.
bool saveApplSettings()
2004-05-25 19:10:00 +00:00
{
QSettings settings ("qucs","qucs_s");
settings.setValue("DefaultSimulator", QucsSettings.DefaultSimulator);
settings.setValue("x", QucsSettings.x);
settings.setValue("y", QucsSettings.y);
settings.setValue("dx", QucsSettings.dx);
settings.setValue("dy", QucsSettings.dy);
settings.setValue("font", QucsSettings.font.toString());
// store LargeFontSize as a string, so it will be also human-readable in the settings file (will be a @Variant() otherwise)
settings.setValue("LargeFontSize", QString::number(QucsSettings.largeFontSize));
settings.setValue("maxUndo", QucsSettings.maxUndo);
settings.setValue("NodeWiring", QucsSettings.NodeWiring);
settings.setValue("BGColor", QucsSettings.BGColor.name());
settings.setValue("Editor", QucsSettings.Editor);
settings.setValue("FileTypes", QucsSettings.FileTypes);
settings.setValue("Language", QucsSettings.Language);
settings.setValue("Comment", QucsSettings.Comment.name());
settings.setValue("String", QucsSettings.String.name());
settings.setValue("Integer", QucsSettings.Integer.name());
settings.setValue("Real", QucsSettings.Real.name());
settings.setValue("Character", QucsSettings.Character.name());
settings.setValue("Type", QucsSettings.Type.name());
settings.setValue("Attribute", QucsSettings.Attribute.name());
settings.setValue("Directive", QucsSettings.Directive.name());
settings.setValue("Task", QucsSettings.Task.name());
//settings.setValue("Qucsator", QucsSettings.Qucsator);
//settings.setValue("BinDir", QucsSettings.BinDir);
//settings.setValue("LangDir", QucsSettings.LangDir);
//settings.setValue("LibDir", QucsSettings.LibDir);
settings.setValue("AdmsXmlBinDir", QucsSettings.AdmsXmlBinDir.canonicalPath());
settings.setValue("AscoBinDir", QucsSettings.AscoBinDir.canonicalPath());
//settings.setValue("OctaveDir", QucsSettings.OctaveDir);
//settings.setValue("ExamplesDir", QucsSettings.ExamplesDir);
//settings.setValue("DocDir", QucsSettings.DocDir);
2016-11-05 17:54:15 +03:00
//settings.setValue("OctaveBinDir", QucsSettings.OctaveBinDir.canonicalPath());
settings.setValue("NgspiceExecutable",QucsSettings.NgspiceExecutable);
settings.setValue("XyceExecutable",QucsSettings.XyceExecutable);
2015-04-26 11:07:00 +03:00
settings.setValue("XyceParExecutable",QucsSettings.XyceParExecutable);
settings.setValue("SpiceOpusExecutable",QucsSettings.SpiceOpusExecutable);
settings.setValue("Qucsator",QucsSettings.Qucsator);
2015-04-26 11:07:00 +03:00
settings.setValue("Nprocs",QucsSettings.NProcs);
2015-07-12 15:39:48 +03:00
settings.setValue("S4Q_workdir",QucsSettings.S4Qworkdir);
settings.setValue("SimParameters",QucsSettings.SimParameters);
// settings.setValue("OctaveBinDir", QucsSettings.OctaveBinDir.canonicalPath());
settings.setValue("OctaveExecutable",QucsSettings.OctaveExecutable);
settings.setValue("QucsHomeDir", QucsSettings.QucsHomeDir.canonicalPath());
settings.setValue("IgnoreVersion", QucsSettings.IgnoreFutureVersion);
settings.setValue("GraphAntiAliasing", QucsSettings.GraphAntiAliasing);
settings.setValue("TextAntiAliasing", QucsSettings.TextAntiAliasing);
// Copy the list of directory paths in which Qucs should
// search for subcircuit schematics from qucsPathList
2013-10-01 12:04:31 +01:00
settings.remove("Paths");
settings.beginWriteArray("Paths");
int i = 0;
foreach(QString path, qucsPathList) {
settings.setArrayIndex(i);
settings.setValue("path", path);
i++;
}
settings.endArray();
2004-05-25 19:10:00 +00:00
return true;
2004-05-25 19:10:00 +00:00
}
/*!
* \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.
* Particulary on Windows, as the messages are sent to the debugger and do not
* show on the terminal. The handler could aslo be extended to create a log
* mechanism.
* <http://qt-project.org/doc/qt-4.8/debug.html#warning-and-debugging-messages>
* <http://qt-project.org/doc/qt-4.8/qtglobal.html#qInstallMsgHandler>
*/
void qucsMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &str)
{
const char *msg = str.toUtf8().data();
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s\n", msg);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s\n", msg);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s\n", msg);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s\n", msg);
case QtInfoMsg:
fprintf(stderr,"Info %s\n", msg);
abort();
}
#ifdef _WIN32
OutputDebugStringA(msg);
#endif
}
2014-09-10 21:56:13 +09:00
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());
2014-09-10 21:56:13 +09:00
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;
2014-09-10 21:56:13 +09:00
return NULL;
}
return sch;
}
int doNetlist(QString schematic, QString netlist)
{
QucsSettings.DefaultSimulator = spicecompat::simQucsator;
2014-09-10 21:56:13 +09:00
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);
2014-09-10 21:56:13 +09:00
delete(sch);
NetlistFile.close();
return 0;
}
int runNgspice(QString schematic, QString dataset)
{
QucsSettings.DefaultSimulator = spicecompat::simNgspice;
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::simXyceSer;
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;
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::simXyceSer;
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;
}
2014-09-27 11:44:10 +09:00
int doPrint(QString schematic, QString printFile,
QString page, int dpi, QString color, QString orientation)
2014-09-10 21:56:13 +09:00
{
QucsSettings.DefaultSimulator = spicecompat::simQucsator;
2014-09-10 21:56:13 +09:00
Schematic *sch = openSchematic(schematic);
if (sch == NULL) {
return 1;
}
sch->Nodes = &(sch->DocNodes);
sch->Wires = &(sch->DocWires);
sch->Diagrams = &(sch->DocDiags);
sch->Paintings = &(sch->DocPaints);
sch->Components = &(sch->DocComps);
sch->reloadGraphs();
2014-09-10 21:56:13 +09:00
qDebug() << "*** try to print file :" << printFile;
2014-09-27 11:44:10 +09:00
// determine filetype
if (printFile.endsWith(".pdf")) {
//initial printer
2014-11-25 00:23:22 +08:00
PrinterWriter *Printer = new PrinterWriter();
Printer->setFitToPage(true);
Printer->noGuiPrint(sch, printFile, page, dpi, color, orientation);
2014-09-27 11:44:10 +09:00
} else {
2015-03-24 11:46:36 +03:00
ImageWriter *Printer = new ImageWriter("");
2014-11-25 00:31:33 +08:00
Printer->noGuiPrint(sch, printFile, color);
2014-09-10 21:56:13 +09:00
}
return 0;
}
2014-12-01 16:12:51 +01:00
/*!
* \brief createIcons Create component icons (png) from command line.
*/
void createIcons() {
2004-06-26 07:05:47 +00:00
int nCats = 0, nComps = 0;
2014-12-01 16:12:51 +01:00
if(!QDir("./bitmaps_generated").exists()){
QDir().mkdir("bitmaps_generated");
}
Module::registerModules ();
2014-12-01 16:12:51 +01:00
QStringList cats = Category::getCategories ();
foreach(QString category, cats) {
QList<Module *> Comps;
Comps = Category::getModules(category);
// crash with diagrams, skip
if(category == "diagrams") break;
2014-12-01 16:12:51 +01:00
char * File;
QString Name;
foreach (Module *Mod, Comps) {
if (Mod->info) {
2014-12-01 16:12:51 +01:00
Element *e = (Mod->info) (Name, File, true);
2014-12-01 16:12:51 +01:00
Component *c = (Component* ) e;
QList<qucs::Line *> Lines = c->Lines;
QList<struct qucs::Arc *> Arcs = c-> Arcs;
QList<qucs::Area *> Rects = c-> Rects;
QList<qucs::Area *> Ellips = c-> Ellips;
2014-12-01 16:12:51 +01:00
QList<Port *> Ports = c->Ports;
QList<Text*> Texts = c->Texts;
QGraphicsScene *scene = new QGraphicsScene();
foreach (qucs::Line *l, Lines) {
2014-12-01 16:12:51 +01:00
scene->addLine(l->x1, l->y1, l->x2, l->y2, l->style);
}
2014-12-01 16:12:51 +01:00
foreach(struct qucs::Arc *a, Arcs) {
2014-12-01 16:12:51 +01:00
// 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);
}
foreach(qucs::Area *a, Rects) {
2014-12-01 16:12:51 +01:00
scene->addRect(a->x, a->y, a->w, a->h, a->Pen, a->Brush);
}
foreach(qucs::Area *a, Ellips) {
2014-12-01 16:12:51 +01:00
scene->addEllipse(a->x, a->y, a->w, a->h, a->Pen, a->Brush);
}
foreach(Port *p, Ports) {
scene->addEllipse(p->x-4, p->y-4, 8, 8, QPen(Qt::red));
2014-12-01 16:12:51 +01:00
}
foreach(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);
2014-12-01 16:12:51 +01:00
}
// 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);
2014-12-01 16:12:51 +01:00
// 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 = 0;
// 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);
2014-12-01 16:12:51 +01:00
image.save("./bitmaps_generated/" + QString(File) + ".png");
fprintf(stdout, "[%s] %s\n", category.toLatin1().data(), File);
2014-12-01 16:12:51 +01:00
}
nComps++;
2014-12-01 16:12:51 +01:00
} // module
nCats++;
2014-12-01 16:12:51 +01:00
} // 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<int, QString> 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
foreach(QString category, cats) {
QList<Module *> 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; // compoment id inside category
foreach (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 = QString("%1").arg(num,3,'d',0,'0');
QString objDataFile;
objDataFile = QString("%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 << QString("# %1; %2; %3; %4").arg( "Name", "Value", "Display", "Description");
foreach(Property *prop, c->Props) {
compProps << QString("%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 = QString("%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
foreach(QString category, cats) {
QList<Module *> Comps;
Comps = Category::getModules(category);
// \fixme, crash with diagrams, skip
if(category == "diagrams") break;
char * File;
QString Name;
foreach (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;
foreach (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
}
2004-05-25 19:10:00 +00:00
// #########################################################################
// ########## ##########
// ########## Program Start ##########
// ########## ##########
// #########################################################################
2003-10-15 21:32:36 +00:00
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;
// initially center the application
QApplication a(argc, argv);
QDesktopWidget *d = a.desktop();
QucsSettings.font = QApplication::font();
QucsSettings.font.setPointSize(12);
int w = d->width();
int h = d->height();
QucsSettings.x = w/8;
QucsSettings.y = h/8;
QucsSettings.dx = w*3/4;
QucsSettings.dy = h*3/4;
// default
QucsSettings.QucsHomeDir.setPath(QDir::homePath()+QDir::toNativeSeparators ("/.qucs"));
QucsSettings.QucsWorkDir.setPath(QucsSettings.QucsHomeDir.canonicalPath());
// load existing settings (if any)
loadSettings();
// continue to set up overrides or default settings (some are saved on exit)
// check for relocation env variable
QDir QucsDir;
2017-10-20 17:46:44 +03:00
QString QucsApplicationPath = QCoreApplication::applicationDirPath();
#ifdef __APPLE__
QucsDir = QDir(QucsApplicationPath.section("/bin",0,0));
#else
QucsDir = QDir(QucsApplicationPath);
QucsDir.cdUp();
#endif
2014-06-10 22:06:05 +02:00
QucsSettings.BinDir = QucsDir.absolutePath() + "/bin/";
QucsSettings.LangDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/lang/";
2017-10-20 17:46:44 +03:00
QucsSettings.LibDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/library/";
QucsSettings.OctaveDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/octave/";
2017-01-22 18:07:20 +03:00
QucsSettings.ExamplesDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/examples/";
QucsSettings.DocDir = QucsDir.canonicalPath() + "/share/" QUCS_NAME "/docs/";
2013-12-11 09:32:01 +00:00
QucsSettings.Editor = "qucs";
/// \todo Make the setting up of all executables below more consistent
2017-10-20 17:46:44 +03:00
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;
#ifdef __MINGW32__
2014-06-09 13:01:11 +02:00
admsExec = QDir::toNativeSeparators(QucsSettings.BinDir+"/"+"admsXml.exe");
#else
2014-06-09 13:01:11 +02:00
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;
#ifdef __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();
}
2006-07-03 06:02:08 +00:00
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;
2006-07-03 06:02:08 +00:00
//a.setFont(QucsSettings.font);
2004-05-25 19:10:00 +00:00
// set codecs
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
// QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
2003-10-15 21:32:36 +00:00
QTranslator tor( 0 );
2006-02-14 07:25:27 +00:00
QString lang = QucsSettings.Language;
if(lang.isEmpty()) {
QLocale loc;
lang = loc.name();
// lang = QTextCodec::locale();
}
2006-02-14 07:25:27 +00:00
tor.load( QString("qucs_") + lang, QucsSettings.LangDir);
2003-12-07 15:21:31 +00:00
a.installTranslator( &tor );
2004-05-25 19:10:00 +00:00
2006-07-24 06:12:23 +00:00
// This seems to be neccessary on a few system to make strtod()
// work properly !???!
setlocale (LC_NUMERIC, "C");
2006-07-24 06:12:23 +00:00
2014-09-10 21:56:13 +09:00
QString inputfile;
QString outputfile;
2014-09-10 21:56:13 +09:00
bool netlist_flag = false;
bool print_flag = false;
bool ngspice_flag = false;
bool xyce_flag = false;
bool run_flag = false;
2014-09-24 22:56:31 +09:00
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,
2014-10-03 16:46:28 +02:00
"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"
2014-10-03 16:46:28 +02:00
" -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"
2014-01-21 19:08:03 +01:00
" -icons create component icons under ./bitmaps_generated\n"
2015-02-11 23:59:52 +01:00
" -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
2014-12-31 13:09:45 +02:00
fprintf(stdout, "Qucs " PACKAGE_VERSION " (" GIT ")" "\n");
#else
fprintf(stdout, "Qucs " PACKAGE_VERSION "\n");
#endif
return 0;
}
else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--netlist")) {
2014-09-10 21:56:13 +09:00
netlist_flag = true;
}
else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--print")) {
print_flag = true;
}
2014-09-24 22:56:31 +09:00
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")) {
2014-09-10 21:56:13 +09:00
inputfile = argv[++i];
}
else if (!strcmp(argv[i], "-o")) {
2014-09-10 21:56:13 +09:00
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
2014-09-10 21:56:13 +09:00
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;
2014-09-10 21:56:13 +09:00
} else if (netlist_flag or print_flag) {
if (inputfile.isEmpty()) {
fprintf(stderr, "Error: Expected input file.\n");
return -1;
}
2014-09-10 21:56:13 +09:00
if (outputfile.isEmpty()) {
fprintf(stderr, "Error: Expected output file.\n");
return -1;
}
// create netlist from schematic
2014-09-10 21:56:13 +09:00
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;
}
2014-09-10 21:56:13 +09:00
} else if (print_flag) {
2014-09-27 11:44:10 +09:00
return doPrint(inputfile, outputfile,
page, dpi, color, orientation);
2014-09-10 21:56:13 +09:00
}
}
2004-12-04 18:41:22 +00:00
QucsMain = new QucsApp();
//1a.setMainWidget(QucsMain);
2004-12-04 18:41:22 +00:00
QucsMain->show();
2004-06-12 12:35:04 +00:00
int result = a.exec();
//saveApplSettings(QucsMain);
2004-06-12 12:35:04 +00:00
return result;
2003-10-15 21:32:36 +00:00
}