My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
main.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  main.cpp
3  ----------
4  begin : Thu Aug 28 2003
5  copyright : (C) 2003 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include <math.h>
25 #include <locale.h>
26 
27 #include <qapplication.h>
28 #include <qstring.h>
29 #include <qstringlist.h>
30 #include <qtextcodec.h>
31 #include <qtranslator.h>
32 #include <qfile.h>
33 #include <qtextstream.h>
34 #include <qmessagebox.h>
35 #include <qregexp.h>
36 
37 #include "qucs.h"
38 #include "main.h"
39 #include "node.h"
40 
42 
43 QFont savingFont; // to remember which font to save in "qucsrc"
44 
45 QucsApp *QucsMain; // the Qucs application itself
46 QString lastDir; // to remember last directory for several dialogs
47 
48 // #########################################################################
49 // Loads the settings file and stores the settings.
51 {
52  QFile file(QucsHomeDir.filePath("qucsrc"));
53  if(!file.open(IO_ReadOnly)) return false; // settings file doesn't exist
54 
55  QTextStream stream(&file);
56  QString Line, Setting;
57 
58  bool ok;
59  while(!stream.atEnd()) {
60  Line = stream.readLine();
61  Setting = Line.section('=',0,0);
62  Line = Line.section('=',1).stripWhiteSpace();
63  if(Setting == "Position") {
64  QucsSettings.x = Line.section(",",0,0).toInt(&ok);
65  QucsSettings.y = Line.section(",",1,1).toInt(&ok); }
66  else if(Setting == "Size") {
67  QucsSettings.dx = Line.section(",",0,0).toInt(&ok);
68  QucsSettings.dy = Line.section(",",1,1).toInt(&ok); }
69  else if(Setting == "Font") {
70  QucsSettings.font.fromString(Line);
71  savingFont = QucsSettings.font;
72 
73  QucsSettings.largeFontSize
74  = floor(4.0/3.0 * QucsSettings.font.pointSize());
75  }
76  else if(Setting == "BGColor") {
77  QucsSettings.BGColor.setNamedColor(Line); }
78  else if(Setting == "maxUndo") {
79  QucsSettings.maxUndo = Line.toInt(&ok); }
80  else if(Setting == "Editor") {
81  QucsSettings.Editor = Line; }
82  else if(Setting == "FileType") {
83  QucsSettings.FileTypes.append(Line); }
84  else if(Setting == "Language") {
85  QucsSettings.Language = Line; }
86  else if(Setting == "SyntaxColor") {
87  QucsSettings.Comment.setNamedColor(Line.section(",", 0,0));
88  QucsSettings.String.setNamedColor(Line.section(",", 1,1));
89  QucsSettings.Integer.setNamedColor(Line.section(",", 2,2));
90  QucsSettings.Real.setNamedColor(Line.section(",", 3,3));
91  QucsSettings.Character.setNamedColor(Line.section(",", 4,4));
92  QucsSettings.Type.setNamedColor(Line.section(",", 5,5));
93  QucsSettings.Attribute.setNamedColor(Line.section(",", 6,6));
94  QucsSettings.Directive.setNamedColor(Line.section(",", 7,7));
95  QucsSettings.Task.setNamedColor(Line.section(",", 8,8));
96  }
97  else if(Setting == "NodeWiring") {
98  QucsSettings.NodeWiring = Line.toInt(&ok); }
99  }
100 
101  file.close();
102  return true;
103 }
104 
105 // #########################################################################
106 // Saves the settings in the settings file.
108 {
109  QFile file(QucsHomeDir.filePath("qucsrc"));
110  if(!file.open(IO_WriteOnly)) { // settings file cannot be created
111  QMessageBox::warning(0, QObject::tr("Warning"),
112  QObject::tr("Cannot save settings !"));
113  return false;
114  }
115 
116  QTextStream stream(&file);
117 
118  stream << "Settings file, Qucs " PACKAGE_VERSION "\n"
119  << "Position=" << qucs->x() << "," << qucs->y() << "\n"
120  << "Size=" << qucs->width() << "," << qucs->height() << "\n"
121  << "Font=" << savingFont.toString() << "\n"
122  << "Language=" << QucsSettings.Language << "\n"
123  << "BGColor=" << QucsSettings.BGColor.name() << "\n"
124  << "maxUndo=" << QucsSettings.maxUndo << "\n"
125  << "Editor=" << QucsSettings.Editor << "\n"
126  << "SyntaxColor="
127  << QucsSettings.Comment.name() << ","
128  << QucsSettings.String.name() << ","
129  << QucsSettings.Integer.name() << ","
130  << QucsSettings.Real.name() << ","
131  << QucsSettings.Character.name() << ","
132  << QucsSettings.Type.name() << ","
133  << QucsSettings.Attribute.name() << ","
134  << QucsSettings.Directive.name() << ","
135  << QucsSettings.Task.name() << "\n"
136  << "NodeWiring=" << QucsSettings.NodeWiring << "\n";
137 
138  QStringList::Iterator it = QucsSettings.FileTypes.begin();
139  while(it != QucsSettings.FileTypes.end())
140  stream << "FileType=" << (*(it++)) << "\n";
141 
142  file.close();
143  return true;
144 }
145 
146 // #########################################################################
147 QString complexRect(double real, double imag, int Precision)
148 {
149  QString Text;
150  if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision);
151  else {
152  Text = QString::number(imag,'g',Precision);
153  if(Text.at(0) == '-') {
154  Text.at(0) = 'j';
155  Text = '-'+Text;
156  }
157  else Text = "+j"+Text;
158  Text = QString::number(real,'g',Precision) + Text;
159  }
160  return Text;
161 }
162 
163 QString complexDeg(double real, double imag, int Precision)
164 {
165  QString Text;
166  if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision);
167  else {
168  Text = QString::number(sqrt(real*real+imag*imag),'g',Precision) + " / ";
169  Text += QString::number(180.0/M_PI*atan2(imag,real),'g',Precision) + '°';
170  }
171  return Text;
172 }
173 
174 QString complexRad (double real, double imag, int Precision)
175 {
176  QString Text;
177  if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision);
178  else {
179  Text = QString::number(sqrt(real*real+imag*imag),'g',Precision);
180  Text += " / " + QString::number(atan2(imag,real),'g',Precision) + "rad";
181  }
182  return Text;
183 }
184 
185 // #########################################################################
186 QString StringNum(double num, char form, int Precision)
187 {
188  int a = 0;
189  char *p, Buffer[512], Format[6] = "%.00g";
190 
191  if(Precision < 0) {
192  Format[1] = form;
193  Format[2] = 0;
194  }
195  else {
196  Format[4] = form;
197  Format[2] += Precision / 10;
198  Format[3] += Precision % 10;
199  }
200  sprintf(Buffer, Format, num);
201  p = strchr(Buffer, 'e');
202  if(p) {
203  p++;
204  if(*(p++) == '+') { a = 1; } // remove '+' of exponent
205  if(*p == '0') { a++; p++; } // remove leading zeros of exponent
206  if(a > 0)
207  do {
208  *(p-a) = *p;
209  } while(*(p++) != 0); // override characters not needed
210  }
211 
212  return QString(Buffer);
213 }
214 
215 // #########################################################################
216 QString StringNiceNum(double num)
217 {
218  char Format[6] = "%.8e";
219  if(fabs(num) < 1e-250) return QString("0"); // avoid many problems
220  if(fabs(log10(fabs(num))) < 3.0) Format[3] = 'g';
221 
222  int a = 0;
223  char *p, *pe, Buffer[512];
224 
225  sprintf(Buffer, Format, num);
226  p = pe = strchr(Buffer, 'e');
227  if(p) {
228  if(*(++p) == '+') { a = 1; } // remove '+' of exponent
229  if(*(++p) == '0') { a++; p++; } // remove leading zeros of exponent
230  if(a > 0)
231  do {
232  *(p-a) = *p;
233  } while(*(p++) != 0); // override characters not needed
234 
235  // In 'g' format, trailing zeros are already cut off !!!
236  p = strchr(Buffer, '.');
237  if(p) {
238  if(!pe) pe = Buffer + strlen(Buffer);
239  p = pe-1;
240  while(*p == '0') // looking for unneccessary zero characters
241  if((--p) <= Buffer) break;
242  if(*p != '.') p++; // no digit after decimal point ?
243  while( (*(p++) = *(pe++)) != 0 ) ; // overwrite zero characters
244  }
245  }
246 
247  return QString(Buffer);
248 }
249 
250 // #########################################################################
251 void str2num(const QString& s_, double& Number, QString& Unit, double& Factor)
252 {
253  QString str = s_.stripWhiteSpace();
254 
255 /* int i=0;
256  bool neg = false;
257  if(str[0] == '-') { // check sign
258  neg = true;
259  i++;
260  }
261  else if(str[0] == '+') i++;
262 
263  double num = 0.0;
264  for(;;) {
265  if(str[i] >= '0') if(str[i] <= '9') {
266  num = 10.0*num + double(str[i]-'0');
267  }
268  }*/
269 
270  QRegExp Expr( QRegExp("[^0-9\\x2E\\x2D\\x2B]") );
271  int i = str.find( Expr );
272  if(i >= 0)
273  if((str.at(i).latin1() | 0x20) == 'e') {
274  int j = str.find( Expr , ++i);
275  if(j == i) j--;
276  i = j;
277  }
278 
279  Number = str.left(i).toDouble();
280  Unit = str.mid(i).stripWhiteSpace();
281 
282  switch(Unit.at(0).latin1()) {
283  case 'T': Factor = 1e12; break;
284  case 'G': Factor = 1e9; break;
285  case 'M': Factor = 1e6; break;
286  case 'k': Factor = 1e3; break;
287  case 'c': Factor = 1e-2; break;
288  case 'm': Factor = 1e-3; break;
289  case 'u': Factor = 1e-6; break;
290  case 'n': Factor = 1e-9; break;
291  case 'p': Factor = 1e-12; break;
292  case 'f': Factor = 1e-15; break;
293 // case 'd':
294  default: Factor = 1.0;
295  }
296 
297  return;
298 }
299 
300 // #########################################################################
301 QString num2str(double Num)
302 {
303  char c = 0;
304  double cal = fabs(Num);
305  if(cal > 1e-20) {
306  cal = log10(cal) / 3.0;
307  if(cal < -0.2) cal -= 0.98;
308  int Expo = int(cal);
309 
310  if(Expo >= -5) if(Expo <= 4)
311  switch(Expo) {
312  case -5: c = 'f'; break;
313  case -4: c = 'p'; break;
314  case -3: c = 'n'; break;
315  case -2: c = 'u'; break;
316  case -1: c = 'm'; break;
317  case 1: c = 'k'; break;
318  case 2: c = 'M'; break;
319  case 3: c = 'G'; break;
320  case 4: c = 'T'; break;
321  }
322 
323  if(c) Num /= pow(10.0, double(3*Expo));
324  }
325 
326  QString Str = QString::number(Num);
327  if(c) Str += c;
328 
329  return Str;
330 }
331 
332 // #########################################################################
333 void convert2Unicode(QString& Text)
334 {
335  bool ok;
336  int i = 0;
337  QString n;
338  unsigned short ch;
339  while((i=Text.find("\\x", i)) >= 0) {
340  n = Text.mid(i, 6);
341  ch = n.mid(2).toUShort(&ok, 16);
342  if(ok) Text.replace(n, QChar(ch));
343  i++;
344  }
345  Text.replace("\\n", "\n");
346  Text.replace("\\\\", "\\");
347 }
348 
349 // #########################################################################
350 void convert2ASCII(QString& Text)
351 {
352  Text.replace('\\', "\\\\");
353  Text.replace('\n', "\\n");
354 
355  int i = 0;
356  QChar ch;
357  char Str[8];
358  while((ch=Text.at(i++)) != QChar(0)) { // convert special characters
359  if(ch > QChar(0x7F)) {
360  sprintf(Str, "\\x%04X", ch.unicode());
361  Text.replace(ch, Str);
362  }
363  }
364 }
365 
366 // #########################################################################
367 QString properAbsFileName(const QString& Name)
368 {
369  QString s = Name;
370  QFileInfo Info(s);
371  if(Info.isRelative()) s = QucsWorkDir.filePath(s);
372  return QDir::cleanDirPath(s);
373 }
374 
375 // #########################################################################
376 QString properFileName(const QString& Name)
377 {
378  QFileInfo Info(Name);
379  return Info.fileName();
380 }
381 
382 // #########################################################################
383 // Takes a file name (with path) and replaces all special characters.
384 QString properName(const QString& Name)
385 {
386  QString s = Name;
387  QFileInfo Info(s);
388  if(Info.extension() == "sch")
389  s = s.left(s.length()-4);
390  if(s.at(0) <= '9') if(s.at(0) >= '0')
391  s = 'n' + s;
392  s.replace(QRegExp("\\W"), "_"); // none [a-zA-Z0-9] into "_"
393  s.replace("__", "_"); // '__' not allowed in VHDL
394  if(s.at(0) == '_')
395  s = 'n' + s;
396  return s;
397 }
398 
399 // #########################################################################
400 // Creates and returns delay time for VHDL entities.
401 bool VHDL_Delay(QString& td, const QString& Name)
402 {
403  if(strtod(td.latin1(), 0) != 0.0) { // delay time property
404  if(!VHDL_Time(td, Name))
405  return false; // time has not VHDL format
406  td = " after " + td;
407  return true;
408  }
409  else if(isalpha(td.latin1()[0])) {
410  td = " after " + td;
411  return true;
412  }
413  else {
414  td = "";
415  return true;
416  }
417 }
418 
419 // #########################################################################
420 // Checks and corrects a time (number & unit) according VHDL standard.
421 bool VHDL_Time(QString& t, const QString& Name)
422 {
423  char *p;
424  double Time = strtod(t.latin1(), &p);
425  while(*p == ' ') p++;
426  for(;;) {
427  if(Time >= 0.0) {
428  if(strcmp(p, "fs") == 0) break;
429  if(strcmp(p, "ps") == 0) break;
430  if(strcmp(p, "ns") == 0) break;
431  if(strcmp(p, "us") == 0) break;
432  if(strcmp(p, "ms") == 0) break;
433  if(strcmp(p, "sec") == 0) break;
434  if(strcmp(p, "min") == 0) break;
435  if(strcmp(p, "hr") == 0) break;
436  }
437  t = "§" + QObject::tr("Error: Wrong time format in \"%1\". Use positive number with units").arg(Name)
438  + " fs, ps, ns, us, ms, sec, min, hr.\n";
439  return false;
440  }
441 
442  t = QString::number(Time) + " " + QString(p); // the space is mandatory !
443  return true;
444 }
445 
446 // #########################################################################
447 // Returns parameters for Verilog modules.
448 QString Verilog_Param(const QString Value)
449 {
450  if(strtod(Value.latin1(), 0) != 0.0) {
451  QString td = Value;
452  if(!Verilog_Time(td, "parameter"))
453  return Value;
454  else
455  return td;
456  }
457  else
458  return Value;
459 }
460 
461 // #########################################################################
462 // Creates and returns delay time for Verilog modules.
463 bool Verilog_Delay(QString& td, const QString& Name)
464 {
465  if(strtod(td.latin1(), 0) != 0.0) { // delay time property
466  if(!Verilog_Time(td, Name))
467  return false; // time has not Verilog format
468  td = " #" + td;
469  return true;
470  }
471  else if(isalpha(td.latin1()[0])) {
472  td = " #" + td;
473  return true;
474  }
475  else {
476  td = "";
477  return true;
478  }
479 }
480 
481 // #########################################################################
482 // Checks and corrects a time (number & unit) according Verilog standard.
483 bool Verilog_Time(QString& t, const QString& Name)
484 {
485  char *p;
486  double Time = strtod(t.latin1(), &p);
487  double factor = 1.0;
488  while(*p == ' ') p++;
489  for(;;) {
490  if(Time >= 0.0) {
491  if(strcmp(p, "fs") == 0) { factor = 1e-3; break; }
492  if(strcmp(p, "ps") == 0) { factor = 1; break; }
493  if(strcmp(p, "ns") == 0) { factor = 1e3; break; }
494  if(strcmp(p, "us") == 0) { factor = 1e6; break; }
495  if(strcmp(p, "ms") == 0) { factor = 1e9; break; }
496  if(strcmp(p, "sec") == 0) { factor = 1e12; break; }
497  if(strcmp(p, "min") == 0) { factor = 1e12*60; break; }
498  if(strcmp(p, "hr") == 0) { factor = 1e12*60*60; break; }
499  }
500  t = "§" + QObject::tr("Error: Wrong time format in \"%1\". Use positive number with units").arg(Name)
501  + " fs, ps, ns, us, ms, sec, min, hr.\n";
502  return false;
503  }
504 
505  t = QString::number(Time*factor);
506  return true;
507 }
508 
509 // #########################################################################
510 bool checkVersion(QString& Line)
511 {
512  QStringList sl = QStringList::split('.',PACKAGE_VERSION);
513  QStringList ll = QStringList::split('.',Line);
514  if (ll.count() != 3 || sl.count() != 3)
515  return false;
516  int sv = (*sl.at(1)).toInt() * 10000 + (*sl.at(2)).toInt() * 100 +
517  (*sl.at(3)).toInt();
518  int lv = (*ll.at(1)).toInt() * 10000 + (*ll.at(2)).toInt() * 100 +
519  (*ll.at(3)).toInt();
520  if(lv > sv) // wrong version number ? (only backward compatible)
521  return false;
522  return true;
523 }
524 
525 
526 // #########################################################################
527 // ########## ##########
528 // ########## Program Start ##########
529 // ########## ##########
530 // #########################################################################
531 
532 int main(int argc, char *argv[])
533 {
534  // apply default settings
535  QucsSettings.font = QFont("Helvetica", 12);
536  QucsSettings.largeFontSize = 16.0;
537  QucsSettings.maxUndo = 20;
538  QucsSettings.NodeWiring = 0;
539 
540  // initially center the application
541  QApplication a(argc, argv);
542  QDesktopWidget *d = a.desktop();
543  int w = d->width();
544  int h = d->height();
545  QucsSettings.x = w/8;
546  QucsSettings.y = h/8;
547  QucsSettings.dx = w*3/4;
548  QucsSettings.dy = h*3/4;
549 
550  // is application relocated?
551  char * var = getenv ("QUCSDIR");
552  if (var != NULL) {
553  QDir QucsDir = QDir (var);
554  QString QucsDirStr = QucsDir.canonicalPath ();
555  QucsSettings.BinDir =
556  QDir::convertSeparators (QucsDirStr + "/bin/");
557  QucsSettings.BitmapDir =
558  QDir::convertSeparators (QucsDirStr + "/share/qucs/bitmaps/");
559  QucsSettings.LangDir =
560  QDir::convertSeparators (QucsDirStr + "/share/qucs/lang/");
561  QucsSettings.LibDir =
562  QDir::convertSeparators (QucsDirStr + "/share/qucs/library/");
563  QucsSettings.OctaveDir =
564  QDir::convertSeparators (QucsDirStr + "/share/qucs/octave/");
565  } else {
566  QucsSettings.BinDir = BINARYDIR;
567  QucsSettings.BitmapDir = BITMAPDIR;
568  QucsSettings.LangDir = LANGUAGEDIR;
569  QucsSettings.LibDir = LIBRARYDIR;
570  QucsSettings.OctaveDir = OCTAVEDIR;
571  }
572  QucsSettings.Editor = QucsSettings.BinDir + "qucsedit";
573 
574  QucsWorkDir.setPath(QDir::homeDirPath()+QDir::convertSeparators ("/.qucs"));
575  QucsHomeDir.setPath(QDir::homeDirPath()+QDir::convertSeparators ("/.qucs"));
576  loadSettings();
577 
578  if(!QucsSettings.BGColor.isValid())
579  QucsSettings.BGColor.setRgb(255, 250, 225);
580 
581  // syntax highlighting
582  if(!QucsSettings.Comment.isValid())
583  QucsSettings.Comment = Qt::gray;
584  if(!QucsSettings.String.isValid())
585  QucsSettings.String = Qt::red;
586  if(!QucsSettings.Integer.isValid())
587  QucsSettings.Integer = Qt::blue;
588  if(!QucsSettings.Real.isValid())
589  QucsSettings.Real = Qt::darkMagenta;
590  if(!QucsSettings.Character.isValid())
591  QucsSettings.Character = Qt::magenta;
592  if(!QucsSettings.Type.isValid())
593  QucsSettings.Type = Qt::darkRed;
594  if(!QucsSettings.Attribute.isValid())
595  QucsSettings.Attribute = Qt::darkCyan;
596  if(!QucsSettings.Directive.isValid())
597  QucsSettings.Directive = Qt::darkCyan;
598  if(!QucsSettings.Task.isValid())
599  QucsSettings.Task = Qt::darkRed;
600 
601  var = getenv ("ASCODIR");
602  if (var != NULL) {
603  QDir AscoDir = QDir (var);
604  QString AscoDirStr = AscoDir.canonicalPath ();
605  QucsSettings.AscoDir =
606  QDir::convertSeparators (AscoDirStr + "/bin/");
607  } else {
608  QucsSettings.AscoDir = "";
609  }
610 
611  a.setFont(QucsSettings.font);
612 
613  QTranslator tor( 0 );
614  QString lang = QucsSettings.Language;
615  if(lang.isEmpty())
616  lang = QTextCodec::locale();
617  tor.load( QString("qucs_") + lang, QucsSettings.LangDir);
618  a.installTranslator( &tor );
619 
620  // This seems to be neccessary on a few system to make strtod()
621  // work properly !???!
622  setlocale (LC_NUMERIC, "C");
623 
624  QucsMain = new QucsApp();
625  a.setMainWidget(QucsMain);
626  QucsMain->show();
627  int result = a.exec();
628  saveApplSettings(QucsMain);
629  return result;
630 }