qucs_s/qucs/main.cpp

1062 lines
37 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>
2023-01-17 13:27:12 +03:00
//#include <QTextCodec>
#include <QTranslator>
#include <QFile>
#include <QMessageBox>
2023-01-17 13:27:12 +03:00
#include <QRegularExpression>
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"
#include "schematic.h"
#include "settings.h"
#include "module.h"
#include "misc.h"
#include "extsimkernels/ngspice.h"
#include "extsimkernels/xyce.h"
2024-07-04 10:42:54 +03:00
#if defined(_WIN32) ||defined(__MINGW32__)
#include <windows.h> //for OutputDebugString
#endif
2024-07-04 10:42:54 +03:00
#if defined(_WIN32) ||defined(__MINGW32__)
#define executableSuffix ".exe"
#else
#define executableSuffix ""
#endif
tQucsSettings QucsSettings;
QucsApp *QucsMain = nullptr; // 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");
QucsSettings.DefaultSimulator = _settings::Get().item<int>("DefaultSimulator");
QucsSettings.firstRun = _settings::Get().item<bool>("firstRun");
/*** Temporarily continue to use QucsSettings to make sure all settings convert okay and remain compatible ***/
QucsSettings.font.fromString(_settings::Get().item<QString>("font"));
QucsSettings.appFont.fromString(_settings::Get().item<QString>("appFont"));
QucsSettings.textFont.fromString(_settings::Get().item<QString>("textFont"));
QucsSettings.largeFontSize = _settings::Get().item<double>("LargeFontSize");
QucsSettings.maxUndo = _settings::Get().item<int>("maxUndo");
QucsSettings.NodeWiring = _settings::Get().item<int>("NodeWiring");
QucsSettings.BGColor = _settings::Get().item<QString>("BGColor");
QucsSettings.Editor = _settings::Get().item<QString>("Editor");
QucsSettings.FileTypes = _settings::Get().item<QStringList>("FileTypes");
QucsSettings.Language = _settings::Get().item<QString>("Language");
// Editor syntax highlighting settings.
QucsSettings.Comment = _settings::Get().item<QString>("Comment");
QucsSettings.String = _settings::Get().item<QString>("String");
QucsSettings.Integer = _settings::Get().item<QString>("Integer");
QucsSettings.Real = _settings::Get().item<QString>("Real");
QucsSettings.Character = _settings::Get().item<QString>("Character");
QucsSettings.Type = _settings::Get().item<QString>("Type");
QucsSettings.Attribute = _settings::Get().item<QString>("Attribute");
QucsSettings.Directive = _settings::Get().item<QString>("Directive");
QucsSettings.Task = _settings::Get().item<QString>("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 = QStandardPaths::findExecutable("qucsconv_rf",{QucsSettings.QucsatorDir});
} else {
QucsSettings.Qucsator = QStandardPaths::findExecutable("qucsator_rf",{QucsSettings.BinDir});
QucsSettings.QucsatorDir = QucsSettings.BinDir;
if (QucsSettings.Qucsconv.isEmpty())
QucsSettings.Qucsconv = QStandardPaths::findExecutable("qucsconv_rf",{QucsSettings.BinDir});
}
QucsSettings.AdmsXmlBinDir.setPath(_settings::Get().item<QString>("AdmsXmlBinDir"));
QucsSettings.AscoBinDir.setPath(_settings::Get().item<QString>("AscoBinDir"));
QucsSettings.NgspiceExecutable = _settings::Get().item<QString>("NgspiceExecutable");
QucsSettings.XyceExecutable = _settings::Get().item<QString>("XyceExecutable");
QucsSettings.XyceParExecutable = _settings::Get().item<QString>("XyceParExecutable");
QucsSettings.SpiceOpusExecutable = _settings::Get().item<QString>("SpiceOpusExecutable");
QucsSettings.NProcs = _settings::Get().item<int>("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<QString>("S4Q_workdir");
if (QucsSettings.S4Qworkdir == "")
QucsSettings.S4Qworkdir = QDir::toNativeSeparators(QucsSettings.QucsWorkDir.absolutePath()+"/spice4qucs");
2024-02-06 21:53:18 +00:00
QucsSettings.SimParameters = _settings::Get().item<QString>("SimParameters");
QucsSettings.OctaveExecutable = _settings::Get().item<QString>("OctaveExecutable");
QucsSettings.OpenVAFExecutable = _settings::Get().item<QString>("OpenVAFExecutable");
QucsSettings.RFLayoutExecutable = _settings::Get().item<QString>("RFLayoutExecutable");
QucsSettings.qucsWorkspaceDir.setPath(_settings::Get().item<QString>("QucsHomeDir"));
QucsSettings.QucsWorkDir = QucsSettings.qucsWorkspaceDir;
QucsSettings.tempFilesDir.setPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QucsSettings.IgnoreFutureVersion = _settings::Get().item<bool>("IgnoreVersion");
QucsSettings.GraphAntiAliasing = _settings::Get().item<bool>("GraphAntiAliasing");
QucsSettings.TextAntiAliasing = _settings::Get().item<bool>("TextAntiAliasing");
QucsSettings.fullTraceName = _settings::Get().item<bool>("fullTraceName");
QucsSettings.RecentDocs = _settings::Get().item<QString>("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
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");
// Note: It is not really necessary to take the following reference, but it
2024-02-06 21:53:18 +00:00
// arguably makes the code slightly cleaner - thoughts? To be clear:
// qs.item<int>() is identical to _settings::get().item<int>()
settingsManager& qs = _settings::Get();
qs.setItem<int>("DefaultSimulator", QucsSettings.DefaultSimulator);
qs.setItem<bool>("firstRun", false);
qs.setItem<QString>("font", QucsSettings.font.toString());
qs.setItem<QString>("appFont", QucsSettings.appFont.toString());
qs.setItem<QString>("textFont", QucsSettings.textFont.toString());
if (QucsMain != nullptr) {
qs.setItem<QByteArray>("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<QString>("LargeFontSize", QString::number(QucsSettings.largeFontSize));
qs.setItem<unsigned int>("maxUndo", QucsSettings.maxUndo);
qs.setItem<unsigned int>("NodeWiring", QucsSettings.NodeWiring);
qs.setItem<QString>("BGColor", QucsSettings.BGColor.name());
qs.setItem<QString>("Editor", QucsSettings.Editor);
qs.setItem<QStringList>("FileTypes", QucsSettings.FileTypes);
qs.setItem<QString>("Language", QucsSettings.Language);
qs.setItem<QString>("Comment", QucsSettings.Comment.name());
qs.setItem<QString>("String", QucsSettings.String.name());
qs.setItem<QString>("Integer", QucsSettings.Integer.name());
qs.setItem<QString>("Real", QucsSettings.Real.name());
qs.setItem<QString>("Character", QucsSettings.Character.name());
qs.setItem<QString>("Type", QucsSettings.Type.name());
qs.setItem<QString>("Attribute", QucsSettings.Attribute.name());
qs.setItem<QString>("Directive", QucsSettings.Directive.name());
qs.setItem<QString>("Task", QucsSettings.Task.name());
qs.setItem<QString>("AdmsXmlBinDir", QucsSettings.AdmsXmlBinDir.canonicalPath());
qs.setItem<QString>("AscoBinDir", QucsSettings.AscoBinDir.canonicalPath());
qs.setItem<QString>("NgspiceExecutable",QucsSettings.NgspiceExecutable);
qs.setItem<QString>("XyceExecutable",QucsSettings.XyceExecutable);
qs.setItem<QString>("XyceParExecutable",QucsSettings.XyceParExecutable);
qs.setItem<QString>("SpiceOpusExecutable",QucsSettings.SpiceOpusExecutable);
qs.setItem<QString>("Qucsator",QucsSettings.Qucsator);
qs.setItem<int>("Nprocs",QucsSettings.NProcs);
qs.setItem<QString>("S4Q_workdir",QucsSettings.S4Qworkdir);
qs.setItem<QString>("SimParameters",QucsSettings.SimParameters);
qs.setItem<QString>("OctaveExecutable",QucsSettings.OctaveExecutable);
qs.setItem<QString>("OpenVAFExecutable",QucsSettings.OpenVAFExecutable);
qs.setItem<QString>("QucsHomeDir", QucsSettings.qucsWorkspaceDir.canonicalPath());
qs.setItem<bool>("IgnoreVersion", QucsSettings.IgnoreFutureVersion);
qs.setItem<bool>("GraphAntiAliasing", QucsSettings.GraphAntiAliasing);
qs.setItem<bool>("TextAntiAliasing", QucsSettings.TextAntiAliasing);
qs.setItem<bool>("fullTraceName",QucsSettings.fullTraceName);
// 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;
2023-01-15 01:17:09 +03:00
for (QString& path: qucsPathList) {
settings.setArrayIndex(i);
settings.setValue("path", path);
i++;
}
settings.endArray();
2004-05-25 19:10:00 +00:00
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.
* <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>
*/
2022-12-29 16:10:46 +03:00
void qucsMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
2022-12-29 16:10:46 +03:00
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);
}
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
2023-06-15 19:24:02 +03:00
//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;
2024-03-13 13:02:59 +03:00
Module::registerModules();
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;
2024-09-27 17:18:55 +03:00
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)
{
2023-06-05 23:52:53 +03:00
QucsSettings.DefaultSimulator = spicecompat::simXyce;
2024-09-27 17:18:55 +03:00
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;
2024-03-13 13:02:59 +03:00
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)
{
2023-06-05 23:52:53 +03:00
QucsSettings.DefaultSimulator = spicecompat::simXyce;
2024-03-13 13:02:59 +03:00
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;
}
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->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();
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 ();
2023-01-15 01:17:09 +03:00
for (const QString& category: cats) {
2014-12-01 16:12:51 +01:00
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;
2023-01-15 01:17:09 +03:00
for (Module *Mod: Comps) {
2014-12-01 16:12:51 +01:00
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::Rect *> Rects = c-> Rects;
QList<qucs::Ellips *> Ellips = c-> Ellipses;
2014-12-01 16:12:51 +01:00
QList<Port *> Ports = c->Ports;
QList<Text*> Texts = c->Texts;
QGraphicsScene *scene = new QGraphicsScene();
2023-01-15 01:17:09 +03:00
for (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
2023-01-15 01:17:09 +03:00
for (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);
}
for(qucs::Rect *a: Rects) {
2014-12-01 16:12:51 +01:00
scene->addRect(a->x, a->y, a->w, a->h, a->Pen, a->Brush);
}
for(qucs::Ellips *a: Ellips) {
2014-12-01 16:12:51 +01:00
scene->addEllipse(a->x, a->y, a->w, a->h, a->Pen, a->Brush);
}
2023-01-15 01:17:09 +03:00
for(Port *p: Ports) {
scene->addEllipse(p->x-4, p->y-4, 8, 8, QPen(Qt::red));
2014-12-01 16:12:51 +01:00
}
2023-01-15 01:17:09 +03:00
for(Text *t: Texts) {
2014-12-01 16:12:51 +01:00
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);
2022-02-24 00:13:12 +01:00
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);
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
2023-01-15 01:17:09 +03:00
for (const 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; // component id inside category
2023-01-15 01:17:09 +03:00
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");
2023-01-15 01:17:09 +03:00
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
2023-01-15 01:17:09 +03:00
for (QString category: cats) {
QList<Module *> Comps;
Comps = Category::getModules(category);
// \fixme, crash with diagrams, skip
if(category == "diagrams") break;
char * File;
QString Name;
2023-01-15 01:17:09 +03:00
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;
2023-01-15 01:17:09 +03:00
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
}
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;
#if QT_VERSION < 0x060000
2023-11-27 22:59:34 +03:00
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling,true);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps,true);
#endif
// initially center the application
QApplication a(argc, argv);
2023-01-17 13:27:12 +03:00
//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();
2024-12-03 23:26:56 +03:00
/* restore saved style */
QString savedStyle = _settings::Get().item<QString>("AppStyle");
QStyle* style = QStyleFactory::create(savedStyle);
if (style) {
QApplication::setStyle(style);
}
/* restore saved style */
QDir().mkpath(QucsSettings.qucsWorkspaceDir.absolutePath());
QDir().mkpath(QucsSettings.tempFilesDir.absolutePath());
2023-06-07 01:45:39 +03:00
// 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
2024-12-18 00:26:54 +03:00
QucsSettings.BinDir = QucsApplicationPath.contains("bin") ?
(QucsApplicationPath + QDir::separator()) : QucsDir.absoluteFilePath("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;
2024-07-04 10:42:54 +03:00
#if defined(_WIN32) || defined(__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;
2024-07-04 10:42:54 +03:00
#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();
}
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
QucsSettings.sysDefaultFont = QApplication::font();
2023-11-27 22:59:34 +03:00
QApplication::setFont(QucsSettings.appFont);
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();
}
tor.load( QStringLiteral("qucs_") + lang, QucsSettings.LangDir);
2023-11-27 22:59:34 +03:00
QApplication::installTranslator( &tor );
2004-05-25 19:10:00 +00:00
// This seems to be necessary on a few system to make strtod()
2006-07-24 06:12:23 +00:00
// 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
2023-11-29 12:18:20 +03:00
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")) {
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);
2022-03-01 17:34:25 +01:00
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
}