Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/dialogs/librarydialog.cpp
Go to the documentation of this file.
00001 /*
00002  * librarydialog.cpp - implementation of dialog to create library
00003  *
00004  * Copyright (C) 2006, Michael Margraf, michael.margraf@alumni.tu-berlin.de
00005  * Copyright (C) 2014, Yodalee, lc85301@gmail.com
00006  *
00007  * This file is part of Qucs
00008  *
00009  * Qucs is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2, or (at your option)
00012  * any later version.
00013  *
00014  * This software is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with Qucs.  If not, see <http://www.gnu.org/licenses/>.
00021  *
00022  */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 # include <config.h>
00026 #endif
00027 #include <QLabel>
00028 #include <QLineEdit>
00029 #include <QPlainTextEdit>
00030 #include <QTextStream>
00031 
00032 #include <QDataStream>
00033 #include <QCheckBox>
00034 #include <QTreeWidgetItem>
00035 #include <QValidator>
00036 #include <QMessageBox>
00037 #include <QPushButton>
00038 #include <QScrollArea>
00039 #include <QButtonGroup>
00040 #include <QVBoxLayout>
00041 #include <QHBoxLayout>
00042 #include <QStackedWidget>
00043 #include <QGroupBox>
00044 #include <QDebug>
00045 #include <QStringList>
00046 
00047 #include "librarydialog.h"
00048 #include "main.h"
00049 #include "schematic.h"
00050 
00051 extern SubMap FileList;
00052 
00053 LibraryDialog::LibraryDialog(QWidget *parent)
00054       : QDialog(parent)
00055 {
00056   setWindowTitle(tr("Create Library"));
00057 
00058   Expr.setPattern("[\\w_]+");
00059   Validator = new QRegExpValidator(Expr, this);
00060 
00061   curDescr = 0; // description counter, prev, next
00062 
00063  // ...........................................................
00064   all = new QVBoxLayout(this);
00065   all->setMargin(5);
00066   all->setSpacing(6);
00067 
00068   stackedWidgets = new QStackedWidget(this);
00069   all->addWidget(stackedWidgets);
00070 
00071 
00072   // stacked 0 - select subcirbuit, name, and descriptions
00073   // ...........................................................
00074   QWidget *selectSubckt = new QWidget();
00075   stackedWidgets->addWidget(selectSubckt);
00076 
00077   QVBoxLayout *selectSubcktLayout = new QVBoxLayout();
00078   selectSubckt->setLayout(selectSubcktLayout);
00079 
00080 
00081   QHBoxLayout *h1 = new QHBoxLayout();
00082   selectSubcktLayout->addLayout(h1);
00083   theLabel = new QLabel(tr("Library Name:"));
00084   h1->addWidget(theLabel);
00085   NameEdit = new QLineEdit();
00086   h1->addWidget(NameEdit);
00087   NameEdit->setValidator(Validator);
00088 
00089   // ...........................................................
00090   Group = new QGroupBox(tr("Choose subcircuits:"));
00091   selectSubcktLayout->addWidget(Group);
00092 
00093   QScrollArea *scrollArea = new QScrollArea(Group);
00094   scrollArea->setWidgetResizable(true);
00095 
00096   QWidget *scrollWidget = new QWidget();
00097 
00098   checkBoxLayout = new QVBoxLayout();
00099   scrollWidget->setLayout(checkBoxLayout);
00100   scrollArea->setWidget(scrollWidget);
00101 
00102   QVBoxLayout *areaLayout = new QVBoxLayout();
00103   areaLayout->addWidget(scrollArea);
00104   Group->setLayout(areaLayout);
00105 
00106   // ...........................................................
00107   QHBoxLayout *hCheck = new QHBoxLayout();
00108   selectSubcktLayout->addLayout(hCheck);
00109   checkDescr = new QCheckBox(tr("Add subcircuit description"));
00110   checkDescr->setChecked(true);
00111   hCheck->addWidget(checkDescr);
00112   hCheck->addStretch();
00113   connect(checkDescr, SIGNAL(stateChanged(int)), this, SLOT(slotCheckDescrChanged(int)));
00114 
00115   // ...........................................................
00116   QGridLayout *gridButts = new QGridLayout();
00117   selectSubcktLayout->addLayout(gridButts);
00118   ButtSelectAll = new QPushButton(tr("Select All"));
00119   gridButts->addWidget(ButtSelectAll, 0, 0);
00120   connect(ButtSelectAll, SIGNAL(clicked()), SLOT(slotSelectAll()));
00121   ButtSelectNone = new QPushButton(tr("Deselect All"));
00122   gridButts->addWidget(ButtSelectNone, 0, 1);
00123   connect(ButtSelectNone, SIGNAL(clicked()), SLOT(slotSelectNone()));
00124   // ...........................................................
00125   ButtCancel = new QPushButton(tr("Cancel"));
00126   gridButts->addWidget(ButtCancel, 1, 0);
00127   connect(ButtCancel, SIGNAL(clicked()), SLOT(reject()));
00128   ButtCreateNext = new QPushButton(tr("Next >>"));
00129   gridButts->addWidget(ButtCreateNext, 1, 1);
00130   connect(ButtCreateNext, SIGNAL(clicked()), SLOT(slotCreateNext()));
00131   ButtCreateNext->setDefault(true);
00132 
00133 
00134   // stacked 1 - enter description, loop over checked subckts
00135   // ...........................................................
00136   QWidget *subcktDescr = new QWidget();
00137   stackedWidgets->addWidget(subcktDescr);
00138 
00139   QVBoxLayout *subcktDescrLayout = new QVBoxLayout();
00140   subcktDescr->setLayout(subcktDescrLayout);
00141 
00142   QHBoxLayout *hbox = new QHBoxLayout();
00143   subcktDescrLayout->addLayout(hbox);
00144   QLabel *libName = new QLabel(tr("Enter description for:"));
00145   hbox->addWidget(libName);
00146   checkedCktName = new QLabel();
00147   checkedCktName->setText("dummy");
00148   hbox->addWidget(checkedCktName);
00149 
00150   QGroupBox *descrBox = new QGroupBox(tr("Description:"));
00151   subcktDescrLayout->addWidget(descrBox);
00152   textDescr = new QTextEdit();
00153   textDescr->setTextFormat(Qt::PlainText);
00154   textDescr->setWordWrapMode(QTextOption::NoWrap);
00155   connect(textDescr, SIGNAL(textChanged()), SLOT(slotUpdateDescription()));
00156   QVBoxLayout *vGroup = new QVBoxLayout;
00157   vGroup->addWidget(textDescr);
00158   descrBox->setLayout(vGroup);
00159 
00160   // ...........................................................
00161   gridButts = new QGridLayout();
00162   subcktDescrLayout->addLayout(gridButts);
00163   prevButt = new QPushButton(tr("Previous"));
00164   gridButts->addWidget(prevButt, 0, 0);
00165   prevButt->setDisabled(true);
00166   connect(prevButt, SIGNAL(clicked()), SLOT(slotPrevDescr()));
00167   nextButt = new QPushButton(tr("Next >>"));
00168   nextButt->setDefault(true);
00169   gridButts->addWidget(nextButt, 0, 1);
00170   connect(nextButt, SIGNAL(clicked()), SLOT(slotNextDescr()));
00171   // ...........................................................
00172   ButtCancel = new QPushButton(tr("Cancel"));
00173   gridButts->addWidget(ButtCancel, 1, 0);
00174   connect(ButtCancel, SIGNAL(clicked()), SLOT(reject()));
00175   createButt = new QPushButton(tr("Create"));
00176   connect(createButt, SIGNAL(clicked()), SLOT(slotSave()));
00177   gridButts->addWidget(createButt, 1, 1);
00178   createButt->setDisabled(true);
00179 
00180 
00181   // stacked 2 - show error / sucess message
00182   // ...........................................................
00183   QWidget *msg = new QWidget();
00184   stackedWidgets->addWidget(msg);
00185 
00186   QVBoxLayout *msgLayout = new QVBoxLayout();
00187   msg->setLayout(msgLayout);
00188 
00189   QHBoxLayout *hbox1 = new QHBoxLayout();
00190   msgLayout->addLayout(hbox1);
00191   QLabel *finalLabel = new QLabel(tr("Library Name:"));
00192   hbox1->addWidget(finalLabel);
00193   libSaveName = new QLabel();
00194   hbox1->addWidget(libSaveName);
00195 
00196   QGroupBox *msgBox = new QGroupBox(tr("Message:"));
00197   msgLayout->addWidget(msgBox);
00198   ErrText = new QPlainTextEdit();
00199   ErrText->setWordWrapMode(QTextOption::NoWrap);
00200   ErrText->setReadOnly(true);
00201   QVBoxLayout *vbox1 = new QVBoxLayout();
00202   vbox1->addWidget(ErrText);
00203   msgBox->setLayout(vbox1);
00204 
00205   QHBoxLayout *hbox2 = new QHBoxLayout();
00206   hbox2->addStretch();
00207   QPushButton  *close = new QPushButton(tr("Close"));
00208   hbox2->addWidget(close);
00209   connect(close, SIGNAL(clicked()), SLOT(reject()));
00210   msgLayout->addLayout(hbox2);
00211 }
00212 
00213 
00214 LibraryDialog::~LibraryDialog()
00215 {
00216   delete all;
00217   delete Validator;
00218 }
00219 
00220 void
00221 LibraryDialog::fillSchematicList(QStringList SchematicList)
00222 {
00223   // ...........................................................
00224   // insert all subcircuits of into checklist
00225   if (SchematicList.size() == 0) {
00226     ButtCreateNext->setEnabled(false);
00227     QLabel *noProj = new QLabel(tr("No projects!"));
00228     checkBoxLayout->addWidget(noProj);
00229   } else {
00230     foreach(const QString &filename, SchematicList) {
00231       QCheckBox *subCheck = new QCheckBox(filename);
00232       checkBoxLayout->addWidget(subCheck);
00233       BoxList.append(subCheck);
00234     }
00235   }
00236 }
00237 
00238 // ---------------------------------------------------------------
00239 void LibraryDialog::slotCreateNext()
00240 {
00241   if(NameEdit->text().isEmpty()) {
00242     QMessageBox::critical(this, tr("Error"), tr("Please insert a library name!"));
00243     return;
00244   }
00245 
00246   int count=0;
00247   QCheckBox *p;
00248   QListIterator<QCheckBox *> i(BoxList);
00249   while(i.hasNext()){
00250     p = i.next();
00251     if(p->isChecked()) {
00252       SelectedNames.append(p->text());
00253       Descriptions.append("");
00254       count++;
00255     }
00256   }
00257 
00258   if(count < 1) {
00259     QMessageBox::critical(this, tr("Error"), tr("Please choose at least one subcircuit!"));
00260     return;
00261   }
00262 
00263   LibDir = QDir(QucsSettings.QucsHomeDir);
00264   if(!LibDir.cd("user_lib")) { // user library directory exists ?
00265     if(!LibDir.mkdir("user_lib")) { // no, then create it
00266       QMessageBox::warning(this, tr("Warning"),
00267                    tr("Cannot create user library directory !"));
00268       return;
00269     }
00270     LibDir.cd("user_lib");
00271   }
00272 
00273   LibFile.setFileName(QucsSettings.LibDir + NameEdit->text() + ".lib");
00274   if(LibFile.exists()) {
00275     QMessageBox::critical(this, tr("Error"), tr("A system library with this name already exists!"));
00276     return;
00277   }
00278 
00279   LibFile.setFileName(LibDir.absFilePath(NameEdit->text()) + ".lib");
00280   if(LibFile.exists()) {
00281     QMessageBox::critical(this, tr("Error"), tr("A library with this name already exists!"));
00282     return;
00283   }
00284 
00285   if (checkDescr->checkState() == Qt::Checked){
00286     // user enter descriptions
00287     stackedWidgets->setCurrentIndex(1);  // subcircuit description view
00288 
00289     checkedCktName->setText(SelectedNames[0]);
00290     textDescr->setText(Descriptions[0]);
00291 
00292     if (SelectedNames.count() == 1){
00293         prevButt->setDisabled(true);
00294         nextButt->setDisabled(true);
00295         createButt->setEnabled(true);
00296       }
00297   }
00298   else {
00299       // save whitout description
00300       emit slotSave();
00301   }
00302 }
00303 
00304 // ---------------------------------------------------------------
00305 void LibraryDialog::intoStream(QTextStream &Stream, QString &tmp,
00306              const char *sec)
00307 {
00308   int i = tmp.indexOf("TOP LEVEL MARK");
00309   if(i >= 0) {
00310     i = tmp.indexOf('\n',i) + 1;
00311     tmp = tmp.mid(i);
00312   }
00313   Stream << "  <" << sec << ">";
00314   Stream << tmp;
00315   Stream << "  </" << sec << ">\n";
00316 }
00317 
00318 // ---------------------------------------------------------------
00319 int LibraryDialog::intoFile(QString &ifn, QString &ofn, QStringList &IFiles)
00320 {
00321   int error = 0;
00322   QFile ifile(ifn);
00323   if(!ifile.open(QIODevice::ReadOnly)) {
00324     ErrText->insertPlainText(QObject::tr("ERROR: Cannot open file \"%1\".\n").
00325         arg(ifn));
00326     error++;
00327   }
00328   else {
00329     QByteArray FileContent = ifile.readAll();
00330     ifile.close();
00331     if(ifile.name().right(4) == ".lst")
00332       LibDir.remove(ifile.name());
00333     QDir LibDirSub(LibDir);
00334     if(!LibDirSub.cd(NameEdit->text())) {
00335       if(!LibDirSub.mkdir(NameEdit->text())) {
00336   ErrText->insertPlainText(
00337           QObject::tr("ERROR: Cannot create user library subdirectory !\n"));
00338   error++;
00339       }
00340       LibDirSub.cd(NameEdit->text());
00341     }
00342     QFileInfo Info(ofn);
00343     ofn = Info.fileName();
00344     IFiles.append(ofn);
00345     QFile ofile;
00346     ofile.setFileName(LibDirSub.absFilePath(ofn));
00347     if(!ofile.open(QIODevice::WriteOnly)) {
00348       ErrText->insertPlainText(
00349         QObject::tr("ERROR: Cannot create file \"%1\".\n").arg(ofn));
00350       error++;
00351     }
00352     else {
00353       QDataStream ds(&ofile);
00354       ds.writeRawBytes(FileContent.data(), FileContent.size());
00355       ofile.close();
00356     }
00357   }
00358   return error;
00359 }
00360 
00361 // ---------------------------------------------------------------
00362 void LibraryDialog::slotCheckDescrChanged(int state)
00363 {
00364   if (state == Qt::Unchecked){
00365     ButtCreateNext->setText(tr("Create"));
00366   }
00367   else {
00368     ButtCreateNext->setText(tr("Next..."));
00369   }
00370 }
00371 
00372 // ---------------------------------------------------------------
00373 void LibraryDialog::slotPrevDescr()
00374 {
00375   if ( curDescr > 0 ) {
00376     nextButt->setDisabled(false);
00377     checkedCktName->setText(SelectedNames[curDescr]);
00378     curDescr--;
00379     checkedCktName->setText(SelectedNames[curDescr]);
00380     textDescr->setText(Descriptions[curDescr]);
00381   }
00382 
00383   if (curDescr == 0){
00384     prevButt->setDisabled(true);
00385     nextButt->setEnabled(true);
00386   }
00387 }
00388 
00389 // ---------------------------------------------------------------
00390 void LibraryDialog::slotNextDescr()
00391 {
00392   if ( curDescr < SelectedNames.count()) {
00393     prevButt->setDisabled(false);
00394     checkedCktName->setText(SelectedNames[curDescr]);
00395     curDescr++;
00396     checkedCktName->setText(SelectedNames[curDescr]);
00397     textDescr->setText(Descriptions[curDescr]);
00398   }
00399 
00400   if (curDescr == SelectedNames.count()-1){
00401     nextButt->setDisabled(true);
00402     createButt->setEnabled(true);
00403   }
00404 }
00405 
00406 void LibraryDialog::slotUpdateDescription()
00407 {
00408   // store on every change
00409   Descriptions[curDescr] = textDescr->text();
00410 }
00411 
00412 // ---------------------------------------------------------------
00413 void LibraryDialog::slotSave()
00414 {
00415   stackedWidgets->setCurrentIndex(2); //message window
00416   libSaveName->setText(NameEdit->text() + ".lib");
00417 
00418   ErrText->insertPlainText(tr("Saving library..."));
00419 
00420   if(!LibFile.open(QIODevice::WriteOnly)) {
00421     ErrText->appendPlainText(tr("Error: Cannot create library!"));
00422     return;
00423   }
00424   QTextStream Stream;
00425   Stream.setDevice(&LibFile);
00426   Stream << "<Qucs Library " PACKAGE_VERSION " \""
00427    << NameEdit->text() << "\">\n\n";
00428 
00429   bool Success = true, ret;
00430 
00431   QString tmp;
00432   QTextStream ts(&tmp, QIODevice::WriteOnly);
00433 
00434   for (int i=0; i < SelectedNames.count(); i++) {
00435     ErrText->insertPlainText("\n=================\n");
00436 
00437     QString description = "";
00438     if(checkDescr->checkState() == Qt::Checked)
00439       description = Descriptions[i];
00440 
00441     Stream << "<Component " + SelectedNames[i].section('.',0,0) + ">\n"
00442            << "  <Description>\n"
00443            << description
00444            << "\n  </Description>\n";
00445 
00446     Schematic *Doc = new Schematic(0, QucsSettings.QucsWorkDir.filePath(SelectedNames[i]));
00447     ErrText->insertPlainText(tr("Loading subcircuit \"%1\".\n").arg(SelectedNames[i]));
00448     if(!Doc->loadDocument()) {  // load document if possible
00449         delete Doc;
00450         ErrText->appendPlainText(tr("Error: Cannot load subcircuit \"%1\".").
00451       arg(SelectedNames[i]));
00452         break;
00453     }
00454     Doc->DocName = NameEdit->text() + "_" + SelectedNames[i];
00455     Success = false;
00456 
00457     // save analog model
00458     tmp.truncate(0);
00459     Doc->isAnalog = true;
00460 
00461     ErrText->insertPlainText("\n");
00462     ErrText->insertPlainText(tr("Creating Qucs netlist.\n"));
00463     ret = Doc->createLibNetlist(&ts, ErrText, -1);
00464     if(ret) {
00465       intoStream(Stream, tmp, "Model");
00466       int error = 0;
00467       QStringList IFiles;
00468       SubMap::Iterator it = FileList.begin();
00469       while(it != FileList.end()) {
00470           QString f = it.data().File;
00471           QString ifn, ofn;
00472           if(it.data().Type == "SCH") {
00473               ifn = f + ".lst";
00474               ofn = ifn;
00475           }
00476           else if(it.data().Type == "CIR") {
00477               ifn = f + ".lst";
00478               ofn = ifn;
00479           }
00480           if (!ifn.isEmpty()) error += intoFile(ifn, ofn, IFiles);
00481           it++;
00482       }
00483       FileList.clear();
00484       if(!IFiles.isEmpty()) {
00485           Stream << "  <ModelIncludes \"" << IFiles.join("\" \"") << "\">\n";
00486       }
00487       Success = error > 0 ? false : true;
00488     }
00489     else {
00490         ErrText->insertPlainText("\n");
00491         ErrText->insertPlainText(tr("Error: Cannot create netlist for \"%1\".\n").arg(SelectedNames[i]));
00492     }
00493 
00494     // save verilog model
00495     tmp.truncate(0);
00496     Doc->isVerilog = true;
00497     Doc->isAnalog = false;
00498 
00499     ErrText->insertPlainText("\n");
00500     ErrText->insertPlainText(tr("Creating Verilog netlist.\n"));
00501     ret = Doc->createLibNetlist(&ts, ErrText, 0);
00502     if(ret) {
00503       intoStream(Stream, tmp, "VerilogModel");
00504       int error = 0;
00505       QStringList IFiles;
00506       SubMap::Iterator it = FileList.begin();
00507       while(it != FileList.end()) {
00508           QString f = it.data().File;
00509           QString ifn, ofn;
00510           if(it.data().Type == "SCH") {
00511               ifn = f + ".lst";
00512               ofn = f + ".v";
00513           }
00514           else if(it.data().Type == "VER") {
00515               ifn = f;
00516               ofn = ifn;
00517           }
00518           if (!ifn.isEmpty()) error += intoFile(ifn, ofn, IFiles);
00519           it++;
00520       }
00521       FileList.clear();
00522       if(!IFiles.isEmpty()) {
00523           Stream << "  <VerilogModelIncludes \""
00524                  << IFiles.join("\" \"") << "\">\n";
00525       }
00526       Success = error > 0 ? false : true;
00527     }
00528     else {
00529         ErrText->insertPlainText("\n");
00530     }
00531 
00532     // save vhdl model
00533     tmp.truncate(0);
00534     Doc->isVerilog = false;
00535     Doc->isAnalog = false;
00536 
00537     ErrText->insertPlainText(tr("Creating VHDL netlist.\n"));
00538     ret = Doc->createLibNetlist(&ts, ErrText, 0);
00539     if(ret) {
00540       intoStream(Stream, tmp, "VHDLModel");
00541       int error = 0;
00542       QStringList IFiles;
00543       SubMap::Iterator it = FileList.begin();
00544       while(it != FileList.end()) {
00545           QString f = it.data().File;
00546           QString ifn, ofn;
00547           if(it.data().Type == "SCH") {
00548               ifn = f + ".lst";
00549               ofn = f + ".vhdl";
00550           }
00551           else if(it.data().Type == "VHD") {
00552               ifn = f;
00553               ofn = ifn;
00554           }
00555           if (!ifn.isEmpty()) error += intoFile(ifn, ofn, IFiles);
00556           it++;
00557       }
00558       FileList.clear();
00559       if(!IFiles.isEmpty()) {
00560           Stream << "  <VHDLModelIncludes \""
00561                  << IFiles.join("\" \"") << "\">\n";
00562       }
00563       Success = error > 0 ? false : true;
00564       }
00565       else {
00566           ErrText->insertPlainText("\n");
00567       }
00568 
00569       Stream << "  <Symbol>\n";
00570       Doc->createSubcircuitSymbol();
00571       Painting *pp;
00572       for(pp = Doc->SymbolPaints.first(); pp != 0; pp = Doc->SymbolPaints.next())
00573         Stream << "    <" << pp->save() << ">\n";
00574 
00575       Stream << "  </Symbol>\n"
00576              << "</Component>\n\n";
00577 
00578       delete Doc;
00579 
00580       if(!Success) break;
00581 
00582   } // for
00583 
00584   LibFile.close();
00585   if(!Success) {
00586     LibFile.remove();
00587     ErrText->appendPlainText(tr("Error creating library."));
00588     return;
00589   }
00590 
00591   ErrText->appendPlainText(tr("Successfully created library."));
00592 }
00593 
00594 // ---------------------------------------------------------------
00595 void LibraryDialog::slotSelectAll()
00596 {
00597   QCheckBox *p;
00598   QListIterator<QCheckBox *> i(BoxList);
00599   while(i.hasNext()){
00600     p = i.next();
00601     p->setChecked(true);
00602   }
00603 }
00604 
00605 // ---------------------------------------------------------------
00606 void LibraryDialog::slotSelectNone()
00607 {
00608   QCheckBox *p;
00609   QListIterator<QCheckBox *> i(BoxList);
00610   while(i.hasNext()){
00611     p = i.next();
00612     p->setChecked(false);
00613   }
00614 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines