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