Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
packagedialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  packagedialog.cpp
3  -------------------
4  begin : Sun Jun 25 2006
5  copyright : (C) 2006 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <QtGui>
23 #include <stdlib.h>
24 
25 #include <QLabel>
26 #include <QLineEdit>
27 #include <QTextEdit>
28 #include <QCheckBox>
29 #include <QFileDialog>
30 #include <QMessageBox>
31 #include <QPushButton>
32 #include <QScrollArea>
33 #include <QDataStream>
34 #include <QButtonGroup>
35 #include <QVBoxLayout>
36 #include <QHBoxLayout>
37 
38 #include "packagedialog.h"
39 #include "qucs.h"
40 #include "main.h"
41 
42 
43 #define HEADER_LENGTH 32
44 #define CODE_ERROR 0x0000
45 #define CODE_DIR 0x0010
46 #define CODE_DIR_END 0x0018
47 #define CODE_FILE 0x0020
48 #define CODE_LIBRARY 0x0040
49 
50 
51 PackageDialog::PackageDialog(QWidget *parent_, bool create_)
52  : QDialog(parent_) //, 0, TRUE, Qt::WDestructiveClose)
53 {
54  all = new QVBoxLayout(this);
55  all->setMargin(5);
56  all->setSpacing(6);
57 
58  QHBoxLayout *h2 = new QHBoxLayout();
59 
60  if(create_) { // create or extract package ?
61  setWindowTitle(tr("Create Project Package"));
62 
63  QHBoxLayout *h1 = new QHBoxLayout();
64  all->addLayout(h1);
65  QLabel *packLabel = new QLabel(tr("Package:"));
66  NameEdit = new QLineEdit();
67  QPushButton *ButtBrowse = new QPushButton(tr("Browse"));
68  connect(ButtBrowse, SIGNAL(clicked()), SLOT(slotBrowse()));
69  h1->addWidget(packLabel);
70  h1->addWidget(NameEdit);
71  h1->addWidget(ButtBrowse);
72 
73  LibraryCheck = new QCheckBox(tr("include user libraries"));
74  all->addWidget(LibraryCheck);
75 
76  Group = new QGroupBox(tr("Choose projects:"));
77  all->addWidget(Group);
78 
79  QScrollArea *scrollArea = new QScrollArea(Group);
80  scrollArea->setWidgetResizable(true);
81 
82  QWidget *scrollWidget = new QWidget();
83 
84  QVBoxLayout *checkBoxLayout = new QVBoxLayout();
85  scrollWidget->setLayout(checkBoxLayout);
86  scrollArea->setWidget(scrollWidget);
87 
88  QVBoxLayout *areaLayout = new QVBoxLayout();
89  areaLayout->addWidget(scrollArea);
90  Group->setLayout(areaLayout);
91 
92  // ...........................................................
93  all->addLayout(h2);
94  QPushButton *ButtCreate = new QPushButton(tr("Create"));
95  h2->addWidget(ButtCreate);
96  connect(ButtCreate, SIGNAL(clicked()), SLOT(slotCreate()));
97  QPushButton *ButtCancel = new QPushButton(tr("Cancel"));
98  h2->addWidget(ButtCancel);
99  connect(ButtCancel, SIGNAL(clicked()), SLOT(reject()));
100 
101  // ...........................................................
102  // insert all projects
103  QStringList PrDirs = QucsSettings.QucsHomeDir.entryList("*", QDir::Dirs, QDir::Name);
104  QStringList::iterator it;
105  for(it = PrDirs.begin(); it != PrDirs.end(); it++)
106  if((*it).right(4) == "_prj"){ // project directories end with "_prj"
107  QCheckBox *subCheck = new QCheckBox((*it).left((*it).length()-4));
108  checkBoxLayout->addWidget(subCheck);
109  BoxList.append(subCheck);
110  }
111 
112  //QColor theColor;
113  if(BoxList.isEmpty()) {
114  ButtCreate->setEnabled(false);
115  //theColor =
116  // (new QLabel(tr("No projects!"), Dia_Box))->paletteBackgroundColor();
117  QLabel *noProj = new QLabel(tr("No projects!"));
118  checkBoxLayout->addWidget(noProj);
119  }
120  //else
121  // theColor = BoxList.current()->paletteBackgroundColor();
122  //Dia_Scroll->viewport()->setPaletteBackgroundColor(theColor);
123  }
124 
125  else { // of "if(create_)"
126  setWindowTitle(tr("Extract Project Package"));
127 
128  MsgText = new QTextEdit(this);
129  MsgText->setTextFormat(Qt::PlainText);
130  MsgText->setWordWrapMode(QTextOption::NoWrap);
131  MsgText->setReadOnly(true);
132  all->addWidget(MsgText);
133 
134  all->addLayout(h2);
135  h2->addStretch(5);
136  ButtClose = new QPushButton(tr("Close"));
137  h2->addWidget(ButtClose);
138  ButtClose->setDisabled(true);
139  connect(ButtClose, SIGNAL(clicked()), SLOT(accept()));
140 
141  resize(400, 250);
142  }
143 }
144 
146 {
147  delete all;
148 }
149 
150 // ---------------------------------------------------------------
152 {
153  QString s = QFileDialog::getSaveFileName(
154  lastDir.isEmpty() ? QString(".") : lastDir,
155  tr("Qucs Packages")+" (*.qucs);;"+
156  tr("Any File")+" (*)",
157  this, 0, tr("Enter a Package File Name"));
158  if(s.isEmpty()) return;
159 
160  QFileInfo Info(s);
161  lastDir = Info.dirPath(true); // remember last directory
162 
163  if(Info.extension().isEmpty())
164  s += ".qucs";
165  NameEdit->setText(s);
166 }
167 
168 // ***************************************************************
169 // ***** Functions for creating package *****
170 // ***************************************************************
171 
172 int PackageDialog::insertFile(const QString& FileName, QFile& File,
173  QDataStream& Stream)
174 {
175  QByteArray FileContent;
176 
177  if(!File.open(QIODevice::ReadOnly)) {
178  QMessageBox::critical(this, tr("Error"),
179  tr("Cannot open \"%1\"!").arg(FileName));
180  return -1;
181  }
182 
183  Q_ULONG Count = File.size();
184  char *p = (char*)malloc(Count+FileName.length()+2);
185  strcpy(p, FileName.latin1());
186  File.readBlock(p+FileName.length()+1, Count);
187  File.close();
188 
189  Count += FileName.length()+1;
190  FileContent = qCompress((unsigned char*)p, Count);
191  free(p);
192 
193  Stream.writeBytes(FileContent.data(), FileContent.size());
194  return 0;
195 }
196 
197 // ---------------------------------------------------------------
198 int PackageDialog::insertDirectory(const QString& DirName,
199  QDataStream& Stream)
200 {
201  QFile File;
202  QDir myDir(DirName);
203 
204  // Put all files of this directory into the package.
205  QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
206  QStringList::iterator it;
207  for(it = Entries.begin(); it != Entries.end(); ++it) {
208  File.setName(myDir.absFilePath(*it));
209  Stream << Q_UINT32(CODE_FILE);
210  if(insertFile(*it, File, Stream) < 0)
211  return -1;
212  }
213 
214  // Put all subdirectories into the package.
215  Entries = myDir.entryList("*", QDir::Dirs, QDir::Name);
216  Entries.pop_front(); // delete "." from list
217  Entries.pop_front(); // delete ".." from list
218  for(it = Entries.begin(); it != Entries.end(); ++it) {
219  Stream << Q_UINT32(CODE_DIR) << (*it).latin1();
220  if(insertDirectory(myDir.absPath()+QDir::separator()+(*it), Stream) < 0)
221  return -1;
222  Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
223  }
224  return 0;
225 }
226 
227 // ---------------------------------------------------------------
228 int PackageDialog::insertLibraries(QDataStream& Stream)
229 {
230  QFile File;
231  QDir myDir(QucsSettings.QucsHomeDir.absPath() + QDir::separator() + "user_lib");
232  QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
233  QStringList::iterator it;
234  for(it = Entries.begin(); it != Entries.end(); ++it) {
235  File.setName(myDir.absFilePath(*it));
236  Stream << Q_UINT32(CODE_LIBRARY);
237  if(insertFile(*it, File, Stream) < 0)
238  return -1;
239  }
240  return 0;
241 }
242 
243 // ---------------------------------------------------------------
245 {
246  if(NameEdit->text().isEmpty()) {
247  QMessageBox::critical(this, tr("Error"), tr("Please insert a package name!"));
248  return;
249  }
250 
251  QCheckBox *p;
252  QListIterator<QCheckBox *> i(BoxList);
253  if(!LibraryCheck->isChecked()) {
254  int count=0;
255  while(i.hasNext()){
256  p = i.next();
257  if(p->isChecked())
258  count++;
259  }
260 
261  if(count < 1) {
262  QMessageBox::critical(this, tr("Error"), tr("Please choose at least one project!"));
263  return;
264  }
265  }
266 
267  QString s(NameEdit->text());
268  QFileInfo Info(s);
269  if(Info.extension().isEmpty())
270  s += ".qucs";
271  NameEdit->setText(s);
272 
273  QFile PkgFile(s);
274  if(PkgFile.exists())
275  if(QMessageBox::information(this, tr("Info"),
276  tr("Output file already exists!")+"\n"+tr("Overwrite it?"),
277  tr("&Yes"), tr("&No"), 0,1,1))
278  return;
279 
280  if(!PkgFile.open(QIODevice::ReadWrite)) {
281  QMessageBox::critical(this, tr("Error"), tr("Cannot create package!"));
282  return;
283  }
284  QDataStream Stream(&PkgFile);
285 
286  // First write header.
287  char Header[HEADER_LENGTH];
288  memset(Header, 0, HEADER_LENGTH);
289  strcpy(Header, "Qucs package " PACKAGE_VERSION);
290  PkgFile.writeBlock(Header, HEADER_LENGTH);
291 
292 
293  // Write project files to package.
294  i.toFront();
295  while(i.hasNext()) {
296  p = i.next();
297  if(p->isChecked()) {
298  s = p->text() + "_prj";
299  Stream << Q_UINT32(CODE_DIR) << s.latin1();
300  s = QucsSettings.QucsHomeDir.absPath() + QDir::separator() + s;
301  if(insertDirectory(s, Stream) < 0) {
302  PkgFile.close();
303  PkgFile.remove();
304  return;
305  }
306  Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
307  }
308  }
309 
310  // Write user libraries to package if desired.
311  if(LibraryCheck->isChecked())
312  if(insertLibraries(Stream) < 0) {
313  PkgFile.close();
314  PkgFile.remove();
315  return;
316  }
317 
318  // Calculate checksum and write it to package file.
319  PkgFile.at(0);
320  QByteArray Content = PkgFile.readAll();
321  Q_UINT16 Checksum = qChecksum(Content.data(), Content.size());
322  PkgFile.at(HEADER_LENGTH-sizeof(Q_UINT16));
323  Stream << Checksum;
324  PkgFile.close();
325 
326  QMessageBox::information(this, tr("Info"),
327  tr("Successfully created Qucs package!"));
328  accept();
329 }
330 
331 
332 
333 // ***************************************************************
334 // ***** Functions for extracting package *****
335 // ***************************************************************
336 
338 {
339  QString s = QFileDialog::getOpenFileName(
340  lastDir.isEmpty() ? QString(".") : lastDir,
341  tr("Qucs Packages")+" (*.qucs);;"+
342  tr("Any File")+" (*)",
343  this, 0, tr("Enter a Package File Name"));
344 
345  if(s.isEmpty()) {
346  reject();
347  return;
348  }
349 
350  QFileInfo Info(s);
351  lastDir = Info.dirPath(true); // remember last directory
352 
353  QFile PkgFile(s);
354  if(!PkgFile.open(QIODevice::ReadOnly)) {
355  if(Info.extension().isEmpty()) s += ".qucs";
356  PkgFile.setName(s);
357  if(!PkgFile.open(QIODevice::ReadOnly)) {
358  MsgText->append(tr("ERROR: Cannot open package!"));
359  ButtClose->setDisabled(false);
360  return;
361  }
362  }
363  QDataStream Stream(&PkgFile);
364 
365  QDir currDir = QucsSettings.QucsHomeDir;
366  QString Version;
367  Q_UINT16 Checksum;
368  Q_UINT32 Code, Length;
369 
370  // First read and check header.
371  QByteArray Content = PkgFile.readAll();
372  if(strncmp(Content.data(), "Qucs package ", 13) != 0) {
373  MsgText->append(tr("ERROR: File contains wrong header!"));
374  goto ErrorEnd;
375  }
376 
377  Version = QString(Content.data()+13);
378  if(!checkVersion(Version)) {
379  MsgText->append(tr("ERROR: Wrong version number!"));
380  goto ErrorEnd;
381  }
382 
383  // checksum correct ?
384  PkgFile.at(HEADER_LENGTH-2);
385  Stream >> Checksum;
386  *((Q_UINT16*)(Content.data()+HEADER_LENGTH-2)) = 0;
387  if(Checksum != qChecksum(Content.data(), Content.size())) {
388  MsgText->append(tr("ERROR: Checksum mismatch!"));
389  goto ErrorEnd;
390  }
391  Content.resize(0); // dispose memory
392 
393 
394  // work on all files and directories in the package
395  for(;;) {
396  if(PkgFile.atEnd()) break;
397  Stream >> Code >> Length;
398 
399  switch(Code) {
400  case CODE_DIR:
401  if(extractDirectory(PkgFile, Length, currDir) > 0)
402  break;
403  goto ErrorEnd;
404  case CODE_DIR_END:
405  MsgText->append(tr("Leave directory \"%1\"").arg(currDir.absPath()));
406  currDir.cdUp();
407  break;
408  case CODE_FILE:
409  if(extractFile(PkgFile, Length, currDir) > 0)
410  break;
411  goto ErrorEnd;
412  case CODE_LIBRARY:
413  if(extractLibrary(PkgFile, Length) > 0)
414  break;
415  goto ErrorEnd;
416  default:
417  MsgText->append(tr("ERROR: Package is corrupt!"));
418  goto ErrorEnd;
419  }
420  }
421 
422 
423  MsgText->append(" ");
424  MsgText->append(tr("Successfully extracted package!"));
425 ErrorEnd:
426  MsgText->append(" ");
427  ButtClose->setDisabled(false);
428  PkgFile.close();
429 }
430 
431 // ---------------------------------------------------------------
432 int PackageDialog::extractDirectory(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
433 {
434  char *p = (char*)malloc(Count);
435  PkgFile.readBlock(p, Count);
436 
437  if(currDir.cd(QString(p))) { // directory exists ?
438  MsgText->append(tr("ERROR: Project directory \"%1\" already exists!").arg(QString(p)));
439  return -1;
440  }
441 
442  if(!currDir.mkdir(QString(p))) {
443  MsgText->append(tr("ERROR: Cannot create directory \"%1\"!").arg(QString(p)));
444  return -2;
445  }
446  currDir.cd(QString(p));
447  MsgText->append(tr("Create and enter directory \"%1\"").arg(currDir.absPath()));
448 
449  free(p);
450  return 1;
451 }
452 
453 // ---------------------------------------------------------------
454 int PackageDialog::extractFile(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
455 {
456  char *p = (char*)malloc(Count);
457  PkgFile.readBlock(p, Count);
458  QByteArray Content = qUncompress((unsigned char*)p, Count);
459  free(p);
460 
461  p = Content.data();
462  QFile File(currDir.absFilePath(QString(p)));
463  if(!File.open(QIODevice::WriteOnly)) {
464  MsgText->append(tr("ERROR: Cannot create file \"%1\"!").arg(QString(p)));
465  return -1;
466  }
467 
468  File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
469  File.close();
470  MsgText->append(tr("Create file \"%1\"").arg(QString(p)));
471  return 1;
472 }
473 
474 // ---------------------------------------------------------------
475 int PackageDialog::extractLibrary(QFile& PkgFile, Q_UINT32 Count)
476 {
477  char *p = (char*)malloc(Count);
478  PkgFile.readBlock(p, Count);
479  QByteArray Content = qUncompress((unsigned char*)p, Count);
480  free(p);
481 
482  p = Content.data();
483  QFile File(QucsSettings.QucsHomeDir.absPath() +
484  QDir::convertSeparators("/user_lib/") + QString(p));
485  if(File.exists()) {
486  MsgText->append(tr("ERROR: User library \"%1\" already exists!").arg(QString(p)));
487  return -1;
488  }
489 
490  if(!File.open(QIODevice::WriteOnly)) {
491  MsgText->append(tr("ERROR: Cannot create library \"%1\"!").arg(QString(p)));
492  return -1;
493  }
494 
495  File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
496  File.close();
497  MsgText->append(tr("Create library \"%1\"").arg(QString(p)));
498  return 1;
499 }
#define CODE_DIR
QTextEdit * MsgText
Definition: packagedialog.h:63
QLineEdit * NameEdit
Definition: packagedialog.h:62
#define CODE_DIR_END
tQucsSettings QucsSettings
Definition: main.cpp:52
int extractDirectory(QFile &, Q_UINT32, QDir &)
bool checkVersion(QString &Line)
Definition: main.cpp:602
QVBoxLayout * all
Definition: packagedialog.h:61
QList< QCheckBox * > BoxList
Definition: packagedialog.h:66
Definitions and declarations for the main application.
QPushButton * ButtClose
Definition: packagedialog.h:67
QString lastDir
Definition: main.cpp:55
#define HEADER_LENGTH
QGroupBox * Group
Definition: packagedialog.h:65
int extractFile(QFile &, Q_UINT32, QDir &)
QCheckBox * LibraryCheck
Definition: packagedialog.h:64
QDir QucsHomeDir
Definition: main.h:66
int extractLibrary(QFile &, Q_UINT32)
#define CODE_FILE
int insertLibraries(QDataStream &)
#define CODE_LIBRARY
int insertFile(const QString &, QFile &, QDataStream &)
int insertDirectory(const QString &, QDataStream &)
PackageDialog(QWidget *, bool)