Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/qucs.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                  qucs.cpp
00003                                 ----------
00004     begin                : Thu Aug 28 2003
00005     copyright            : (C) 2003, 2004, 2005, 2006 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #ifdef HAVE_CONFIG_H
00019 # include <config.h>
00020 #endif
00021 
00022 #include <QModelIndex>
00023 #include <QAction>
00024 #include <QTreeWidget>
00025 #include <QTreeWidgetItem>
00026 #include <QDockWidget>
00027 #include <QLineEdit>
00028 #include <QPushButton>
00029 #include <QListWidget>
00030 #include <QComboBox>
00031 #include <QMenu>
00032 #include <QMessageBox>
00033 #include <QFileDialog>
00034 #include <QStatusBar>
00035 #include <QShortcut>
00036 #include <QApplication>
00037 #include <QClipboard>
00038 #include <QInputDialog>
00039 #include <QDesktopServices>
00040 #include <QFileSystemModel>
00041 #include <QUrl>
00042 #include <QSettings>
00043 #include <QDebug>
00044 
00045 #include "main.h"
00046 #include "qucs.h"
00047 #include "qucsdoc.h"
00048 #include "textdoc.h"
00049 #include "schematic.h"
00050 #include "mouseactions.h"
00051 #include "messagedock.h"
00052 #include "wire.h"
00053 #include "module.h"
00054 #include "projectView.h"
00055 #include "components/components.h"
00056 #include "paintings/paintings.h"
00057 #include "diagrams/diagrams.h"
00058 #include "dialogs/savedialog.h"
00059 #include "dialogs/newprojdialog.h"
00060 #include "dialogs/settingsdialog.h"
00061 #include "dialogs/digisettingsdialog.h"
00062 #include "dialogs/vasettingsdialog.h"
00063 #include "dialogs/qucssettingsdialog.h"
00064 #include "dialogs/searchdialog.h"
00065 #include "dialogs/sweepdialog.h"
00066 #include "dialogs/labeldialog.h"
00067 #include "dialogs/matchdialog.h"
00068 #include "dialogs/simmessage.h"
00069 #include "dialogs/exportdialog.h"
00070 #include "octave_window.h"
00071 #include "printerwriter.h"
00072 #include "imagewriter.h"
00073 #include "../qucs-lib/qucslib_common.h"
00074 #include "misc.h"
00075 
00076 // icon for unsaved files (diskette)
00077 const char *smallsave_xpm[] = {
00078 "16 17 66 1", "   c None",
00079 ".  c #595963","+ c #E6E6F1","@ c #465460","# c #FEFEFF",
00080 "$  c #DEDEEE","% c #43535F","& c #D1D1E6","* c #5E5E66",
00081 "=  c #FFFFFF","- c #C5C5DF","; c #FCF8F9","> c #BDBDDA",
00082 ",  c #BFBFDC","' c #C4C4DF",") c #FBF7F7","! c #D6D6E9",
00083 "~  c #CBCBE3","{ c #B5B5D6","] c #BCBCDA","^ c #C6C6E0",
00084 "/  c #CFCFE5","( c #CEC9DC","_ c #D8D8EA",": c #DADAEB",
00085 "<  c #313134","[ c #807FB3","} c #AEAED1","| c #B7B7D7",
00086 "1  c #E2E2EF","2 c #9393C0","3 c #E3E3F0","4 c #DDD5E1",
00087 "5  c #E8E8F3","6 c #2F2F31","7 c #7B7BAF","8 c #8383B5",
00088 "9  c #151518","0 c #000000","a c #C0C0DC","b c #8E8FBD",
00089 "c  c #8989BA","d c #E7EEF6","e c #282829","f c #6867A1",
00090 "g  c #7373A9","h c #A7A7CD","i c #8080B3","j c #7B7CB0",
00091 "k  c #7070A8","l c #6D6DA5","m c #6E6EA6","n c #6969A2",
00092 "o  c #7A79AF","p c #DCDCEC","q c #60609A","r c #7777AC",
00093 "s  c #5D5D98","t c #7676AB","u c #484785","v c #575793",
00094 "w  c #50506A","x c #8787B8","y c #53536E","z c #07070E",
00095 "A  c #666688",
00096 "        .       ",
00097 "       .+.      ",
00098 "      .+@#.     ",
00099 "     .$%###.    ",
00100 "    .&*####=.   ",
00101 "   .-.#;#####.  ",
00102 "  .>,'.#)!!!!~. ",
00103 " .{].'^./(!_:<[.",
00104 ".}|.1./2.3456789",
00105 "0a.$11.bc.defg9 ",
00106 " 011h11.ij9kl9  ",
00107 "  0_1h1h.mno9   ",
00108 "   0p12h9qr9    ",
00109 "    0hh9st9     ",
00110 "     09uv9w     ",
00111 "      0x9y      ",
00112 "       zA       "};
00113 
00114 const char *empty_xpm[] = {  // provides same height than "smallsave_xpm"
00115 "1 17 1 1", "  c None", " ", " ", " ", " ", " ",
00116 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
00117 
00118 
00119 QucsApp::QucsApp()
00120 {
00121   setWindowTitle("Qucs " PACKAGE_VERSION);
00122 
00123   QucsFileFilter =
00124     tr("Schematic") + " (*.sch);;" +
00125     tr("Data Display") + " (*.dpl);;" +
00126     tr("Qucs Documents") + " (*.sch *.dpl);;" +
00127     tr("VHDL Sources") + " (*.vhdl *.vhd);;" +
00128     tr("Verilog Sources") + " (*.v);;" +
00129     tr("Verilog-A Sources") + " (*.va);;" +
00130     tr("Octave Scripts") + " (*.m *.oct);;" +
00131     tr("Spice Files") + QString(" (") + QucsSettings.spiceExtensions.join(" ") + QString(");;") +
00132     tr("Any File")+" (*)";
00133 
00134   updateSchNameHash();
00135   updateSpiceNameHash();
00136 
00137   move  (QucsSettings.x,  QucsSettings.y);
00138   resize(QucsSettings.dx, QucsSettings.dy);
00139 
00140   MouseMoveAction = 0;
00141   MousePressAction = 0;
00142   MouseReleaseAction = 0;
00143   MouseDoubleClickAction = 0;
00144 
00145   initView();
00146   initActions();
00147   initMenuBar();
00148   initToolBar();
00149   initStatusBar();
00150   viewToolBar->setChecked(true);
00151   viewStatusBar->setChecked(true);
00152   viewBrowseDock->setChecked(true);
00153   slotViewOctaveDock(false);
00154   slotUpdateRecentFiles();
00155   initCursorMenu();
00156   Module::registerModules ();
00157 
00158   // instance of small text search dialog
00159   SearchDia = new SearchDialog(this);
00160 
00161   // creates a document called "untitled"
00162   Schematic *d = new Schematic(this, "");
00163   int i = DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled"));
00164   DocumentTab->setCurrentIndex(i);
00165 
00166   select->setChecked(true);  // switch on the 'select' action
00167   switchSchematicDoc(true);  // "untitled" document is schematic
00168 
00169   lastExportFilename = QDir::homePath() + QDir::separator() + "export.png";
00170 
00171   // load documents given as command line arguments
00172   for(int z=1; z<qApp->argc(); z++) {
00173     QString arg = qApp->argv()[z];
00174     if(*(arg) != '-') {
00175       QFileInfo Info(arg);
00176       QucsSettings.QucsWorkDir.setPath(Info.absoluteDir().absolutePath());
00177       arg = QucsSettings.QucsWorkDir.filePath(Info.fileName());
00178       gotoPage(arg);
00179     }
00180   }
00181 }
00182 
00183 QucsApp::~QucsApp()
00184 {
00185   Module::unregisterModules ();
00186 }
00187 
00188 
00189 // #######################################################################
00190 // ##########                                                   ##########
00191 // ##########     Creates the working area (QTabWidget etc.)    ##########
00192 // ##########                                                   ##########
00193 // #######################################################################
00197 void QucsApp::initView()
00198 {
00199 
00200 
00201   // set application icon
00202   // APPLE sets the QApplication icon with Info.plist
00203 #ifndef __APPLE__
00204   setWindowIcon (QPixmap(":/bitmaps/big.qucs.xpm"));
00205 #endif
00206 
00207   DocumentTab = new QTabWidget(this);
00208   setCentralWidget(DocumentTab);
00209 
00210   connect(DocumentTab,
00211           SIGNAL(currentChanged(QWidget*)), SLOT(slotChangeView(QWidget*)));
00212 
00213   // Give every tab a close button, and connect the button's signal to
00214   // slotFileClose
00215   DocumentTab->setTabsClosable(true);
00216   connect(DocumentTab,
00217           SIGNAL(tabCloseRequested(int)), SLOT(slotFileClose(int)));
00218 #ifdef HAVE_QTABWIDGET_SETMOVABLE
00219   // make tabs draggable if supported
00220   DocumentTab->setMovable (true);
00221 #endif
00222 
00223   dock = new QDockWidget(tr("Main Dock"),this);
00224   TabView = new QTabWidget(dock);
00225   TabView->setTabPosition(QTabWidget::West);
00226 
00227   connect(dock, SIGNAL(visibilityChanged(bool)), SLOT(slotToggleDock(bool)));
00228 
00229   view = new MouseActions(this);
00230 
00231   editText = new QLineEdit(this);  // for editing component properties
00232   editText->setFrame(false);
00233   editText->setHidden(true);
00234 
00235   QPalette p = palette();
00236   p.setColor(backgroundRole(), QucsSettings.BGColor);
00237   editText->setPalette(p);
00238 
00239   connect(editText, SIGNAL(returnPressed()), SLOT(slotApplyCompText()));
00240   connect(editText, SIGNAL(textChanged(const QString&)),
00241           SLOT(slotResizePropEdit(const QString&)));
00242   connect(editText, SIGNAL(lostFocus()), SLOT(slotHideEdit()));
00243 
00244   // ----------------------------------------------------------
00245   // "Project Tab" of the left QTabWidget
00246   QWidget *ProjGroup = new QWidget();
00247   QVBoxLayout *ProjGroupLayout = new QVBoxLayout();
00248   QWidget *ProjButts = new QWidget();
00249   QPushButton *ProjNew = new QPushButton(tr("New"));
00250   connect(ProjNew, SIGNAL(clicked()), SLOT(slotButtonProjNew()));
00251   QPushButton *ProjOpen = new QPushButton(tr("Open"));
00252   connect(ProjOpen, SIGNAL(clicked()), SLOT(slotButtonProjOpen()));
00253   QPushButton *ProjDel = new QPushButton(tr("Delete"));
00254   connect(ProjDel, SIGNAL(clicked()), SLOT(slotButtonProjDel()));
00255 
00256   QHBoxLayout *ProjButtsLayout = new QHBoxLayout();
00257   ProjButtsLayout->addWidget(ProjNew);
00258   ProjButtsLayout->addWidget(ProjOpen);
00259   ProjButtsLayout->addWidget(ProjDel);
00260   ProjButts->setLayout(ProjButtsLayout);
00261 
00262   ProjGroupLayout->addWidget(ProjButts);
00263 
00264   Projects = new QListView();
00265 
00266   ProjGroupLayout->addWidget(Projects);
00267   ProjGroup->setLayout(ProjGroupLayout);
00268 
00269   TabView->addTab(ProjGroup, tr("Projects"));
00270   TabView->setTabToolTip(TabView->indexOf(ProjGroup), tr("content of project directory"));
00271 
00272   connect(Projects, SIGNAL(doubleClicked(const QModelIndex &)),
00273           this, SLOT(slotListProjOpen(const QModelIndex &)));
00274 
00275   // ----------------------------------------------------------
00276   // "Content" Tab of the left QTabWidget
00277   Content = new ProjectView(this);
00278   Content->setContextMenuPolicy(Qt::CustomContextMenu);
00279 
00280   TabView->addTab(Content, tr("Content"));
00281   TabView->setTabToolTip(TabView->indexOf(Content), tr("content of current project"));
00282 
00283   connect(Content, SIGNAL(clicked(const QModelIndex &)), 
00284           SLOT(slotSelectSubcircuit(const QModelIndex &)));
00285 
00286   connect(Content, SIGNAL(doubleClicked(const QModelIndex &)),
00287           SLOT(slotOpenContent(const QModelIndex &)));
00288 
00289   // ----------------------------------------------------------
00290   // "Component" Tab of the left QTabWidget
00291   QWidget *CompGroup  = new QWidget();
00292   QVBoxLayout *CompGroupLayout = new QVBoxLayout();
00293   QHBoxLayout *CompSearchLayout = new QHBoxLayout();
00294 
00295   CompChoose = new QComboBox(this);
00296   CompComps = new QListWidget(this);
00297   CompComps->setViewMode(QListView::IconMode);
00298   CompComps->setGridSize(QSize(110,90));
00299   CompSearch = new QLineEdit(this);
00300   CompSearch->setPlaceholderText(tr("Search Components"));
00301   CompSearchClear = new QPushButton(tr("Clear"));
00302 
00303   CompGroupLayout->setSpacing(5);
00304   CompGroupLayout->addWidget(CompChoose);
00305   CompGroupLayout->addWidget(CompComps);
00306   CompGroupLayout->addLayout(CompSearchLayout);
00307   CompSearchLayout->addWidget(CompSearch);
00308   CompSearchLayout->addWidget(CompSearchClear);
00309   CompGroup->setLayout(CompGroupLayout);
00310 
00311   TabView->addTab(CompGroup,tr("Components"));
00312   TabView->setTabToolTip(TabView->indexOf(CompGroup), tr("components and diagrams"));
00313   fillComboBox(true);
00314 
00315   slotSetCompView(0);
00316   connect(CompChoose, SIGNAL(activated(int)), SLOT(slotSetCompView(int)));
00317   connect(CompComps, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotSelectComponent(QListWidgetItem*)));
00318   connect(CompComps, SIGNAL(itemPressed(QListWidgetItem*)), SLOT(slotSelectComponent(QListWidgetItem*)));
00319   connect(CompSearch, SIGNAL(textEdited(const QString &)), SLOT(slotSearchComponent(const QString &)));
00320   connect(CompSearchClear, SIGNAL(clicked()), SLOT(slotSearchClear()));
00321 
00322   // ----------------------------------------------------------
00323   // "Libraries" Tab of the left QTabWidget
00324 
00325   QWidget *LibGroup = new QWidget ();
00326   QVBoxLayout *LibGroupLayout = new QVBoxLayout ();
00327   QWidget *LibButts = new QWidget ();
00328   QPushButton *LibManage = new QPushButton (tr ("Manage Libraries"));
00329   connect(LibManage, SIGNAL(clicked()), SLOT(slotCallLibrary()));
00330 
00331   QHBoxLayout *LibButtsLayout = new QHBoxLayout();
00332   LibButtsLayout->addWidget (LibManage);
00333   LibButts->setLayout(LibButtsLayout);
00334 
00335   LibGroupLayout->addWidget(LibButts);
00336 
00337 
00338   libTreeWidget = new QTreeWidget (this);
00339   libTreeWidget->setColumnCount (1);
00340   QStringList headers;
00341   headers.clear ();
00342   headers << tr ("Libraries");
00343   libTreeWidget->setHeaderLabels (headers);
00344 
00345   LibGroupLayout->addWidget (libTreeWidget);
00346   LibGroup->setLayout (LibGroupLayout);
00347 
00348   fillLibrariesTreeView ();
00349 
00350   TabView->addTab (LibGroup, tr("Libraries"));
00351   TabView->setTabToolTip (TabView->indexOf (CompGroup), tr ("system and user component libraries"));
00352 
00353   connect(libTreeWidget, SIGNAL(itemPressed (QTreeWidgetItem*, int)),
00354            SLOT(slotSelectLibComponent (QTreeWidgetItem*)));
00355 
00356   // ----------------------------------------------------------
00357   // put the tab widget in the dock
00358   dock->setWidget(TabView);
00359   dock->setAllowedAreas(Qt::LeftDockWidgetArea);
00360   this->addDockWidget(Qt::LeftDockWidgetArea, dock);
00361   TabView->setCurrentIndex(0);
00362 
00363   // ----------------------------------------------------------
00364   // Octave docking window
00365   octDock = new QDockWidget(tr("Octave Dock"));
00366 
00367   connect(octDock, SIGNAL(visibilityChanged(bool)), SLOT(slotToggleOctave(bool)));
00368   octave = new OctaveWindow(octDock);
00369   this->addDockWidget(Qt::BottomDockWidgetArea, octDock);
00370   this->setCorner(Qt::BottomLeftCorner  , Qt::LeftDockWidgetArea);
00371 
00372   // ............................................
00373 
00374   messageDock = new MessageDock(this);
00375 
00376   // initial home directory model
00377   m_homeDirModel = new QFileSystemModel(this);
00378   QStringList filters;
00379   filters << "*_prj";
00380   m_homeDirModel->setNameFilters(filters);
00381   m_homeDirModel->setNameFilterDisables(false);
00382   m_homeDirModel->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
00383 
00384   // ............................................
00385   readProjects(); // reads all projects and inserts them into the ListBox
00386 }
00387 
00388 // Put all available libraries into ComboBox.
00389 void QucsApp::fillLibrariesTreeView ()
00390 {
00391     QStringList LibFiles;
00392     QStringList::iterator it;
00393     QList<QTreeWidgetItem *> topitems;
00394 
00395     libTreeWidget->clear();
00396 
00397     // make the system libraries section header
00398     QTreeWidgetItem* newitem = new QTreeWidgetItem((QTreeWidget*)0, QStringList("System Libraries"));
00399     newitem->setChildIndicatorPolicy (QTreeWidgetItem::DontShowIndicator);
00400     QFont sectionFont = newitem->font(0);
00401     sectionFont.setItalic (true);
00402     sectionFont.setBold (true);
00403     newitem->setFont (0, sectionFont);
00404 //    newitem->setBackground
00405     topitems.append (newitem);
00406 
00407     QDir LibDir(QucsSettings.LibDir);
00408     LibFiles = LibDir.entryList(QStringList("*.lib"), QDir::Files, QDir::Name);
00409 
00410     // create top level library itmes, base on the library names
00411     for(it = LibFiles.begin(); it != LibFiles.end(); it++)
00412     {
00413         ComponentLibrary parsedlibrary;
00414 
00415         int result = parseComponentLibrary (QucsSettings.LibDir + *it , parsedlibrary);
00416         QStringList nameAndFileName;
00417         nameAndFileName.append (parsedlibrary.name);
00418         nameAndFileName.append (QucsSettings.LibDir + *it);
00419 
00420         QTreeWidgetItem* newlibitem = new QTreeWidgetItem((QTreeWidget*)0, nameAndFileName);
00421 
00422         switch (result)
00423         {
00424             case QUCS_COMP_LIB_IO_ERROR:
00425                 QMessageBox::critical(0, tr ("Error"), tr("Cannot open \"%1\".").arg (*it));
00426                 return;
00427             case QUCS_COMP_LIB_CORRUPT:
00428                 QMessageBox::critical(0, tr("Error"), tr("Library is corrupt."));
00429                 return;
00430             default:
00431                 break;
00432         }
00433 
00434         for (int i = 0; i < parsedlibrary.components.count (); i++)
00435         {
00436             QStringList compNameAndDefinition;
00437 
00438             compNameAndDefinition.append (parsedlibrary.components[i].name);
00439 
00440             QString s = "<Qucs Schematic " PACKAGE_VERSION ">\n";
00441 
00442             s +=  "<Components>\n  " +
00443                   parsedlibrary.components[i].modelString + "\n" +
00444                   "</Components>\n";
00445 
00446             compNameAndDefinition.append (s);
00447 
00448             QTreeWidgetItem* newcompitem = new QTreeWidgetItem(newlibitem, compNameAndDefinition);
00449 
00450             // Silence warning from the compiler about unused variable newcompitem
00451             // we pass the pointer to the parent item in the constructor
00452             Q_UNUSED( newcompitem )
00453         }
00454 
00455         topitems.append (newlibitem);
00456     }
00457 
00458 
00459     // make the user libraries section header
00460     newitem = new QTreeWidgetItem((QTreeWidget*)0, QStringList("User Libraries"));
00461     newitem->setChildIndicatorPolicy (QTreeWidgetItem::DontShowIndicator);
00462     newitem->setFont (0, sectionFont);
00463     topitems.append (newitem);
00464 
00465     QDir UserLibDir = QDir (QucsSettings.QucsHomeDir.canonicalPath () + "/user_lib/");
00466 
00467     // if there are user libraries, add them too
00468     if(UserLibDir.exists ())
00469     {
00470         //LibFiles = UserLibDir.entryList("*.lib", QDir::Files, QDir::Name);
00471         LibFiles = UserLibDir.entryList(QStringList("*.lib"), QDir::Files, QDir::Name);
00472         int UserLibCount = LibFiles.count();
00473 
00474         if (UserLibCount > 0)
00475         {
00476 
00477             // create top level library itmes, base on the library names
00478             for(it = LibFiles.begin(); it != LibFiles.end(); it++)
00479             {
00480                 ComponentLibrary parsedlibrary;
00481 
00482                 int result = parseComponentLibrary (UserLibDir.absolutePath() +"/"+ *it , parsedlibrary);
00483                 QStringList nameAndFileName;
00484                 nameAndFileName.append (parsedlibrary.name);
00485                 nameAndFileName.append (UserLibDir.absolutePath() +"/"+ *it);
00486 
00487                 QTreeWidgetItem* newlibitem = new QTreeWidgetItem((QTreeWidget*)0, nameAndFileName);
00488 
00489                 switch (result)
00490                 {
00491                     case QUCS_COMP_LIB_IO_ERROR:
00492                         QMessageBox::critical(0, tr ("Error"), tr("Cannot open \"%1\".").arg (UserLibDir.absolutePath()+"/" +*it));
00493                         return;
00494                     case QUCS_COMP_LIB_CORRUPT:
00495                         QMessageBox::critical(0, tr("Error"), tr("Library is corrupt."));
00496                         return;
00497                     default:
00498                         break;
00499                 }
00500 
00501                 for (int i = 0; i < parsedlibrary.components.count (); i++)
00502                 {
00503                     QStringList compNameAndDefinition;
00504 
00505                     compNameAndDefinition.append (parsedlibrary.components[i].name);
00506 
00507                     QString s = "<Qucs Schematic " PACKAGE_VERSION ">\n";
00508 
00509                     s +=  "<Components>\n  " +
00510                           parsedlibrary.components[i].modelString + "\n" +
00511                           "</Components>\n";
00512 
00513                     compNameAndDefinition.append (s);
00514 
00515 
00516                     QTreeWidgetItem* newcompitem = new QTreeWidgetItem(newlibitem, compNameAndDefinition);
00517 
00518                     // Silence warning from the compiler about unused variable newcompitem
00519                     // we pass the pointer to the parent item in the constructor
00520                     Q_UNUSED( newcompitem )
00521                 }
00522 
00523                 topitems.append (newlibitem);
00524             }
00525             libTreeWidget->insertTopLevelItems(0, topitems);
00526         }
00527         else
00528         {
00529             // make the user libraries section header
00530             newitem = new QTreeWidgetItem((QTreeWidget*)0, QStringList("No User Libraries"));
00531             sectionFont.setBold (false);
00532             newitem->setFont (0, sectionFont);
00533             topitems.append (newitem);
00534         }
00535     }
00536     else
00537     {
00538         // make the user libraries section header
00539         newitem = new QTreeWidgetItem((QTreeWidget*)0, QStringList("No User Libraries"));
00540         sectionFont.setBold (false);
00541         newitem->setFont (0, sectionFont);
00542         topitems.append (newitem);
00543     }
00544 
00545     libTreeWidget->insertTopLevelItems(0, topitems);
00546 }
00547 
00548 
00549 // ---------------------------------------------------------------
00550 // Returns a pointer to the QucsDoc object whose number is "No".
00551 // If No < 0 then a pointer to the current document is returned.
00552 QucsDoc* QucsApp::getDoc(int No)
00553 {
00554   QWidget *w;
00555   if(No < 0)
00556     w = DocumentTab->currentWidget();
00557   else
00558     w = DocumentTab->widget(No);
00559 
00560   if(w) {
00561     if(isTextDocument (w))
00562       return (QucsDoc*) ((TextDoc*)w);
00563     else
00564       return (QucsDoc*) ((Schematic*)w);
00565   }
00566 
00567   return 0;
00568 }
00569 
00570 // ---------------------------------------------------------------
00571 // Returns a pointer to the QucsDoc object whose file name is "Name".
00572 QucsDoc * QucsApp::findDoc (QString File, int * Pos)
00573 {
00574   QucsDoc * d;
00575   int No = 0;
00576   File = QDir::convertSeparators (File);
00577   while ((d = getDoc (No++)) != 0)
00578     if (QDir::convertSeparators (d->DocName) == File) {
00579       if (Pos) *Pos = No - 1;
00580       return d;
00581     }
00582   return 0;
00583 }
00584 
00585 // ---------------------------------------------------------------
00586 // Put the component groups into the ComboBox. It is possible to
00587 // only put the paintings in it, because of "symbol painting mode".
00588 
00589 // if setAll, add all categories to combobox
00590 // if not, set just paintings (symbol painting mode)
00591 void QucsApp::fillComboBox (bool setAll)
00592 {
00593   //CompChoose->setMaxVisibleItems (13); // Increase this if you add items below.
00594   CompChoose->clear ();
00595 
00596   if (!setAll) {
00597     CompChoose->insertItem(CompChoose->count(), QObject::tr("paintings"));
00598   } else {
00599     QStringList cats = Category::getCategories ();
00600     foreach (QString it, cats) {
00601       CompChoose->insertItem(CompChoose->count(), it);
00602     }
00603   }
00604 }
00605 
00606 // ----------------------------------------------------------
00607 // Whenever the Component Library ComboBox is changed, this slot fills the
00608 // Component IconView with the appropriate components.
00609 void QucsApp::slotSetCompView (int index)
00610 {
00611   //qDebug() << "QucsApp::slotSetCompView(" << index << ")";
00612 
00613   editText->setHidden (true); // disable text edit of component property
00614 
00615   QList<Module *> Comps;
00616   CompComps->clear ();   // clear the IconView
00617   if (CompChoose->count () <= 0) return;
00618 
00619   // was in "search mode" ?
00620   if (CompChoose->itemText(0) == tr("Search results")) {
00621     if (index == 0) // user selected "Search results" item
00622       return;
00623     CompChoose->removeItem(0);
00624     CompSearch->clear();
00625     --index; // adjust requested index since item 0 was removed
00626   }
00627 
00628   // make sure the right index is selected
00629   //  (might have been called by a cleared search and not by user action)
00630   CompChoose->setCurrentIndex(index);
00631   QString item = CompChoose->itemText (index);
00632 
00633   Comps = Category::getModules(item);
00634   QString Name;
00635 
00636   // if something was registered dynamicaly, get and draw icons into dock
00637   if (item == QObject::tr("verilog-a user devices")) {
00638 
00639     QListWidgetItem *icon;
00640     QMapIterator<QString, QString> i(Module::vaComponents);
00641     while (i.hasNext()) {
00642       i.next();
00643 
00644       // default icon initally matches the module name
00645       //Name = i.key();
00646 
00647       // Just need path to bitmap, do not create an object
00648       QString Name, vaBitmap;
00649       Component * c = (Component *)
00650               vacomponent::info (Name, vaBitmap, false, i.value());
00651       if (c) delete c;
00652 
00653       // check if icon exists, fall back to default
00654       QString iconPath = QucsSettings.QucsWorkDir.filePath(vaBitmap+".png");
00655 
00656       QFile iconFile(iconPath);
00657       QPixmap vaIcon;
00658 
00659       if(iconFile.exists())
00660       {
00661         // load bitmap defined on the JSON symbol file
00662         vaIcon = QPixmap(iconPath);
00663       }
00664       else
00665       {
00666         QMessageBox::information(this, tr("Info"),
00667                      tr("Default icon not found:\n %1.png").arg(vaBitmap));
00668         // default icon
00669         vaIcon = QPixmap(":/bitmaps/editdelete.png");
00670       }
00671 
00672       // Add icon an name tag to dock
00673       icon = new QListWidgetItem(vaIcon, Name);
00674       icon->setToolTip(Name);
00675       CompComps->addItem(icon);
00676     }
00677   }
00678   else {
00679     char * File;
00680     // Populate list of component bitmaps
00681     QList<Module *>::const_iterator it;
00682     for (it = Comps.constBegin(); it != Comps.constEnd(); it++) {
00683       if ((*it)->info) {
00685         (void) *((*it)->info) (Name, File, false);
00686         QListWidgetItem *icon = new QListWidgetItem(QPixmap(":/bitmaps/" + QString (File) + ".png"), Name);
00687         icon->setToolTip(Name);
00688         CompComps->addItem(icon);
00689       }
00690     }
00691   }
00692 }
00693 
00694 // ------------------------------------------------------------------
00695 // When CompSearch is being edited, create a temp page show the
00696 // search result
00697 void QucsApp::slotSearchComponent(const QString &searchText)
00698 {
00699   qDebug() << "User search: " << searchText;
00700   CompComps->clear ();   // clear the IconView
00701 
00702   // not already in "search mode"
00703   if (CompChoose->itemText(0) != tr("Search results")) {
00704     ccCurIdx = CompChoose->currentIndex(); // remember current panel
00705     // insert "Search results" at the beginning, so that it is visible
00706     CompChoose->insertItem(-1, tr("Search results"));
00707     CompChoose->setCurrentIndex(0);
00708   }
00709 
00710   if (searchText.isEmpty()) {
00711     slotSetCompView(CompChoose->currentIndex());
00712   } else {
00713     editText->setHidden (true); // disable text edit of component property
00714 
00715     //traverse all component and match searchText with name
00716     QString Name;
00717     char * File;
00718     QList<Module *> Comps;
00719 
00720     QStringList cats = Category::getCategories ();
00721     foreach(QString it, cats) {
00722       Comps = Category::getModules(it);
00723       QList<Module *>::const_iterator modit;
00724       for (modit = Comps.constBegin(); modit != Comps.constEnd(); modit++) {
00725         if ((*modit)->info) {
00727           (void) *((*modit)->info) (Name, File, false);
00728 
00729           if((Name.indexOf(searchText, 0, Qt::CaseInsensitive)) != -1) {
00730             //match
00731             QListWidgetItem *icon = new QListWidgetItem(QPixmap(":/bitmaps/" + QString (File) + ".png"), Name);
00732             icon->setToolTip(it + ": " + Name);
00733             CompComps->addItem(icon);
00734           }
00735         }
00736       }
00737     }
00738     QMapIterator<QString, QString> i(Module::vaComponents);
00739     while (i.hasNext()) {
00740       i.next();
00741 
00742       // Just need path to bitmap, do not create an object
00743       QString Name, vaBitmap;
00744       vacomponent::info (Name, vaBitmap, false, i.value());
00745 
00746       if((Name.indexOf(searchText, 0, Qt::CaseInsensitive)) != -1) {
00747         //match
00748 
00749         // check if icon exists, fall back to default
00750         QString iconPath = QucsSettings.QucsWorkDir.filePath(vaBitmap+".png");
00751 
00752         QFile iconFile(iconPath);
00753         QPixmap vaIcon;
00754 
00755         if(iconFile.exists())
00756         {
00757           // load bitmap defined on the JSON symbol file
00758           vaIcon = QPixmap(iconPath);
00759         }
00760         else
00761         {
00762           // default icon
00763           vaIcon = QPixmap(":/bitmaps/editdelete.png");
00764         }
00765 
00766         // Add icon an name tag to dock
00767         QListWidgetItem *icon = new QListWidgetItem(vaIcon, Name);
00768         icon->setToolTip(tr("verilog-a user devices") + ": " + Name);
00769         CompComps->addItem(icon);
00770       }
00771     }
00772   }
00773 }
00774 
00775 // ------------------------------------------------------------------
00776 void QucsApp::slotSearchClear()
00777 {
00778   // was in "search mode" ?
00779   if (CompChoose->itemText(0) == tr("Search results")) {
00780     CompChoose->removeItem(0); // remove the added "Search results" item
00781     CompSearch->clear();
00782     // go back to the panel selected before search started
00783     slotSetCompView(ccCurIdx);
00784     // the added "Search results" panel text will be removed by slotSetCompView()
00785   }
00786 }
00787 
00788 // ------------------------------------------------------------------
00789 // Is called when the mouse is clicked within the Component QIconView.
00790 void QucsApp::slotSelectComponent(QListWidgetItem *item)
00791 {
00792   slotHideEdit(); // disable text edit of component property
00793 
00794   // delete previously selected elements
00795   if(view->selElem != 0)  delete view->selElem;
00796   view->selElem  = 0;   // no component/diagram/painting selected
00797 
00798   if(item == 0) {   // mouse button pressed not over an item ?
00799     CompComps->clearSelection();  // deselect component in ViewList
00800     return;
00801   }
00802 
00803   if(view->drawn)
00804     ((Q3ScrollView*)DocumentTab->currentWidget())->viewport()->update();
00805   view->drawn = false;
00806 
00807   // toggle last toolbar button off
00808   if(activeAction) {
00809     activeAction->blockSignals(true); // do not call toggle slot
00810     activeAction->setChecked(false);       // set last toolbar button off
00811     activeAction->blockSignals(false);
00812   }
00813   activeAction = 0;
00814 
00815   MouseMoveAction = &MouseActions::MMoveElement;
00816   MousePressAction = &MouseActions::MPressElement;
00817   MouseReleaseAction = 0;
00818   MouseDoubleClickAction = 0;
00819 
00820   pInfoFunc Infos = 0;
00821   pInfoVAFunc InfosVA = 0;
00822 
00823   int i = CompComps->row(item);
00824   QList<Module *> Comps;
00825 
00826   // if symbol mode, only paintings are enabled.
00827   Comps = Category::getModules(CompChoose->currentText());
00828   qDebug() << "pressed CompComps id" << i;
00829   qDebug() << CompComps->item(i)->text(); //Name;
00830 
00831   QString name = CompComps->item(i)->text();
00832   QString CompName;
00833   QString CompFile_qstr;
00834   char *CompFile_cptr;
00835 
00836   if (!CompSearch->text().isEmpty()) {
00837     //comp search is not empty, search all category to get a component in same name
00838     QStringList cats = Category::getCategories();
00839     int i = 0;
00840     //search normal component
00841     foreach (QString it, cats) {
00842       Comps = Category::getModules (it);
00843       foreach(Module *mod, Comps) {
00844         if (mod->info) {
00845           (*mod->info)(CompName, CompFile_cptr, false);
00846           if (CompName == name) {
00847       // change currently selected category, so the user will 
00848       //   learn where the component comes from
00849             CompChoose->setCurrentIndex(i+1); // +1 due to the added "Search Results" item
00850       ccCurIdx = i; // remember the category to select when exiting search
00853             view->selElem = (*mod->info) (CompName, CompFile_cptr, true);
00854       // TODO: component found, exit the loops now...
00855           }
00856         }
00857       }
00858       i++;
00859     }
00860     //search verilog-a component
00861     i = CompChoose->findText(QObject::tr("verilog-a user devices"));
00862     QMapIterator<QString, QString> it(Module::vaComponents);
00863     while (it.hasNext()) {
00864       it.next();
00865 
00866       // Just need vacomponent name, do not create an object
00867       QString Name, vaBitmap;
00868       vacomponent::info (Name, vaBitmap, false, it.value());
00869 
00870       if (Name == name) {
00871         view->selElem = vacomponent::info(CompName, CompFile_qstr, true, it.value());
00872       }
00873     }
00874   } else {
00875     // handle static and dynamic components
00876     if (CompChoose->currentText() == QObject::tr("verilog-a user devices")){
00877       InfosVA = Comps.at(i)->infoVA;
00878 
00879       // get JSON file out of item name on widgetitem
00880       QString filename = Module::vaComponents[name];
00881 
00882       if (InfosVA) {
00883         qDebug() <<  " slotSelectComponent, view->selElem" ;
00884         view->selElem = (*InfosVA) (CompName, CompFile_qstr, true, filename);
00885       }
00886     }
00887     else {
00888       Infos = Comps.at(i)->info;
00889 
00890       if (Infos)
00891         view->selElem = (*Infos) (CompName, CompFile_cptr, true);
00892     }
00893   }
00894 }
00895 
00896 // ####################################################################
00897 // #####  Functions for the menu that appears when right-clicking #####
00898 // #####  on a file in the "Content" ListView.                    #####
00899 // ####################################################################
00900 
00901 void QucsApp::initCursorMenu()
00902 {
00903   ContentMenu = new QMenu(this);
00904 #define APPEND_MENU(action, slot, text) \
00905   { \
00906   action = new QAction(tr(text), ContentMenu); \
00907   connect(action, SIGNAL(triggered()), SLOT(slot())); \
00908   ContentMenu->addAction(action); \
00909   }
00910   
00911   APPEND_MENU(ActionCMenuOpen, slotCMenuOpen, "Open")
00912   APPEND_MENU(ActionCMenuCopy, slotCMenuCopy, "Duplicate")
00913   APPEND_MENU(ActionCMenuRename, slotCMenuRename, "Rename")
00914   APPEND_MENU(ActionCMenuDelete, slotCMenuDelete, "Delete")
00915   APPEND_MENU(ActionCMenuInsert, slotCMenuInsert, "Insert")
00916 
00917 #undef APPEND_MENU
00918   connect(Content, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slotShowContentMenu(const QPoint&)));
00919 }
00920 
00921 // ----------------------------------------------------------
00922 // Shows the menu.
00923 void QucsApp::slotShowContentMenu(const QPoint& pos) 
00924 {
00925   QModelIndex idx = Content->indexAt(pos);
00926   if (idx.isValid() && idx.parent().isValid()) {
00927     ActionCMenuInsert->setVisible(
00928         idx.sibling(idx.row(), 1).data().toString().contains(tr("-port"))
00929     );
00930     ContentMenu->popup(Content->mapToGlobal(pos));
00931   }    
00932 }
00933 
00934 // ----------------------------------------------------------
00935 QString QucsApp::fileType (const QString& Ext)
00936 {
00937   QString Type = tr("unknown");
00938   if (Ext == "v")
00939     Type = tr("Verilog source");
00940   else if (Ext == "va")
00941     Type = tr("Verilog-A source");
00942   else if (Ext == "vhd" || Ext == "vhdl")
00943     Type = tr("VHDL source");
00944   else if (Ext == "dat")
00945     Type = tr("data file");
00946   else if (Ext == "dpl")
00947     Type = tr("data display");
00948   else if (Ext == "sch")
00949     Type = tr("schematic");
00950   else if (Ext == "sym")
00951     Type = tr("symbol");
00952   else if (Ext == "vhdl.cfg" || Ext == "vhd.cfg")
00953     Type = tr("VHDL configuration");
00954   else if (Ext == "cfg")
00955     Type = tr("configuration");
00956   return Type;
00957 }
00958 
00959 void QucsApp::slotCMenuOpen()
00960 {
00961   slotOpenContent(Content->currentIndex());
00962 }
00963 
00964 void QucsApp::slotCMenuCopy()
00965 {
00966   QModelIndex idx = Content->currentIndex();
00967 
00968   //test the item is valid
00969   if (!idx.isValid() || !idx.parent().isValid()) { return; }
00970 
00971   QString filename = idx.sibling(idx.row(), 0).data().toString();
00972   QDir dir(QucsSettings.QucsWorkDir);
00973   QString file(dir.filePath(filename));
00974   QFileInfo fileinfo(file);
00975 
00976   //check changed file save
00977   int z = 0; //search if the doc is loaded
00978   QucsDoc *d = findDoc(file, &z);
00979   if (d != NULL && d->DocChanged) {
00980     DocumentTab->setCurrentIndex(z);
00981     int ret = QMessageBox::question(this, tr("Copying Qucs document"), 
00982         tr("The document contains unsaved changes!\n") + 
00983         tr("Do you want to save the changes before copying?"),
00984         tr("&Ignore"), tr("&Save"), 0, 1);
00985     if (ret == 1) {
00986       d->save();
00987     }
00988   }
00989 
00990   QString suffix = fileinfo.suffix();
00991   QString base = fileinfo.completeBaseName();
00992   if(base.isEmpty()) {
00993     base = filename;
00994   }
00995 
00996   bool exists = true;   //generate unique name
00997   int i = 0;
00998   QString defaultName;
00999   while (exists) {
01000     ++i;
01001     defaultName = base + "_copy" + QString::number(i) + "." + suffix;
01002     exists = QFile::exists(dir.filePath(defaultName));
01003   }
01004 
01005   bool ok;
01006   QString s = QInputDialog::getText(this, tr("Copy file"), tr("Enter new name:"), QLineEdit::Normal, defaultName, &ok);
01007 
01008   if(ok && !s.isEmpty()) {
01009     if (!s.endsWith(suffix)) {
01010       s += QString(".") + suffix;
01011     }
01012 
01013     if (QFile::exists(dir.filePath(s))) {  //check New Name exists
01014       QMessageBox::critical(this, tr("error"), tr("Cannot copy file to identical name: %1").arg(filename));
01015       return;
01016     }
01017 
01018     if (!QFile::copy(dir.filePath(filename), dir.filePath(s))) {
01019       QMessageBox::critical(this, tr("Error"), tr("Cannot copy schematic: %1").arg(filename));
01020       return;
01021     }
01022     //TODO: maybe require disable edit here
01023 
01024     // refresh the schematic file path
01025     this->updateSchNameHash();
01026     this->updateSpiceNameHash();
01027 
01028     slotUpdateTreeview();
01029   }
01030 }
01031 
01032 void QucsApp::slotCMenuRename()
01033 {
01034   QModelIndex idx = Content->currentIndex();
01035 
01036   //test the item is valid
01037   if (!idx.isValid() || !idx.parent().isValid()) { return; }
01038 
01039   QString filename = idx.sibling(idx.row(), 0).data().toString();
01040   QString file(QucsSettings.QucsWorkDir.filePath(filename));
01041   QFileInfo fileinfo(file);
01042 
01043   if (findDoc(file)) {
01044     QMessageBox::critical(this, tr("Error"),
01045         tr("Cannot rename an open file!"));
01046     return;
01047   }
01048 
01049   QString suffix = fileinfo.suffix();
01050   QString base = fileinfo.completeBaseName();
01051   if(base.isEmpty()) {
01052     base = filename;
01053   }
01054 
01055   bool ok;
01056   QString s = QInputDialog::getText(this, tr("Rename file"), tr("Enter new filename:"), QLineEdit::Normal, base, &ok);
01057 
01058   if(ok && !s.isEmpty()) { 
01059     if (!s.endsWith(suffix)) {
01060       s += QString(".") + suffix;
01061     }
01062     QDir dir(QucsSettings.QucsWorkDir.path());
01063     if(!dir.rename(filename, s)) {
01064       QMessageBox::critical(this, tr("Error"), tr("Cannot rename file: %1").arg(filename));
01065       return;
01066     }
01067 
01068     slotUpdateTreeview();
01069   }
01070 }
01071 
01072 void QucsApp::slotCMenuDelete()
01073 {
01074   QModelIndex idx = Content->currentIndex();
01075 
01076   //test the item is valid
01077   if (!idx.isValid() || !idx.parent().isValid()) { return; }
01078 
01079   QString filename = idx.sibling(idx.row(), 0).data().toString();
01080   QString file(QucsSettings.QucsWorkDir.filePath(filename));
01081 
01082   if (findDoc (file)) {
01083     QMessageBox::critical(this, tr("Error"), tr("Cannot delete an open file!"));
01084     return;
01085   }
01086 
01087   int No;
01088   No = QMessageBox::warning(this, tr("Warning"),
01089       tr("This will delete the file permanently! Continue ?"),
01090       tr("No"), tr("Yes"));
01091   if(No == 1) {
01092     if(!QFile::remove(file)) {
01093       QMessageBox::critical(this, tr("Error"),
01094       tr("Cannot delete file: %1").arg(filename));
01095       return;
01096     }
01097   }
01098 
01099   slotUpdateTreeview();
01100 }
01101 
01102 void QucsApp::slotCMenuInsert()
01103 {
01104   slotSelectSubcircuit(Content->currentIndex());
01105 }
01106 
01107 // ################################################################
01108 // #####    Functions that handle the project operations.     #####
01109 // ################################################################
01110 
01111 // Checks for qucs directory and reads all existing Qucs projects.
01112 void QucsApp::readProjects()
01113 {
01114   QString path = QucsSettings.QucsHomeDir.absolutePath();
01115   QDir ProjDir(path);
01116 
01117   // create home dir if not exist
01118   if(!ProjDir.exists()) {
01119     if(!ProjDir.mkdir(path)) {
01120       QMessageBox::warning(this, tr("Warning"),
01121           tr("Cannot create work directory !"));
01122       return;
01123     }
01124   }
01125   m_homeDirModel->setRootPath(path);
01126   Projects->setModel(m_homeDirModel);
01127   Projects->setRootIndex(m_homeDirModel->index(path));
01128 }
01129 
01130 // ----------------------------------------------------------
01131 // Is called, when "Create New Project" button is pressed.
01132 void QucsApp::slotButtonProjNew()
01133 {
01134   slotHideEdit(); // disable text edit of component property
01135 
01136   NewProjDialog *d = new NewProjDialog(this);
01137   if(d->exec() != QDialog::Accepted) return;
01138 
01139   QDir projDir(QucsSettings.QucsHomeDir.path());
01140   QString name = d->ProjName->text();
01141   bool open = d->OpenProj->isChecked();
01142 
01143   if (!name.endsWith("_prj")) {
01144     name += "_prj";
01145   }
01146 
01147   if(!projDir.mkdir(name)) {
01148     QMessageBox::information(this, tr("Info"),
01149         tr("Cannot create project directory !"));
01150   }
01151   if(open) {
01152     openProject(QucsSettings.QucsHomeDir.filePath(name));
01153   }
01154 }
01155 
01156 // ----------------------------------------------------------
01157 // Opens an existing project.
01158 void QucsApp::openProject(const QString& Path)
01159 {
01160   slotHideEdit(); // disable text edit of component property
01161 
01162   QString Name = Path;
01163   if (Name.endsWith(QDir::separator())) {
01164     Name = Name.left(Name.length()-1);  // cut off trailing '/'
01165   }
01166   int i = Name.lastIndexOf(QDir::separator());
01167   if(i > 0) Name = Name.mid(i+1);   // cut out the last subdirectory
01168   Name.remove("_prj");
01169 
01170   if(!closeAllFiles()) return;   // close files and ask for saving them
01171   Schematic *d = new Schematic(this, "");
01172   i = DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled"));
01173   DocumentTab->setCurrentIndex(i);
01174 
01175   view->drawn = false;
01176 
01177   slotResetWarnings();
01178 
01179   QDir ProjDir(QDir::cleanPath(Path));
01180   if(!ProjDir.exists() || !ProjDir.isReadable()) { // check project directory
01181     QMessageBox::critical(this, tr("Error"),
01182                           tr("Cannot access project directory: ")+Path);
01183     return;
01184   }
01185   QucsSettings.QucsWorkDir.setPath(ProjDir.path());
01186   octave->adjustDirectory();
01187 
01188   Content->setProjPath(QucsSettings.QucsWorkDir.absolutePath());
01189 
01190   TabView->setCurrentIndex(1);   // switch to "Content"-Tab
01191   ProjName = Name;   // remember the name of project
01192 
01193   // show name in title of main window
01194   setWindowTitle("Qucs " PACKAGE_VERSION + tr(" - Project: ")+Name);
01195 }
01196 
01197 // ----------------------------------------------------------
01198 // Is called when the open project menu is called.
01199 void QucsApp::slotMenuProjOpen()
01200 {
01201   QString d = QFileDialog::getExistingDirectory(
01202       this, tr("Choose Project Directory for Opening"),
01203       QucsSettings.QucsHomeDir.path(),
01204       QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
01205   if(d.isEmpty()) return;
01206 
01207   openProject(d);
01208 }
01209 
01210 // ----------------------------------------------------------
01211 // Is called, when "Open Project" button is pressed.
01212 void QucsApp::slotButtonProjOpen()
01213 {
01214   slotHideEdit();
01215 
01216   QModelIndex idx = Projects->currentIndex();
01217   if (!idx.isValid()) {
01218     QMessageBox::information(this, tr("Info"),
01219         tr("No project is selected !"));
01220   } else {
01221     slotListProjOpen(idx);
01222   }
01223 }
01224 
01225 // ----------------------------------------------------------
01226 // Is called when project is double-clicked to open it.
01227 void QucsApp::slotListProjOpen(const QModelIndex &idx)
01228 {
01229   openProject(QucsSettings.QucsHomeDir.filePath(
01230       idx.data().toString()));
01231 }
01232 
01233 // ----------------------------------------------------------
01234 // Is called when the close project menu is called.
01235 void QucsApp::slotMenuProjClose()
01236 {
01237   slotHideEdit(); // disable text edit of component property
01238 
01239   if(!closeAllFiles()) return;   // close files and ask for saving them
01240   Schematic *d = new Schematic(this, "");
01241   int i = DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled"));
01242   DocumentTab->setCurrentIndex(i);
01243 
01244   view->drawn = false;
01245 
01246   slotResetWarnings();
01247   setWindowTitle("Qucs " PACKAGE_VERSION + tr(" - Project: "));
01248   QucsSettings.QucsWorkDir.setPath(QDir::homePath()+QDir::convertSeparators ("/.qucs"));
01249   octave->adjustDirectory();
01250 
01251   Content->setProjPath("");
01252 
01253   TabView->setCurrentIndex(0);   // switch to "Projects"-Tab
01254   ProjName = "";
01255 }
01256 
01257 // remove a directory recursively
01258 bool QucsApp::recurRemove(const QString &Path)
01259 {
01260   bool result = true;
01261   QDir projDir = QDir(Path);
01262 
01263   if (projDir.exists(Path)) {
01264     Q_FOREACH(QFileInfo info, 
01265         projDir.entryInfoList(
01266             QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::AllEntries, QDir::DirsFirst)) {
01267       if (info.isDir()) {
01268         result = recurRemove(info.absoluteFilePath());
01269         if (!result) {
01270           QMessageBox::information(this, tr("Info"),
01271               tr("Cannot remove directory: %1").arg(Path));
01272           return false;
01273         }
01274       }
01275       else if(info.isFile()) {
01276         result = QFile::remove(info.absoluteFilePath());
01277         if (!result) {
01278           QMessageBox::information(this, tr("Info"),
01279               tr("Cannot delete file: %1").arg(info.fileName()));
01280           return false;
01281         }
01282       }
01283     }
01284     result = projDir.rmdir(Path);
01285   }
01286   return result;
01287 }
01288 
01289 // ----------------------------------------------------------
01290 bool QucsApp::deleteProject(const QString& Path)
01291 {
01292   slotHideEdit();
01293 
01294   QString Name = Path;
01295 
01296   if(Name.isEmpty()) return false;
01297 
01298   if (Name.endsWith(QDir::separator())) {
01299     Name = Name.left(Name.length()-1);  // cut off trailing '/'
01300   }
01301   int i = Name.lastIndexOf(QDir::separator());
01302   if(i > 0) Name = Name.mid(i+1);  // cut out the last subdirectory
01303   Name.chop(4); // remove "_prj" from name
01304 
01305   if(Name == ProjName) {
01306     QMessageBox::information(this, tr("Info"),
01307         tr("Cannot delete an open project !"));
01308     return false;
01309   }
01310 
01311   // first ask, if really delete project ?
01312   if(QMessageBox::warning(this, tr("Warning"),
01313       tr("This will destroy all the project files permanently ! Continue ?"),
01314       tr("&Yes"), tr("&No"), 0,1,1))  return false;
01315 
01316   if (!recurRemove(Path)) {
01317     QMessageBox::information(this, tr("Info"),
01318         tr("Cannot remove project directory!"));
01319     return false;
01320   }
01321   return true;
01322 }
01323 
01324 // ----------------------------------------------------------
01325 // Is called, when "Delete Project" menu is activated.
01326 void QucsApp::slotMenuProjDel()
01327 {
01328   QString d = QFileDialog::getExistingDirectory(
01329       this, tr("Choose Project Directory for Deleting"),
01330       QucsSettings.QucsHomeDir.path(),
01331       QFileDialog::ShowDirsOnly
01332       | QFileDialog::DontResolveSymlinks);
01333 
01334   deleteProject(d);
01335 }
01336 
01337 // ----------------------------------------------------------
01338 // Is called, when "Delete Project" button is pressed.
01339 void QucsApp::slotButtonProjDel()
01340 {
01341   QModelIndex idx = Projects->currentIndex();
01342   if(!idx.isValid()) {
01343     QMessageBox::information(this, tr("Info"),
01344         tr("No project is selected!"));
01345     return;
01346   }
01347 
01348   deleteProject(QucsSettings.QucsHomeDir.filePath(idx.data().toString()));
01349 }
01350 
01351 
01352 // ################################################################
01353 // #####  Functions that handle the file operations for the   #####
01354 // #####  documents.                                          #####
01355 // ################################################################
01356 
01357 void QucsApp::slotFileNew()
01358 {
01359   statusBar()->showMessage(tr("Creating new schematic..."));
01360   slotHideEdit(); // disable text edit of component property
01361 
01362   Schematic *d = new Schematic(this, "");
01363   int i = DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled"));
01364   DocumentTab->setCurrentIndex(i);
01365 
01366   statusBar()->showMessage(tr("Ready."));
01367 }
01368 
01369 // --------------------------------------------------------------
01370 void QucsApp::slotTextNew()
01371 {
01372   statusBar()->showMessage(tr("Creating new text editor..."));
01373   slotHideEdit(); // disable text edit of component property
01374   TextDoc *d = new TextDoc(this, "");
01375   int i = DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled"));
01376   DocumentTab->setCurrentIndex(i);
01377 
01378   statusBar()->showMessage(tr("Ready."));
01379 }
01380 
01381 // --------------------------------------------------------------
01382 // Changes to the document "Name". If already open then it goes to it
01383 // directly, otherwise it loads it.
01384 bool QucsApp::gotoPage(const QString& Name)
01385 {
01386   int No = DocumentTab->currentIndex();
01387 
01388   int i = 0;
01389   QucsDoc * d = findDoc (Name, &i);  // search, if page is already loaded
01390 
01391   if(d) {   // open page found ?
01392     d->becomeCurrent(true);
01393     DocumentTab->setCurrentIndex(i);  // make new document the current
01394     return true;
01395   }
01396 
01397   QFileInfo Info(Name);
01398   if(Info.suffix() == "sch" || Info.suffix() == "dpl" ||
01399      Info.suffix() == "sym") {
01400     d = new Schematic(this, Name);
01401     i = DocumentTab->addTab((Schematic *)d, QPixmap(empty_xpm), Info.fileName()); 
01402   }
01403   else {
01404     d = new TextDoc(this, Name);
01405     i = DocumentTab->addTab((TextDoc *)d, QPixmap(empty_xpm), Info.fileName());
01406   }
01407   DocumentTab->setCurrentIndex(i);
01408 
01409   if(!d->load()) {    // load document if possible
01410     delete d;
01411     DocumentTab->setCurrentIndex(No);
01412     view->drawn = false;
01413     return false;
01414   }
01415   slotChangeView(DocumentTab->currentWidget());
01416 
01417   // if only an untitled document was open -> close it
01418   if(getDoc(0)->DocName.isEmpty())
01419     if(!getDoc(0)->DocChanged)
01420       delete DocumentTab->widget(0);
01421 
01422   view->drawn = false;
01423   return true;
01424 }
01425 
01426 QString lastDirOpenSave; // to remember last directory and file
01427 
01428 // --------------------------------------------------------------
01429 void QucsApp::slotFileOpen()
01430 {
01431   slotHideEdit(); // disable text edit of component property
01432 
01433   statusBar()->showMessage(tr("Opening file..."));
01434 
01435   QString s = QFileDialog::getOpenFileName(this, tr("Enter a Schematic Name"),
01436     lastDirOpenSave.isEmpty() ? QString(".") : lastDirOpenSave, QucsFileFilter);
01437 
01438   if(s.isEmpty())
01439     statusBar()->showMessage(tr("Opening aborted"), 2000);
01440   else {
01441     updateRecentFilesList(s);
01442 
01443     gotoPage(s);
01444     lastDirOpenSave = s;   // remember last directory and file
01445 
01446     statusBar()->showMessage(tr("Ready."));
01447   }
01448 }
01449 
01450 // --------------------------------------------------------------
01451 bool QucsApp::saveFile(QucsDoc *Doc)
01452 {
01453   if(!Doc)
01454     Doc = getDoc();
01455 
01456   if(Doc->DocName.isEmpty())
01457     return saveAs();
01458 
01459   int Result = Doc->save();
01460   if(Result < 0)  return false;
01461 
01462   updatePortNumber(Doc, Result);
01463   slotUpdateTreeview();
01464   return true;
01465 }
01466 
01467 // --------------------------------------------------------------
01468 void QucsApp::slotFileSave()
01469 {
01470   statusBar()->showMessage(tr("Saving file..."));
01471   DocumentTab->blockSignals(true);   // no user interaction during that time
01472   slotHideEdit(); // disable text edit of component property
01473 
01474   if(!saveFile()) {
01475     DocumentTab->blockSignals(false);
01476     statusBar()->showMessage(tr("Saving aborted"), 2000);
01477     statusBar()->showMessage(tr("Ready."));
01478     return;
01479   }
01480 
01481   DocumentTab->blockSignals(false);
01482   statusBar()->showMessage(tr("Ready."));
01483 
01484   if(!ProjName.isEmpty())
01485     slotUpdateTreeview();
01486 }
01487 
01488 // --------------------------------------------------------------
01489 bool QucsApp::saveAs()
01490 {
01491   QWidget *w = DocumentTab->currentWidget();
01492   QucsDoc *Doc = getDoc();
01493 
01494   int n = -1;
01495   QString s, Filter;
01496   QFileInfo Info;
01497   while(true) {
01498     s = Doc->DocName;
01499     Info.setFile(s);
01500     if(s.isEmpty()) {   // which is default directory ?
01501       if(ProjName.isEmpty()) {
01502         if(lastDirOpenSave.isEmpty())  s = QDir::currentPath();
01503         else  s = lastDirOpenSave;
01504       }
01505       else s = QucsSettings.QucsWorkDir.path();
01506     }
01507 
01508     // list of known file extensions
01509     QString ext = "vhdl;vhd;v;va;sch;dpl;m;oct;net;qnet;txt";
01510     QStringList extlist = ext.split (';');
01511 
01512     if(isTextDocument (w))
01513       Filter = tr("VHDL Sources")+" (*.vhdl *.vhd);;" +
01514          tr("Verilog Sources")+" (*.v);;"+
01515          tr("Verilog-A Sources")+" (*.va);;"+
01516          tr("Octave Scripts")+" (*.m *.oct);;"+
01517          tr("Qucs Netlist")+" (*.net *.qnet);;"+
01518          tr("Plain Text")+" (*.txt);;"+
01519          tr("Any File")+" (*)";
01520     else
01521       Filter = QucsFileFilter;
01522 
01523     s = QFileDialog::getSaveFileName(this, tr("Enter a Document Name"),
01524                                      QucsSettings.QucsWorkDir.absolutePath(),
01525                                      Filter);
01526     if(s.isEmpty())  return false;
01527     Info.setFile(s);               // try to guess the best extension ...
01528     ext = Info.suffix();
01529 
01530     if(ext.isEmpty() || !extlist.contains(ext))
01531     {
01532       // if no extension was specified or is unknown
01533       if (!isTextDocument (w))
01534       {
01535         // assume it is a schematic
01536         s += ".sch";
01537       }
01538     }
01539 
01540     Info.setFile(s);
01541     if(QFile::exists(s)) {
01542       n = QMessageBox::warning(this, tr("Warning"),
01543     tr("The file '")+Info.fileName()+tr("' already exists!\n")+
01544     tr("Saving will overwrite the old one! Continue?"),
01545     tr("No"), tr("Yes"), tr("Cancel"));
01546       if(n == 2) return false;    // cancel
01547       if(n == 0) continue;
01548     }
01549 
01550     // search, if document is open
01551     QucsDoc * d = findDoc (s);
01552     if(d) {
01553       QMessageBox::information(this, tr("Info"),
01554     tr("Cannot overwrite an open document"));
01555       return false;
01556     }
01557 
01558     break;
01559   }
01560   Doc->setName(s);
01561   DocumentTab->setTabText(DocumentTab->indexOf(w), misc::properFileName(s));
01562   lastDirOpenSave = Info.absolutePath();  // remember last directory and file
01563   updateRecentFilesList(s);
01564 
01565   n = Doc->save();   // SAVE
01566   if(n < 0)  return false;
01567 
01568   updatePortNumber(Doc, n);
01569   slotUpdateTreeview();
01570   return true;
01571 }
01572 
01573 // --------------------------------------------------------------
01574 void QucsApp::slotFileSaveAs()
01575 {
01576   statusBar()->showMessage(tr("Saving file under new filename..."));
01577   DocumentTab->blockSignals(true);   // no user interaction during the time
01578   slotHideEdit(); // disable text edit of component property
01579 
01580   if(!saveAs()) {
01581     DocumentTab->blockSignals(false);
01582     statusBar()->showMessage(tr("Saving aborted"), 3000);
01583     statusBar()->showMessage(tr("Ready."));
01584     return;
01585   }
01586 
01587   DocumentTab->blockSignals(false);
01588   statusBar()->showMessage(tr("Ready."));
01589 
01590   // refresh the schematic file path
01591   slotRefreshSchPath();
01592 
01593   if(!ProjName.isEmpty())
01594     slotUpdateTreeview();
01595 }
01596 
01597 
01598 // --------------------------------------------------------------
01599 void QucsApp::slotFileSaveAll()
01600 {
01601   statusBar()->showMessage(tr("Saving all files..."));
01602   slotHideEdit(); // disable text edit of component property
01603   DocumentTab->blockSignals(true);   // no user interaction during the time
01604 
01605   int No=0;
01606   QucsDoc *Doc;  // search, if page is already loaded
01607   while((Doc=getDoc(No++)) != 0) {
01608     if(Doc->DocName.isEmpty())  // make document the current ?
01609       DocumentTab->setCurrentIndex(No-1);
01610     if (saveFile(Doc)) { // Hack! TODO: Maybe it's better to let slotFileChanged()
01611         DocumentTab->setTabIcon(No-1,QPixmap(empty_xpm)); // know about Tab number?
01612     }
01613   }
01614 
01615   DocumentTab->blockSignals(false);
01616   // Call update() to update subcircuit symbols in current Schematic document.
01617   // TextDoc has no viewport, it needs no update.
01618   QString tabType = DocumentTab->currentWidget()->metaObject()->className();
01619 
01620   if (tabType == "Schematic") {
01621     ((Q3ScrollView*)DocumentTab->currentWidget())->viewport()->update();
01622   }
01623   view->drawn = false;
01624   statusBar()->showMessage(tr("Ready."));
01625 
01626   // refresh the schematic file path
01627   slotRefreshSchPath();
01628   slotUpdateTreeview();
01629 }
01630 
01631 // --------------------------------------------------------------
01632 // Close the currently active file tab
01633 void QucsApp::slotFileClose()
01634 {
01635     // Using file index -1 closes the currently active file window
01636     closeFile(-1);
01637 }
01638 
01639 // --------------------------------------------------------------
01640 // Close the file tab specified by its index
01641 void QucsApp::slotFileClose(int index)
01642 {
01643     // Call closeFile with a specific tab index
01644     closeFile(index);
01645 }
01646 
01647 // --------------------------------------------------------------
01648 // Common function to close a file tab specified by its index
01649 // checking for changes in the file before doing so. If called
01650 // index == -1, the active document will be closed
01651 void QucsApp::closeFile(int index)
01652 {
01653     statusBar()->showMessage(tr("Closing file..."));
01654 
01655     slotHideEdit(); // disable text edit of component property
01656 
01657     QucsDoc *Doc = getDoc(index);
01658     if(Doc->DocChanged) {
01659       switch(QMessageBox::warning(this,tr("Closing Qucs document"),
01660         tr("The document contains unsaved changes!\n")+
01661         tr("Do you want to save the changes before closing?"),
01662         tr("&Save"), tr("&Discard"), tr("Cancel"), 0, 2)) {
01663         case 0 : slotFileSave();
01664                  break;
01665         case 2 : return;
01666       }
01667     }
01668 
01669     DocumentTab->removeTab(index);
01670     delete Doc;
01671 
01672     if(DocumentTab->count() < 1) { // if no document left, create an untitled
01673       Schematic *d = new Schematic(this, "");
01674       DocumentTab->addTab(d, QPixmap(empty_xpm), QObject::tr("untitled")); 
01675       DocumentTab->setCurrentIndex(0);
01676     }
01677 
01678     statusBar()->showMessage(tr("Ready."));
01679 }
01680 
01681 
01682 // --------------------------------------------------------------
01683 bool QucsApp::closeAllFiles()
01684 {
01685   SaveDialog *sd = new SaveDialog(this);
01686   sd->setApp(this);
01687   for(int i=0; i < DocumentTab->count(); ++i) {
01688     QucsDoc *doc = getDoc(i);
01689     if(doc->DocChanged)
01690       sd->addUnsavedDoc(doc);
01691   }
01692   int Result = SaveDialog::DontSave;
01693   if(!sd->isEmpty())
01694      Result = sd->exec();
01695   delete sd;
01696   if(Result == SaveDialog::AbortClosing)
01697     return false;
01698   QucsDoc *doc = 0;
01699   while((doc = getDoc()) != 0)
01700   delete doc;
01701 
01702 
01703   switchEditMode(true);   // set schematic edit mode
01704   return true;
01705 }
01706 
01707 
01708 void QucsApp::slotFileExamples()
01709 {
01710   statusBar()->showMessage(tr("Open examples directory..."));
01711   QString path = QDir::toNativeSeparators(QucsSettings.ExamplesDir);
01712   QDesktopServices::openUrl(QUrl("file:///" + path.replace("\\","/")));
01713   statusBar()->showMessage(tr("Ready."));
01714 }
01715 
01716 void QucsApp::slotHelpTutorial()
01717 {
01718   QString path = QDir::toNativeSeparators(QucsSettings.DocDir);
01719   QUrl url = QUrl("file:///" + path.replace("\\","/") + "tutorial/" + QObject::sender()->objectName());
01720   QDesktopServices::openUrl(url);
01721 }
01722 
01723 void QucsApp::slotHelpTechnical()
01724 {
01725   QString path = QDir::toNativeSeparators(QucsSettings.DocDir);
01726   QUrl url = QUrl("file:///" + path.replace("\\","/") + "technical/" + QObject::sender()->objectName());
01727   QDesktopServices::openUrl(url);
01728 }
01729 
01730 void QucsApp::slotHelpReport()
01731 {
01732   QString path = QDir::toNativeSeparators(QucsSettings.DocDir);
01733   QUrl url = QUrl("file:///" + path.replace("\\","/") + "report/" + QObject::sender()->objectName());
01734   QDesktopServices::openUrl(url);
01735 }
01736 
01737 
01738 
01739 // --------------------------------------------------------------
01740 // Is called when another document is selected via the TabBar.
01741 void QucsApp::slotChangeView(QWidget *w)
01742 {
01743 
01744   editText->setHidden (true); // disable text edit of component property
01745   QucsDoc * Doc;
01746   if(w==NULL)return;
01747   // for text documents
01748   if (isTextDocument (w)) {
01749     TextDoc *d = (TextDoc*)w;
01750     Doc = (QucsDoc*)d;
01751     // update menu entries, etc. if neccesary
01752     magAll->setDisabled(true);
01753     if(cursorLeft->isEnabled())
01754       switchSchematicDoc (false);
01755   }
01756   // for schematic documents
01757   else {
01758     Schematic *d = (Schematic*)w;
01759     Doc = (QucsDoc*)d;
01760     magAll->setDisabled(false);
01761     // already in schematic?
01762     if(cursorLeft->isEnabled()) {
01763       // which mode: schematic or symbol editor ?
01764       if((CompChoose->count() > 1) == d->symbolMode)
01765         changeSchematicSymbolMode (d);
01766     }
01767     else {
01768       switchSchematicDoc(true);
01769       changeSchematicSymbolMode(d);
01770     }
01771   }
01772 
01773   Doc->becomeCurrent(true);
01774   view->drawn = false;
01775 
01776   HierarchyHistory.clear();
01777   popH->setEnabled(false);
01778 }
01779 
01780 // --------------------------------------------------------------
01781 void QucsApp::slotFileSettings ()
01782 {
01783   editText->setHidden (true); // disable text edit of component property
01784 
01785   QWidget * w = DocumentTab->currentWidget ();
01786   if (isTextDocument (w)) {
01787     QucsDoc * Doc = (QucsDoc *) ((TextDoc *) w);
01788     QString ext = Doc->fileSuffix ();
01789     // Octave properties
01790     if (ext == "m" || ext == "oct") {
01791     }
01792     // Verilog-A properties
01793     else if (ext == "va") {
01794       VASettingsDialog * d = new VASettingsDialog ((TextDoc *) w);
01795       d->exec ();
01796     }
01797     // VHDL and Verilog-HDL properties
01798     else {
01799       DigiSettingsDialog * d = new DigiSettingsDialog ((TextDoc *) w);
01800       d->exec ();
01801     }
01802   }
01803   // schematic properties
01804   else {
01805     SettingsDialog * d = new SettingsDialog ((Schematic *) w);
01806     d->exec ();
01807   }
01808   view->drawn = false;
01809 }
01810 
01811 // --------------------------------------------------------------
01812 void QucsApp::slotApplSettings()
01813 {
01814   slotHideEdit(); // disable text edit of component property
01815 
01816   QucsSettingsDialog *d = new QucsSettingsDialog(this);
01817   d->exec();
01818   view->drawn = false;
01819 }
01820 
01821 // --------------------------------------------------------------
01822 void QucsApp::slotRefreshSchPath()
01823 {
01824   this->updateSchNameHash();
01825   this->updateSpiceNameHash();
01826 
01827   statusBar()->showMessage(tr("The schematic search path has been refreshed."), 2000);
01828 }
01829 
01830 // --------------------------------------------------------------
01831 void QucsApp::updatePortNumber(QucsDoc *currDoc, int No)
01832 {
01833   if(No<0) return;
01834 
01835   QString pathName = currDoc->DocName;
01836   QString ext = currDoc->fileSuffix ();
01837   QFileInfo Info (pathName);
01838   QString Model, File, Name = Info.fileName();
01839 
01840   if (ext == "sch") {
01841     Model = "Sub";
01842   }
01843   else if (ext == "vhdl" || ext == "vhd") {
01844     Model = "VHDL";
01845   }
01846   else if (ext == "v") {
01847     Model = "Verilog";
01848   }
01849 
01850   // update all occurencies of subcircuit in all open documents
01851   No = 0;
01852   QWidget *w;
01853   Component *pc_tmp;
01854   while((w=DocumentTab->widget(No++)) != 0) {
01855     if(isTextDocument (w))  continue;
01856 
01857     // start from the last to omit re-appended components
01858     Schematic *Doc = (Schematic*)w;
01859     for(Component *pc=Doc->Components->last(); pc!=0; ) {
01860       if(pc->Model == Model) {
01861         File = pc->Props.getFirst()->Value;
01862         if((File == pathName) || (File == Name)) {
01863           pc_tmp = Doc->Components->prev();
01864           Doc->recreateComponent(pc);  // delete and re-append component
01865           if(!pc_tmp)  break;
01866           Doc->Components->findRef(pc_tmp);
01867           pc = Doc->Components->current();
01868           continue;
01869         }
01870       }
01871       pc = Doc->Components->prev();
01872     }
01873   }
01874 }
01875 
01876 
01877 // --------------------------------------------------------------
01878 // printCurrentDocument: call printerwriter to print document
01879 void QucsApp::printCurrentDocument(bool fitToPage)
01880 {
01881   statusBar()->showMessage(tr("Printing..."));
01882   slotHideEdit(); // disable text edit of component property
01883 
01884   PrinterWriter *writer = new PrinterWriter();
01885   writer->setFitToPage(fitToPage);
01886   writer->print(DocumentTab->currentWidget());
01887   delete writer;
01888 
01889   statusBar()->showMessage(tr("Ready."));
01890   return;
01891 }
01892 
01893 // --------------------------------------------------------------
01894 void QucsApp::slotFilePrint()
01895 {
01896   printCurrentDocument(false);
01897 }
01898 
01899 // --------------------------------------------------------------
01900 // Fit printed content to page size.
01901 void QucsApp::slotFilePrintFit()
01902 {
01903   printCurrentDocument(true);
01904 }
01905 
01906 // --------------------------------------------------------------------
01907 // Exits the application.
01908 void QucsApp::slotFileQuit()
01909 {
01910   statusBar()->showMessage(tr("Exiting application..."));
01911   slotHideEdit(); // disable text edit of component property
01912 
01913   int exit = QMessageBox::information(this,
01914       tr("Quit..."), tr("Do you really want to quit?"),
01915       tr("Yes"), tr("No"));
01916 
01917   if(exit == 0)
01918     if(closeAllFiles()) {
01919       emit signalKillEmAll();   // kill all subprocesses
01920       qApp->quit();
01921     }
01922 
01923   statusBar()->showMessage(tr("Ready."));
01924 }
01925 
01926 //-----------------------------------------------------------------
01927 // To get all close events.
01928 void QucsApp::closeEvent(QCloseEvent* Event)
01929 {
01930     qDebug()<<"x"<<pos().x()<<" ,y"<<pos().y();
01931     qDebug()<<"dx"<<size().width()<<" ,dy"<<size().height();
01932     QucsSettings.x=pos().x();
01933     QucsSettings.y=pos().y();
01934     QucsSettings.dx=size().width();
01935     QucsSettings.dy=size().height();
01936     saveApplSettings();
01937 
01938    if(closeAllFiles()) {
01939       emit signalKillEmAll();   // kill all subprocesses
01940       Event->accept();
01941       qApp->quit();
01942    }
01943    else
01944       Event->ignore();
01945 }
01946 
01947 // --------------------------------------------------------------------
01948 // Is called when the toolbar button is pressed to go into a subcircuit.
01949 void QucsApp::slotIntoHierarchy()
01950 {
01951   slotHideEdit(); // disable text edit of component property
01952 
01953   Schematic *Doc = (Schematic*)DocumentTab->currentWidget();
01954   Component *pc = Doc->searchSelSubcircuit();
01955   if(pc == 0) { return; }
01956 
01957   QString s = pc->getSubcircuitFile();
01958   if(!gotoPage(s)) { return; }
01959 
01960   HierarchyHistory.push(Doc->DocName); //remember for the way back
01961   popH->setEnabled(true);
01962 }
01963 
01964 // --------------------------------------------------------------------
01965 // Is called when the toolbar button is pressed to leave a subcircuit.
01966 void QucsApp::slotPopHierarchy()
01967 {
01968   slotHideEdit(); // disable text edit of component property
01969 
01970   if(HierarchyHistory.size() == 0) return;
01971 
01972   QString Doc = HierarchyHistory.pop();
01973 
01974   if(!gotoPage(Doc)) {
01975     HierarchyHistory.push(Doc);
01976     return;
01977   }
01978 
01979   if(HierarchyHistory.size() == 0) {
01980     popH->setEnabled(false);
01981   }
01982 }
01983 
01984 // --------------------------------------------------------------
01985 void QucsApp::slotShowAll()
01986 {
01987   slotHideEdit(); // disable text edit of component property
01988   getDoc()->showAll();
01989 }
01990 
01991 // -----------------------------------------------------------
01992 // Sets the scale factor to 1.
01993 void QucsApp::slotShowOne()
01994 {
01995   slotHideEdit(); // disable text edit of component property
01996   getDoc()->showNoZoom();
01997 }
01998 
01999 // -----------------------------------------------------------
02000 void QucsApp::slotZoomOut()
02001 {
02002   slotHideEdit(); // disable text edit of component property
02003   getDoc()->zoomBy(0.5f);
02004 }
02005 
02006 
02011 void QucsApp::slotSimulate()
02012 {
02013   slotHideEdit(); // disable text edit of component property
02014 
02015   QucsDoc *Doc;
02016   QWidget *w = DocumentTab->currentWidget();
02017   if(isTextDocument (w)) {
02018     Doc = (QucsDoc*)((TextDoc*)w);
02019     if(Doc->SimTime.isEmpty() && ((TextDoc*)Doc)->simulation) {
02020       DigiSettingsDialog *d = new DigiSettingsDialog((TextDoc*)Doc);
02021       if(d->exec() == QDialog::Rejected)
02022   return;
02023     }
02024   }
02025   else
02026     Doc = (QucsDoc*)((Schematic*)w);
02027 
02028   if(Doc->DocName.isEmpty()) // if document 'untitled' ...
02029     if(!saveAs()) return;    // ... save schematic before
02030 
02031   // Perhaps the document was modified from another program ?
02032   QFileInfo Info(Doc->DocName);
02033   if(Doc->lastSaved.isValid()) {
02034     if(Doc->lastSaved < Info.lastModified()) {
02035       int No = QMessageBox::warning(this, tr("Warning"),
02036                tr("The document was modified by another program !") + '\n' +
02037                tr("Do you want to reload or keep this version ?"),
02038                tr("Reload"), tr("Keep it"));
02039       if(No == 0)
02040         Doc->load();
02041     }
02042   }
02043 
02044   slotResetWarnings();
02045 
02046   if(Info.suffix() == "m" || Info.suffix() == "oct") {
02047     // It is an Octave script.
02048     if(Doc->DocChanged)
02049       Doc->save();
02050     slotViewOctaveDock(true);
02051     octave->runOctaveScript(Doc->DocName);
02052     return;
02053   }
02054 
02055   SimMessage *sim = new SimMessage(w, this);
02056   // disconnect is automatically performed, if one of the involved objects
02057   // is destroyed !
02058   connect(sim, SIGNAL(SimulationEnded(int, SimMessage*)), this,
02059     SLOT(slotAfterSimulation(int, SimMessage*)));
02060   connect(sim, SIGNAL(displayDataPage(QString&, QString&)),
02061     this, SLOT(slotChangePage(QString&, QString&)));
02062 
02063   sim->show();
02064   if(!sim->startProcess()) return;
02065 
02066   // to kill it before qucs ends
02067   connect(this, SIGNAL(signalKillEmAll()), sim, SLOT(slotClose()));
02068 }
02069 
02070 // ------------------------------------------------------------------------
02071 // Is called after the simulation process terminates.
02072 void QucsApp::slotAfterSimulation(int Status, SimMessage *sim)
02073 {
02074   if(Status != 0) return;  // errors ocurred ?
02075 
02076   if(sim->ErrText->document()->lineCount() > 1)   // were there warnings ?
02077     slotShowWarnings();
02078 
02079   int i=0;
02080   QWidget *w;  // search, if page is still open
02081   while((w=DocumentTab->widget(i++)) != 0)
02082     if(w == sim->DocWidget)
02083       break;
02084 
02085   if(sim->showBias == 0) {  // paint dc bias into schematic ?
02086     sim->slotClose();   // close and delete simulation window
02087     if(w) {  // schematic still open ?
02088       SweepDialog *Dia = new SweepDialog((Schematic*)sim->DocWidget);
02089 
02090       // silence warning about unused variable.
02091       Q_UNUSED(Dia)
02092     }
02093   }
02094   else {
02095     if(sim->SimRunScript) {
02096       // run script
02097       octave->startOctave();
02098       octave->runOctaveScript(sim->Script);
02099     }
02100     if(sim->SimOpenDpl) {
02101       // switch to data display
02102       if(sim->DataDisplay.right(2) == ".m" ||
02103    sim->DataDisplay.right(4) == ".oct") {  // Is it an Octave script?
02104   octave->startOctave();
02105   octave->runOctaveScript(sim->DataDisplay);
02106       }
02107       else
02108   slotChangePage(sim->DocName, sim->DataDisplay);
02109       sim->slotClose();   // close and delete simulation window
02110     }
02111     else
02112       if(w) if(!isTextDocument (sim->DocWidget))
02113   // load recent simulation data (if document is still open)
02114   ((Schematic*)sim->DocWidget)->reloadGraphs();
02115   }
02116 
02117   if(!isTextDocument (sim->DocWidget))
02118     ((Schematic*)sim->DocWidget)->viewport()->update();
02119 
02120 }
02121 
02122 // ------------------------------------------------------------------------
02123 void QucsApp::slotDCbias()
02124 {
02125   getDoc()->showBias = 0;
02126   slotSimulate();
02127 }
02128 
02129 // ------------------------------------------------------------------------
02130 // Changes to the corresponding data display page or vice versa.
02131 void QucsApp::slotChangePage(QString& DocName, QString& DataDisplay)
02132 {
02133   if(DataDisplay.isEmpty())  return;
02134 
02135   QFileInfo Info(DocName);
02136   QString Name = Info.path() + QDir::separator() + DataDisplay;
02137 
02138   QWidget  *w = DocumentTab->currentWidget();
02139 
02140   int z = 0;  // search, if page is already loaded
02141   QucsDoc * d = findDoc (Name, &z);
02142 
02143   if(d)
02144     DocumentTab->setCurrentIndex(z);
02145   else {   // no open page found ?
02146     QString ext = QucsDoc::fileSuffix (DataDisplay);
02147 
02148     int i = 0;
02149     if (ext != "vhd" && ext != "vhdl" && ext != "v" && ext != "va" &&
02150   ext != "oct" && ext != "m") {
02151       d = new Schematic(this, Name);
02152       i = DocumentTab->addTab((Schematic *)d, QPixmap(empty_xpm), DataDisplay);
02153     }
02154     else {
02155       d = new TextDoc(this, Name);
02156       i = DocumentTab->addTab((TextDoc *)d, QPixmap(empty_xpm), DataDisplay);
02157     }
02158     DocumentTab->setCurrentIndex(i);
02159 
02160     QFile file(Name);
02161     if(file.open(QIODevice::ReadOnly)) {      // try to load document
02162       file.close();
02163       if(!d->load()) {
02164         delete d;
02165         view->drawn = false;
02166         return;
02167       }
02168     }
02169     else {
02170       if(file.open(QIODevice::ReadWrite)) {  // if document doesn't exist, create
02171         d->DataDisplay = Info.fileName();
02172         slotUpdateTreeview();
02173       }
02174       else {
02175         QMessageBox::critical(this, tr("Error"), tr("Cannot create ")+Name);
02176         return;
02177       }
02178       file.close();
02179     }
02180 
02181     d->becomeCurrent(true);
02182   }
02183 
02184 
02185   if(DocumentTab->currentWidget() == w)      // if page not ...
02186     if(!isTextDocument (w))
02187       ((Schematic*)w)->reloadGraphs();  // ... changes, reload here !
02188 
02189   TabView->setCurrentIndex(2);   // switch to "Component"-Tab
02190   if (Name.right(4) == ".dpl") {
02191     int i = Category::getModulesNr (QObject::tr("diagrams"));
02192     CompChoose->setCurrentIndex(i);   // switch to diagrams
02193     slotSetCompView (i);
02194   }
02195 }
02196 
02197 // -------------------------------------------------------------------
02198 // Changes to the data display of current page.
02199 void QucsApp::slotToPage()
02200 {
02201   QucsDoc *d = getDoc();
02202   if(d->DataDisplay.isEmpty()) {
02203     QMessageBox::critical(this, tr("Error"), tr("No page set !"));
02204     return;
02205   }
02206 
02207   if(d->DocName.right(2) == ".m" ||
02208      d->DocName.right(4) == ".oct")
02209     slotViewOctaveDock(true);
02210   else
02211     slotChangePage(d->DocName, d->DataDisplay);
02212 }
02213 
02214 // -------------------------------------------------------------------
02215 // Called when file name in Project View is double-clicked
02216 //   or open is selected in the context menu
02217 void QucsApp::slotOpenContent(const QModelIndex &idx)
02218 {
02219   editText->setHidden(true); // disable text edit of component property
02220 
02221   //test the item is valid
02222   if (!idx.isValid()) { return; }
02223   if (!idx.parent().isValid()) { return; }
02224 
02225   QString filename = idx.sibling(idx.row(), 0).data().toString();
02226   QString note = idx.sibling(idx.row(), 1).data().toString();
02227   QFileInfo Info(QucsSettings.QucsWorkDir.filePath(filename));
02228   QString extName = Info.suffix();
02229 
02230   if (extName == "sch" || extName == "dpl" || extName == "vhdl" ||
02231       extName == "vhd" || extName == "v" || extName == "va" ||
02232       extName == "m" || extName == "oct") {
02233     gotoPage(Info.absoluteFilePath());
02234     updateRecentFilesList(Info.absoluteFilePath());
02235     slotUpdateRecentFiles();
02236 
02237     if(note.isEmpty())     // is subcircuit ?
02238       if(extName == "sch") return;
02239 
02240     select->blockSignals(true);  // switch on the 'select' action ...
02241     select->setChecked(true);
02242     select->blockSignals(false);
02243 
02244     activeAction = select;
02245     MouseMoveAction = 0;
02246     MousePressAction = &MouseActions::MPressSelect;
02247     MouseReleaseAction = &MouseActions::MReleaseSelect;
02248     MouseDoubleClickAction = &MouseActions::MDoubleClickSelect;
02249     return;
02250   }
02251 
02252   if(extName == "dat") {
02253     editFile(Info.absoluteFilePath());  // open datasets with text editor
02254     return;
02255   }
02256 
02257   // File is no Qucs file, so go through list and search a user
02258   // defined program to open it.
02259   QStringList com;
02260   QStringList::const_iterator it = QucsSettings.FileTypes.constBegin();
02261   while(it != QucsSettings.FileTypes.constEnd()) {
02262     if(extName == (*it).section('/',0,0)) {
02263       QString progName = (*it).section('/',1,1);
02264       com = progName.split(" ");
02265       com << Info.absoluteFilePath();
02266 
02267       QProcess *Program = new QProcess();
02268       //Program->setCommunication(0);
02269       QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
02270       env.insert("PATH", env.value("PATH") );
02271       Program->setProcessEnvironment(env);
02272       Program->start(com.join(" "));
02273       if(Program->state()!=QProcess::Running&&
02274               Program->state()!=QProcess::Starting) {
02275         QMessageBox::critical(this, tr("Error"),
02276                tr("Cannot start \"%1\"!").arg(Info.absoluteFilePath()));
02277         delete Program;
02278       }
02279       return;
02280     }
02281     it++;
02282   }
02283 
02284   // If no appropriate program was found, open as text file.
02285   editFile(Info.absoluteFilePath());  // open datasets with text editor
02286 }
02287 
02288 // ---------------------------------------------------------
02289 // Is called when the mouse is clicked within the Content QListView.
02290 void QucsApp::slotSelectSubcircuit(const QModelIndex &idx)
02291 {
02292   editText->setHidden(true); // disable text edit of component property
02293 
02294   if(!idx.isValid()) {   // mouse button pressed not over an item ?
02295     Content->clearSelection();  // deselect component in ListView
02296     return;
02297   }
02298 
02299   bool isVHDL = false;
02300   bool isVerilog = false;
02301   QModelIndex parentIdx = idx.parent();
02302   if(!parentIdx.isValid()) { return; }
02303 
02304   QString category = parentIdx.data().toString();
02305 
02306   if(category == tr("Schematics")) {
02307     if(idx.sibling(idx.row(), 1).data().toString().isEmpty())
02308       return;   // return, if not a subcircuit
02309   }
02310   else if(category == tr("VHDL"))
02311     isVHDL = true;
02312   else if(category == tr("Verilog"))
02313     isVerilog = true;
02314   else
02315     return;
02316 
02317   QString filename = idx.sibling(idx.row(), 0).data().toString();
02318   QString note = idx.sibling(idx.row(), 1).data().toString();
02319   int idx_pag = DocumentTab->currentIndex();
02320   QString tab_titl = "";
02321   if (idx_pag>=0) tab_titl = DocumentTab->tabText(idx_pag);
02322   if (filename == tab_titl ) return; // Forbid to paste subcircuit into itself.
02323 
02324   // delete previously selected elements
02325   if(view->selElem != 0)  delete view->selElem;
02326   view->selElem = 0;
02327 
02328   // toggle last toolbar button off
02329   if(activeAction) {
02330     activeAction->blockSignals(true); // do not call toggle slot
02331     activeAction->setChecked(false);       // set last toolbar button off
02332     activeAction->blockSignals(false);
02333   }
02334   activeAction = 0;
02335 
02336   Component *Comp;
02337   if(isVHDL)
02338     Comp = new VHDL_File();
02339   else if(isVerilog)
02340     Comp = new Verilog_File();
02341   else
02342     Comp = new Subcircuit();
02343   Comp->Props.first()->Value = idx.sibling(idx.row(), 0).data().toString();
02344   Comp->recreate(0);
02345   view->selElem = Comp;
02346 
02347   if(view->drawn)
02348     ((Q3ScrollView*)DocumentTab->currentWidget())->viewport()->update();
02349   view->drawn = false;
02350   MouseMoveAction = &MouseActions::MMoveElement;
02351   MousePressAction = &MouseActions::MPressElement;
02352   MouseReleaseAction = 0;
02353   MouseDoubleClickAction = 0;
02354 }
02355 
02356 // ---------------------------------------------------------
02357 // Is called when the mouse is clicked within the Content QListView.
02358 void QucsApp::slotSelectLibComponent(QTreeWidgetItem *item)
02359 {
02360     // get the current document
02361     Schematic *Doc = (Schematic*)DocumentTab->currentWidget();
02362 
02363     // if the current document is a schematic activate the paste
02364     if(!isTextDocument(Doc))
02365     {
02366         // if theres not a higher level item, this is a top level item,
02367         // not a component item so return
02368         if(item->parent() == 0) return;
02369         if(item->text(1).isEmpty()) return;   // return, if not a subcircuit
02370 
02371         // copy the subcircuit schematic to the clipboard
02372         QClipboard *cb = QApplication::clipboard();
02373         cb->setText(item->text(1));
02374 
02375         // activate the paste command
02376         slotEditPaste (true);
02377     }
02378 
02379 }
02380 
02381 
02382 // ---------------------------------------------------------
02383 // This function is called if the document type changes, i.e.
02384 // from schematic to text document or vice versa.
02385 void QucsApp::switchSchematicDoc (bool SchematicMode)
02386 {
02387   // switch our scroll key actions on/off according to SchematicMode
02388   cursorLeft->setEnabled(SchematicMode);
02389   cursorRight->setEnabled(SchematicMode);
02390   cursorUp->setEnabled(SchematicMode);
02391   cursorDown->setEnabled(SchematicMode);
02392 
02393   // text document
02394   if (!SchematicMode) {
02395     if (activeAction) {
02396       activeAction->blockSignals (true); // do not call toggle slot
02397       activeAction->setChecked(false);       // set last toolbar button off
02398       activeAction->blockSignals (false);
02399     }
02400     activeAction = select;
02401     select->blockSignals (true);
02402     select->setChecked(true);
02403     select->blockSignals (false);
02404   }
02405   // schematic document
02406   else {
02407     MouseMoveAction = 0;
02408     MousePressAction = &MouseActions::MPressSelect;
02409     MouseReleaseAction = &MouseActions::MReleaseSelect;
02410     MouseDoubleClickAction = &MouseActions::MDoubleClickSelect;
02411   }
02412 
02413   selectMarker->setEnabled (SchematicMode);
02414   alignTop->setEnabled (SchematicMode);
02415   alignBottom->setEnabled (SchematicMode);
02416   alignLeft->setEnabled (SchematicMode);
02417   alignRight->setEnabled (SchematicMode);
02418   centerHor->setEnabled (SchematicMode);
02419   centerVert->setEnabled (SchematicMode);
02420   distrHor->setEnabled (SchematicMode);
02421   distrVert->setEnabled (SchematicMode);
02422   onGrid->setEnabled (SchematicMode);
02423   moveText->setEnabled (SchematicMode);
02424   filePrintFit->setEnabled (SchematicMode);
02425   editRotate->setEnabled (SchematicMode);
02426   editMirror->setEnabled (SchematicMode);
02427   editMirrorY->setEnabled (SchematicMode);
02428   intoH->setEnabled (SchematicMode);
02429   popH->setEnabled (SchematicMode);
02430   dcbias->setEnabled (SchematicMode);
02431   insWire->setEnabled (SchematicMode);
02432   insLabel->setEnabled (SchematicMode);
02433   insPort->setEnabled (SchematicMode);
02434   insGround->setEnabled (SchematicMode);
02435   insEquation->setEnabled (SchematicMode);
02436   setMarker->setEnabled (SchematicMode);
02437 
02438   exportAsImage->setEnabled (SchematicMode); // only export schematic, no text
02439 
02440   editFind->setEnabled (!SchematicMode);
02441   insEntity->setEnabled (!SchematicMode);
02442 
02443   buildModule->setEnabled(!SchematicMode); // only build if VA document
02444 }
02445 
02446 // ---------------------------------------------------------
02447 void QucsApp::switchEditMode(bool SchematicMode)
02448 {
02449   fillComboBox(SchematicMode);
02450   slotSetCompView(0);
02451 
02452   intoH->setEnabled(SchematicMode);
02453   popH->setEnabled(SchematicMode);
02454   editActivate->setEnabled(SchematicMode);
02455   changeProps->setEnabled(SchematicMode);
02456   insEquation->setEnabled(SchematicMode);
02457   insGround->setEnabled(SchematicMode);
02458   insPort->setEnabled(SchematicMode);
02459   insWire->setEnabled(SchematicMode);
02460   insLabel->setEnabled(SchematicMode);
02461   setMarker->setEnabled(SchematicMode);
02462   selectMarker->setEnabled(SchematicMode);
02463   simulate->setEnabled(SchematicMode);
02464 }
02465 
02466 // ---------------------------------------------------------
02467 void QucsApp::changeSchematicSymbolMode(Schematic *Doc)
02468 {
02469   if(Doc->symbolMode) {
02470     // go into select modus to avoid placing a forbidden element
02471     select->setChecked(true);
02472 
02473     switchEditMode(false);
02474   }
02475   else
02476     switchEditMode(true);
02477 }
02478 
02479 // ---------------------------------------------------------
02480 bool QucsApp::isTextDocument(QWidget *w) {
02481   return w->inherits("QPlainTextEdit");
02482 }
02483 
02484 // ---------------------------------------------------------
02485 // Is called if the "symEdit" action is activated, i.e. if the user
02486 // switches between the two painting mode: Schematic and (subcircuit)
02487 // symbol.
02488 void QucsApp::slotSymbolEdit()
02489 {
02490   QWidget *w = DocumentTab->currentWidget();
02491 
02492   // in a text document (e.g. VHDL)
02493   if (isTextDocument (w)) {
02494     TextDoc *TDoc = (TextDoc*)w;
02495     // set 'DataDisplay' document of text file to symbol file
02496     QFileInfo Info(TDoc->DocName);
02497     QString sym = Info.completeBaseName()+".sym";
02498     TDoc->DataDisplay = sym;
02499 
02500     // symbol file already loaded?
02501     int paint_mode = 0;
02502     if (!findDoc (QucsSettings.QucsWorkDir.filePath(sym)))
02503       paint_mode = 1;
02504 
02505     // change current page to appropriate symbol file
02506     slotChangePage(TDoc->DocName,TDoc->DataDisplay);
02507 
02508     // set 'DataDisplay' document of symbol file to original text file
02509     Schematic *SDoc = (Schematic*)DocumentTab->currentWidget();
02510     SDoc->DataDisplay = Info.fileName();
02511 
02512     // change into symbol mode
02513     if (paint_mode) // but only switch coordinates if newly loaded
02514       SDoc->switchPaintMode();
02515     SDoc->symbolMode = true;
02516     changeSchematicSymbolMode(SDoc);
02517     SDoc->becomeCurrent(true);
02518     SDoc->viewport()->update();
02519     view->drawn = false;
02520   }
02521   // in a normal schematic, data display or symbol file
02522   else {
02523     Schematic *SDoc = (Schematic*)w;
02524     // in a symbol file
02525     if(SDoc->DocName.right(4) == ".sym") {
02526       slotChangePage(SDoc->DocName, SDoc->DataDisplay);
02527     }
02528     // in a normal schematic
02529     else {
02530       slotHideEdit(); // disable text edit of component property
02531       SDoc->switchPaintMode();   // twist the view coordinates
02532       changeSchematicSymbolMode(SDoc);
02533       SDoc->becomeCurrent(true);
02534       SDoc->viewport()->update();
02535       view->drawn = false;
02536     }
02537   }
02538 }
02539 
02540 // -----------------------------------------------------------
02541 void QucsApp::slotPowerMatching()
02542 {
02543   if(!view->focusElement) return;
02544   if(view->focusElement->Type != isMarker) return;
02545   Marker *pm = (Marker*)view->focusElement;
02546 
02547 //  double Z0 = 50.0;
02548   QString Var = pm->pGraph->Var;
02549   double Imag = pm->powImag();
02550   if(Var == "Sopt")  // noise matching ?
02551     Imag *= -1.0;
02552 
02553   MatchDialog *Dia = new MatchDialog(this);
02554   Dia->TwoCheck->setChecked(false);
02555   Dia->TwoCheck->setEnabled(false);
02556 //  Dia->Ref1Edit->setText(QString::number(Z0));
02557   Dia->S11magEdit->setText(QString::number(pm->powReal()));
02558   Dia->S11degEdit->setText(QString::number(Imag));
02559   Dia->setFrequency(pm->powFreq());
02560 
02561   slotToPage();
02562   if(Dia->exec() != QDialog::Accepted)
02563     return;
02564 }
02565 
02566 // -----------------------------------------------------------
02567 void QucsApp::slot2PortMatching()
02568 {
02569   if(!view->focusElement) return;
02570   if(view->focusElement->Type != isMarker) return;
02571   Marker *pm = (Marker*)view->focusElement;
02572 
02573   QString DataSet;
02574   Schematic *Doc = (Schematic*)DocumentTab->currentWidget();
02575   int z = pm->pGraph->Var.indexOf(':');
02576   if(z <= 0)  DataSet = Doc->DataSet;
02577   else  DataSet = pm->pGraph->Var.mid(z+1);
02578   double Freq = pm->powFreq();
02579 
02580   QFileInfo Info(Doc->DocName);
02581   DataSet = Info.path()+QDir::separator()+DataSet;
02582 
02583   Diagram *Diag = new Diagram();
02584 
02585   // FIXME: use normal Diagrams.
02586   Graph *pg = new Graph(Diag, "S[1,1]");
02587   Diag->Graphs.append(pg);
02588   if(!pg->loadDatFile(DataSet)) {
02589     QMessageBox::critical(0, tr("Error"), tr("Could not load S[1,1]."));
02590     return;
02591   }
02592 
02593   pg = new Graph(Diag, "S[1,2]");
02594   Diag->Graphs.append(pg);
02595   if(!pg->loadDatFile(DataSet)) {
02596     QMessageBox::critical(0, tr("Error"), tr("Could not load S[1,2]."));
02597     return;
02598   }
02599 
02600   pg = new Graph(Diag, "S[2,1]");
02601   Diag->Graphs.append(pg);
02602   if(!pg->loadDatFile(DataSet)) {
02603     QMessageBox::critical(0, tr("Error"), tr("Could not load S[2,1]."));
02604     return;
02605   }
02606 
02607   pg = new Graph(Diag, "S[2,2]");
02608   Diag->Graphs.append(pg);
02609   if(!pg->loadDatFile(DataSet)) {
02610     QMessageBox::critical(0, tr("Error"), tr("Could not load S[2,2]."));
02611     return;
02612   }
02613 
02614   DataX const *Data = Diag->Graphs.first()->axis(0);
02615   if(Data->Var != "frequency") {
02616     QMessageBox::critical(0, tr("Error"), tr("Wrong dependency!"));
02617     return;
02618   }
02619 
02620   double *Value = Data->Points;
02621   // search for values for chosen frequency
02622   for(z=0; z<Data->count; z++)
02623     if(*(Value++) == Freq) break;
02624 
02625   // get S-parameters
02626   double S11real = *(Diag->Graphs.at(0)->cPointsY + 2*z);
02627   double S11imag = *(Diag->Graphs.at(0)->cPointsY + 2*z + 1);
02628   double S12real = *(Diag->Graphs.at(1)->cPointsY + 2*z);
02629   double S12imag = *(Diag->Graphs.at(1)->cPointsY + 2*z + 1);
02630   double S21real = *(Diag->Graphs.at(2)->cPointsY + 2*z);
02631   double S21imag = *(Diag->Graphs.at(2)->cPointsY + 2*z + 1);
02632   double S22real = *(Diag->Graphs.at(3)->cPointsY + 2*z);
02633   double S22imag = *(Diag->Graphs.at(3)->cPointsY + 2*z + 1);
02634   delete Diag;
02635 
02636   MatchDialog *Dia = new MatchDialog(this);
02637   Dia->TwoCheck->setEnabled(false);
02638   Dia->setFrequency(Freq);
02639   Dia->S11magEdit->setText(QString::number(S11real));
02640   Dia->S11degEdit->setText(QString::number(S11imag));
02641   Dia->S12magEdit->setText(QString::number(S12real));
02642   Dia->S12degEdit->setText(QString::number(S12imag));
02643   Dia->S21magEdit->setText(QString::number(S21real));
02644   Dia->S21degEdit->setText(QString::number(S21imag));
02645   Dia->S22magEdit->setText(QString::number(S22real));
02646   Dia->S22degEdit->setText(QString::number(S22imag));
02647 
02648   slotToPage();
02649   if(Dia->exec() != QDialog::Accepted)
02650     return;
02651 }
02652 
02653 // -----------------------------------------------------------
02654 // Is called if the "edit" action is clicked on right mouse button menu.
02655 void QucsApp::slotEditElement()
02656 {
02657   if(view->focusMEvent)
02658     view->editElement((Schematic*)DocumentTab->currentWidget(), view->focusMEvent);
02659 }
02660 
02661 // -----------------------------------------------------------
02662 // Hides the edit for component property. Called e.g. if QLineEdit
02663 // looses the focus.
02664 void QucsApp::slotHideEdit()
02665 {
02666   editText->setParent(this, 0);
02667   editText->setHidden(true);
02668 }
02669 
02670 // -----------------------------------------------------------
02671 // set document tab icon to smallsave_xpm or empty_xpm
02672 void QucsApp::slotFileChanged(bool changed)
02673 {
02674   DocumentTab->setTabIcon(DocumentTab->currentIndex(),
02675       QPixmap((changed)? smallsave_xpm : empty_xpm));
02676 }
02677 
02678 // -----------------------------------------------------------
02679 // Update project view by call refresh function
02680 // looses the focus.
02681 void QucsApp::slotUpdateTreeview()
02682 {
02683   Content->refresh();
02684 }
02685 
02686 // -----------------------------------------------------------
02687 // Searches the qucs path list for all schematic files and creates
02688 // a hash for lookup later
02689 void QucsApp::updateSchNameHash(void)
02690 {
02691     // update the list of paths to search in qucsPathList, this
02692     // removes nonexisting entries
02693     updatePathList();
02694 
02695     // now go through the paths creating a map to all the schematic files
02696     // found in the directories. Note that we go through the list of paths from
02697     // first index to last index. Since keys are unique it means schematic files
02698     // in directories at the end of the list take precendence over those at the
02699     // start of the list, we should warn about shadowing of schematic files in
02700     // this way in the future
02701     QStringList nameFilter;
02702     nameFilter << "*.sch";
02703 
02704     // clear out any existing hash table entriess
02705     schNameHash.clear();
02706 
02707     foreach (QString qucspath, qucsPathList) {
02708         QDir thispath(qucspath);
02709         // get all the schematic files in the directory
02710         QFileInfoList schfilesList = thispath.entryInfoList( nameFilter, QDir::Files );
02711         // put each one in the hash table with the unique key the base name of
02712         // the file, note this will overwrite the value if the key already exists
02713         foreach (QFileInfo schfile, schfilesList) {
02714             QString bn = schfile.completeBaseName();
02715             schNameHash[schfile.completeBaseName()] = schfile.absoluteFilePath();
02716         }
02717     }
02718 
02719     // finally check the home/working directory
02720     QDir thispath(QucsSettings.QucsWorkDir);
02721     QFileInfoList schfilesList = thispath.entryInfoList( nameFilter, QDir::Files );
02722     // put each one in the hash table with the unique key the base name of
02723     // the file, note this will overwrite the value if the key already exists
02724     foreach (QFileInfo schfile, schfilesList) {
02725         schNameHash[schfile.completeBaseName()] = schfile.absoluteFilePath();
02726     }
02727 }
02728 
02729 // -----------------------------------------------------------
02730 // Searches the qucs path list for all spice files and creates
02731 // a hash for lookup later
02732 void QucsApp::updateSpiceNameHash(void)
02733 {
02734     // update the list of paths to search in qucsPathList, this
02735     // removes nonexisting entries
02736     updatePathList();
02737 
02738     // now go through the paths creating a map to all the spice files
02739     // found in the directories. Note that we go through the list of paths from
02740     // first index to last index. Since keys are unique it means spice files
02741     // in directories at the end of the list take precendence over those at the
02742     // start of the list, we should warn about shadowing of spice files in
02743     // this way in the future
02744 
02745     // clear out any existing hash table entriess
02746     spiceNameHash.clear();
02747 
02748     foreach (QString qucspath, qucsPathList) {
02749         QDir thispath(qucspath);
02750         // get all the schematic files in the directory
02751         QFileInfoList spicefilesList = thispath.entryInfoList( QucsSettings.spiceExtensions, QDir::Files );
02752         // put each one in the hash table with the unique key the base name of
02753         // the file, note this will overwrite the value if the key already exists
02754         foreach (QFileInfo spicefile, spicefilesList) {
02755             QString bn = spicefile.completeBaseName();
02756             schNameHash[spicefile.completeBaseName()] = spicefile.absoluteFilePath();
02757         }
02758     }
02759 
02760     // finally check the home/working directory
02761     QDir thispath(QucsSettings.QucsWorkDir);
02762     QFileInfoList spicefilesList = thispath.entryInfoList( QucsSettings.spiceExtensions, QDir::Files );
02763     // put each one in the hash table with the unique key the base name of
02764     // the file, note this will overwrite the value if the key already exists
02765     foreach (QFileInfo spicefile, spicefilesList) {
02766         spiceNameHash[spicefile.completeBaseName()] = spicefile.absoluteFilePath();
02767     }
02768 }
02769 
02770 // -----------------------------------------------------------
02771 // update the list of paths, pruning non-existing paths
02772 void QucsApp::updatePathList(void)
02773 {
02774     // check each path actually exists, if not remove it
02775     QMutableListIterator<QString> i(qucsPathList);
02776     while (i.hasNext()) {
02777         i.next();
02778         QDir thispath(i.value());
02779         if (!thispath.exists())
02780         {
02781             // the path does not exist, remove it from the list
02782             i.remove();
02783         }
02784     }
02785 }
02786 
02787 // replace the old path list with a new one
02788 void QucsApp::updatePathList(QStringList newPathList)
02789 {
02790     // clear out the old path list
02791     qucsPathList.clear();
02792 
02793     // copy the new path into the path list
02794     foreach(QString path, newPathList)
02795     {
02796         qucsPathList.append(path);
02797     }
02798     // do the normal path update operations
02799     updatePathList();
02800 }
02801 
02802 
02803 void QucsApp::updateRecentFilesList(QString s)
02804 {
02805   QSettings* settings = new QSettings("qucs","qucs");
02806   QucsSettings.RecentDocs.removeAll(s);
02807   QucsSettings.RecentDocs.prepend(s);
02808   if (QucsSettings.RecentDocs.size() > MaxRecentFiles) {
02809     QucsSettings.RecentDocs.removeLast();
02810   }
02811   settings->setValue("RecentDocs",QucsSettings.RecentDocs.join("*"));
02812   delete settings;
02813   slotUpdateRecentFiles();
02814 }
02815 
02816 void QucsApp::slotSaveDiagramToGraphicsFile()
02817 {
02818   slotSaveSchematicToGraphicsFile(true);
02819 }
02820 
02821 void QucsApp::slotSaveSchematicToGraphicsFile(bool diagram)
02822 {
02823   ImageWriter *writer = new ImageWriter(lastExportFilename);
02824   writer->setDiagram(diagram);
02825   if (!writer->print(DocumentTab->currentWidget())) {
02826     lastExportFilename = writer->getLastSavedFile();
02827     statusBar()->showMessage(QObject::tr("Successfully exported"), 2000);
02828   }
02829   delete writer;
02830 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines