Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/dialogs/packagedialog.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               packagedialog.cpp
00003                              -------------------
00004     begin                : Sun Jun 25 2006
00005     copyright            : (C) 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 <stdlib.h>
00023 
00024 #include <QLabel>
00025 #include <QLineEdit>
00026 #include <QTextEdit>
00027 #include <QCheckBox>
00028 #include <QFileDialog>
00029 #include <QMessageBox>
00030 #include <QPushButton>
00031 #include <QScrollArea>
00032 #include <QDataStream>
00033 #include <QButtonGroup>
00034 #include <QVBoxLayout>
00035 #include <QHBoxLayout>
00036 #include <QGroupBox>
00037 
00038 #include "packagedialog.h"
00039 #include "qucs.h"
00040 #include "main.h"
00041 #include "misc.h"
00042 
00043 
00044 #define HEADER_LENGTH   32
00045 #define CODE_ERROR      0x0000
00046 #define CODE_DIR        0x0010
00047 #define CODE_DIR_END    0x0018
00048 #define CODE_FILE       0x0020
00049 #define CODE_LIBRARY    0x0040
00050 
00051 
00052 PackageDialog::PackageDialog(QWidget *parent_, bool create_)
00053       : QDialog(parent_) 
00054 {
00055   all = new QVBoxLayout(this);
00056   all->setMargin(5);
00057   all->setSpacing(6);
00058 
00059   QHBoxLayout *h2 = new QHBoxLayout();
00060 
00061   if(create_) {  // create or extract package ?
00062     setWindowTitle(tr("Create Project Package"));
00063 
00064     QHBoxLayout *h1 = new QHBoxLayout();
00065     all->addLayout(h1);
00066     QLabel *packLabel = new QLabel(tr("Package:"));
00067     NameEdit = new QLineEdit();
00068     QPushButton *ButtBrowse = new QPushButton(tr("Browse"));
00069     connect(ButtBrowse, SIGNAL(clicked()), SLOT(slotBrowse()));
00070     h1->addWidget(packLabel);
00071     h1->addWidget(NameEdit);
00072     h1->addWidget(ButtBrowse);
00073 
00074     LibraryCheck = new QCheckBox(tr("include user libraries"));
00075     all->addWidget(LibraryCheck);
00076 
00077     Group = new QGroupBox(tr("Choose projects:"));
00078     all->addWidget(Group);
00079     
00080     QScrollArea *scrollArea = new QScrollArea(Group);
00081     scrollArea->setWidgetResizable(true);
00082     
00083     QWidget *scrollWidget = new QWidget();
00084     
00085     QVBoxLayout *checkBoxLayout = new QVBoxLayout();
00086     scrollWidget->setLayout(checkBoxLayout);
00087     scrollArea->setWidget(scrollWidget);
00088     
00089     QVBoxLayout *areaLayout = new QVBoxLayout();
00090     areaLayout->addWidget(scrollArea);
00091     Group->setLayout(areaLayout);
00092     
00093     // ...........................................................
00094     all->addLayout(h2);
00095     QPushButton *ButtCreate = new QPushButton(tr("Create"));
00096     h2->addWidget(ButtCreate);
00097     connect(ButtCreate, SIGNAL(clicked()), SLOT(slotCreate()));
00098     QPushButton *ButtCancel = new QPushButton(tr("Cancel"));
00099     h2->addWidget(ButtCancel);
00100     connect(ButtCancel, SIGNAL(clicked()), SLOT(reject()));
00101 
00102     // ...........................................................
00103     // insert all projects
00104     QStringList PrDirs = QucsSettings.QucsHomeDir.entryList("*", QDir::Dirs, QDir::Name);
00105     QStringList::iterator it;
00106     for(it = PrDirs.begin(); it != PrDirs.end(); it++)
00107        if((*it).right(4) == "_prj"){   // project directories end with "_prj"
00108          QCheckBox *subCheck = new QCheckBox((*it).left((*it).length()-4));
00109          checkBoxLayout->addWidget(subCheck);
00110          BoxList.append(subCheck);
00111        }
00112     
00113     //QColor theColor;
00114     if(BoxList.isEmpty()) {
00115       ButtCreate->setEnabled(false);
00116       //theColor =
00117       //   (new QLabel(tr("No projects!"), Dia_Box))->paletteBackgroundColor();
00118       QLabel *noProj = new QLabel(tr("No projects!"));
00119       checkBoxLayout->addWidget(noProj);              
00120     }
00121     //else
00122     //  theColor = BoxList.current()->paletteBackgroundColor();
00123     //Dia_Scroll->viewport()->setPaletteBackgroundColor(theColor);
00124   }
00125 
00126   else {  // of "if(create_)"
00127     setWindowTitle(tr("Extract Project Package"));
00128 
00129     MsgText = new QTextEdit(this);
00130     MsgText->setTextFormat(Qt::PlainText);
00131     MsgText->setWordWrapMode(QTextOption::NoWrap);
00132     MsgText->setReadOnly(true);
00133     all->addWidget(MsgText);
00134 
00135     all->addLayout(h2);
00136     h2->addStretch(5);
00137     ButtClose = new QPushButton(tr("Close"));
00138     h2->addWidget(ButtClose);
00139     ButtClose->setDisabled(true);
00140     connect(ButtClose, SIGNAL(clicked()), SLOT(accept()));
00141 
00142     resize(400, 250);
00143   }
00144 }
00145 
00146 PackageDialog::~PackageDialog()
00147 {
00148   delete all;
00149 }
00150 
00151 // ---------------------------------------------------------------
00152 void PackageDialog::slotBrowse()
00153 {
00154   QString s = QFileDialog::getSaveFileName(
00155      lastDir.isEmpty() ? QString(".") : lastDir,
00156      tr("Qucs Packages")+" (*.qucs);;"+
00157      tr("Any File")+" (*)",
00158      this, 0, tr("Enter a Package File Name"));
00159   if(s.isEmpty()) return;
00160 
00161   QFileInfo Info(s);
00162   lastDir = Info.dirPath(true);  // remember last directory
00163 
00164   if(Info.extension().isEmpty())
00165     s += ".qucs";
00166   NameEdit->setText(s);
00167 }
00168 
00169 // ***************************************************************
00170 // *****           Functions for creating package            *****
00171 // ***************************************************************
00172 
00173 int PackageDialog::insertFile(const QString& FileName, QFile& File,
00174                               QDataStream& Stream)
00175 {
00176   QByteArray FileContent;
00177 
00178   if(!File.open(QIODevice::ReadOnly)) {
00179     QMessageBox::critical(this, tr("Error"),
00180                     tr("Cannot open \"%1\"!").arg(FileName));
00181     return -1;
00182   }
00183 
00184   Q_ULONG Count = File.size();
00185   char *p = (char*)malloc(Count+FileName.length()+2);
00186   strcpy(p, FileName.toLatin1());
00187   File.readBlock(p+FileName.length()+1, Count);
00188   File.close();
00189 
00190   Count += FileName.length()+1;
00191   FileContent = qCompress((unsigned char*)p, Count);
00192   free(p);
00193 
00194   Stream.writeBytes(FileContent.data(), FileContent.size());
00195   return 0;
00196 }
00197 
00198 // ---------------------------------------------------------------
00199 int PackageDialog::insertDirectory(const QString& DirName,
00200                            QDataStream& Stream)
00201 {
00202   QFile File;
00203   QDir myDir(DirName);
00204 
00205   // Put all files of this directory into the package.
00206   QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
00207   QStringList::iterator it;
00208   for(it = Entries.begin(); it != Entries.end(); ++it) {
00209     File.setFileName(myDir.absFilePath(*it));
00210     Stream << Q_UINT32(CODE_FILE);
00211     if(insertFile(*it, File, Stream) < 0)
00212       return -1;
00213   }
00214 
00215   // Put all subdirectories into the package.
00216   Entries = myDir.entryList("*", QDir::Dirs, QDir::Name);
00217   Entries.pop_front();  // delete "." from list
00218   Entries.pop_front();  // delete ".." from list
00219   for(it = Entries.begin(); it != Entries.end(); ++it) {
00220     Stream << Q_UINT32(CODE_DIR) << (*it).toLatin1();
00221     if(insertDirectory(myDir.absPath()+QDir::separator()+(*it), Stream) < 0)
00222       return -1;
00223     Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
00224   }
00225   return 0;
00226 }
00227 
00228 // ---------------------------------------------------------------
00229 int PackageDialog::insertLibraries(QDataStream& Stream)
00230 {
00231   QFile File;
00232   QDir myDir(QucsSettings.QucsHomeDir.absPath() + QDir::separator() + "user_lib");
00233   QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
00234   QStringList::iterator it;
00235   for(it = Entries.begin(); it != Entries.end(); ++it) {
00236     File.setFileName(myDir.absFilePath(*it));
00237     Stream << Q_UINT32(CODE_LIBRARY);
00238     if(insertFile(*it, File, Stream) < 0)
00239       return -1;
00240   }
00241   return 0;
00242 }
00243 
00244 // ---------------------------------------------------------------
00245 void PackageDialog::slotCreate()
00246 {
00247   if(NameEdit->text().isEmpty()) {
00248     QMessageBox::critical(this, tr("Error"), tr("Please insert a package name!"));
00249     return;
00250   }
00251 
00252   QCheckBox *p;
00253   QListIterator<QCheckBox *> i(BoxList);
00254   if(!LibraryCheck->isChecked()) {
00255     int count=0;
00256     while(i.hasNext()){
00257       p = i.next();
00258       if(p->isChecked())
00259         count++;
00260     }
00261     
00262     if(count < 1) {
00263       QMessageBox::critical(this, tr("Error"), tr("Please choose at least one project!"));
00264       return;
00265     }
00266   }
00267 
00268   QString s(NameEdit->text());
00269   QFileInfo Info(s);
00270   if(Info.extension().isEmpty())
00271     s += ".qucs";
00272   NameEdit->setText(s);
00273 
00274   QFile PkgFile(s);
00275   if(PkgFile.exists())
00276     if(QMessageBox::information(this, tr("Info"),
00277           tr("Output file already exists!")+"\n"+tr("Overwrite it?"),
00278           tr("&Yes"), tr("&No"), 0,1,1))
00279       return;
00280 
00281   if(!PkgFile.open(QIODevice::ReadWrite)) {
00282     QMessageBox::critical(this, tr("Error"), tr("Cannot create package!"));
00283     return;
00284   }
00285   QDataStream Stream(&PkgFile);
00286 
00287   // First write header.
00288   char Header[HEADER_LENGTH];
00289   memset(Header, 0, HEADER_LENGTH);
00290   strcpy(Header, "Qucs package " PACKAGE_VERSION);
00291   PkgFile.writeBlock(Header, HEADER_LENGTH);
00292 
00293 
00294   // Write project files to package.
00295   i.toFront();
00296   while(i.hasNext()) {
00297     p = i.next();  
00298     if(p->isChecked()) {
00299       s = p->text() + "_prj";
00300       Stream << Q_UINT32(CODE_DIR) << s.toLatin1();
00301       s = QucsSettings.QucsHomeDir.absPath() + QDir::separator() + s;
00302       if(insertDirectory(s, Stream) < 0) {
00303         PkgFile.close();
00304         PkgFile.remove();
00305         return;
00306       }
00307       Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
00308     }
00309   }
00310 
00311   // Write user libraries to package if desired.
00312   if(LibraryCheck->isChecked())
00313     if(insertLibraries(Stream) < 0) {
00314       PkgFile.close();
00315       PkgFile.remove();
00316       return;
00317     }
00318 
00319   // Calculate checksum and write it to package file.
00320   PkgFile.at(0);
00321   QByteArray Content = PkgFile.readAll();
00322   Q_UINT16 Checksum = qChecksum(Content.data(), Content.size());
00323   PkgFile.at(HEADER_LENGTH-sizeof(Q_UINT16));
00324   Stream << Checksum;
00325   PkgFile.close();
00326 
00327   QMessageBox::information(this, tr("Info"),
00328           tr("Successfully created Qucs package!"));
00329   accept();
00330 }
00331 
00332 
00333 
00334 // ***************************************************************
00335 // *****          Functions for extracting package           *****
00336 // ***************************************************************
00337 
00338 void PackageDialog::extractPackage()
00339 {
00340   QString s = QFileDialog::getOpenFileName(
00341      lastDir.isEmpty() ? QString(".") : lastDir,
00342      tr("Qucs Packages")+" (*.qucs);;"+
00343      tr("Any File")+" (*)",
00344      this, 0, tr("Enter a Package File Name"));
00345 
00346   if(s.isEmpty()) {
00347     reject();
00348     return;
00349   }
00350 
00351   QFileInfo Info(s);
00352   lastDir = Info.dirPath(true);  // remember last directory
00353 
00354   QFile PkgFile(s);
00355   if(!PkgFile.open(QIODevice::ReadOnly)) {
00356     if(Info.extension().isEmpty()) s += ".qucs";
00357     PkgFile.setFileName(s);
00358     if(!PkgFile.open(QIODevice::ReadOnly)) {
00359       MsgText->append(tr("ERROR: Cannot open package!"));
00360       ButtClose->setDisabled(false);
00361       return;
00362     }
00363   }
00364   QDataStream Stream(&PkgFile);
00365 
00366   QDir currDir = QucsSettings.QucsHomeDir;
00367   QString Version;
00368   Q_UINT16 Checksum;
00369   Q_UINT32 Code, Length;
00370 
00371   // First read and check header.
00372   QByteArray Content = PkgFile.readAll();
00373   if(strncmp(Content.data(), "Qucs package ", 13) != 0) {
00374     MsgText->append(tr("ERROR: File contains wrong header!"));
00375     goto ErrorEnd;
00376   }
00377 
00378   Version = QString(Content.data()+13);
00379   if(!misc::checkVersion(Version)) {
00380     MsgText->append(tr("ERROR: Wrong version number!"));
00381     goto ErrorEnd;
00382   }
00383 
00384   // checksum correct ?
00385   PkgFile.at(HEADER_LENGTH-2);
00386   Stream >> Checksum;
00387   *((Q_UINT16*)(Content.data()+HEADER_LENGTH-2)) = 0;
00388   if(Checksum != qChecksum(Content.data(), Content.size())) {
00389     MsgText->append(tr("ERROR: Checksum mismatch!"));
00390     goto ErrorEnd;
00391   }
00392   Content.resize(0);   // dispose memory
00393 
00394 
00395   // work on all files and directories in the package
00396   for(;;) {
00397     if(PkgFile.atEnd()) break;
00398     Stream >> Code >> Length;
00399 
00400     switch(Code) {
00401       case CODE_DIR:
00402         if(extractDirectory(PkgFile, Length, currDir) > 0)
00403           break;
00404         goto ErrorEnd;
00405       case CODE_DIR_END:
00406         MsgText->append(tr("Leave directory \"%1\"").arg(currDir.absPath()));
00407         currDir.cdUp();
00408         break;
00409       case CODE_FILE:
00410         if(extractFile(PkgFile, Length, currDir) > 0)
00411           break;
00412         goto ErrorEnd;
00413       case CODE_LIBRARY:
00414         if(extractLibrary(PkgFile, Length) > 0)
00415           break;
00416         goto ErrorEnd;
00417       default:
00418         MsgText->append(tr("ERROR: Package is corrupt!"));
00419         goto ErrorEnd;
00420     }
00421   }
00422 
00423 
00424   MsgText->append(" ");
00425   MsgText->append(tr("Successfully extracted package!"));
00426 ErrorEnd:
00427   MsgText->append(" ");
00428   ButtClose->setDisabled(false);
00429   PkgFile.close();
00430 }
00431 
00432 // ---------------------------------------------------------------
00433 int PackageDialog::extractDirectory(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
00434 {
00435   char *p = (char*)malloc(Count);
00436   PkgFile.readBlock(p, Count);
00437 
00438   if(currDir.cd(QString(p))) { // directory exists ?
00439     MsgText->append(tr("ERROR: Project directory \"%1\" already exists!").arg(QString(p)));
00440     return -1;
00441   }
00442 
00443   if(!currDir.mkdir(QString(p))) {
00444     MsgText->append(tr("ERROR: Cannot create directory \"%1\"!").arg(QString(p)));
00445     return -2;
00446   }
00447   currDir.cd(QString(p));
00448   MsgText->append(tr("Create and enter directory \"%1\"").arg(currDir.absPath()));
00449 
00450   free(p);
00451   return 1;
00452 }
00453 
00454 // ---------------------------------------------------------------
00455 int PackageDialog::extractFile(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
00456 {
00457   char *p = (char*)malloc(Count);
00458   PkgFile.readBlock(p, Count);
00459   QByteArray Content = qUncompress((unsigned char*)p, Count);
00460   free(p);
00461 
00462   p = Content.data();
00463   QFile File(currDir.absFilePath(QString(p)));
00464   if(!File.open(QIODevice::WriteOnly)) {
00465     MsgText->append(tr("ERROR: Cannot create file \"%1\"!").arg(QString(p)));
00466     return -1;
00467   }
00468 
00469   File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
00470   File.close();
00471   MsgText->append(tr("Create file \"%1\"").arg(QString(p)));
00472   return 1;
00473 }
00474 
00475 // ---------------------------------------------------------------
00476 int PackageDialog::extractLibrary(QFile& PkgFile, Q_UINT32 Count)
00477 {
00478   char *p = (char*)malloc(Count);
00479   PkgFile.readBlock(p, Count);
00480   QByteArray Content = qUncompress((unsigned char*)p, Count);
00481   free(p);
00482 
00483   p = Content.data();
00484   QFile File(QucsSettings.QucsHomeDir.absPath() +
00485              QDir::convertSeparators("/user_lib/") + QString(p));
00486   if(File.exists()) {
00487     MsgText->append(tr("ERROR: User library \"%1\" already exists!").arg(QString(p)));
00488     return -1;
00489   }
00490 
00491   if(!File.open(QIODevice::WriteOnly)) {
00492     MsgText->append(tr("ERROR: Cannot create library \"%1\"!").arg(QString(p)));
00493     return -1;
00494   }
00495 
00496   File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
00497   File.close();
00498   MsgText->append(tr("Create library \"%1\"").arg(QString(p)));
00499   return 1;
00500 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines