Qucs-GUI
0.0.19
|
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 }