PageRenderTime 2760ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/doc/project_plan/tools/qucs-code/qucs/qucs/dialogs/packagedialog.cpp

https://bitbucket.org/JonSRomero/arduino_motorcycle_gauges
C++ | 474 lines | 359 code | 75 blank | 40 comment | 54 complexity | 2e5825f1c92f018078025934badcee00 MD5 | raw 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. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************/
  16. #ifdef HAVE_CONFIG_H
  17. # include <config.h>
  18. #endif
  19. #include <stdlib.h>
  20. #include <qhbox.h>
  21. #include <qvbox.h>
  22. #include <qlabel.h>
  23. #include <qlayout.h>
  24. #include <qlineedit.h>
  25. #include <qtextedit.h>
  26. #include <qcheckbox.h>
  27. #include <qfiledialog.h>
  28. #include <qmessagebox.h>
  29. #include <qpushbutton.h>
  30. #include <qscrollview.h>
  31. #include <qdatastream.h>
  32. #include <qvbuttongroup.h>
  33. #include "packagedialog.h"
  34. #include "qucs.h"
  35. #include "main.h"
  36. #define HEADER_LENGTH 32
  37. #define CODE_ERROR 0x0000
  38. #define CODE_DIR 0x0010
  39. #define CODE_DIR_END 0x0018
  40. #define CODE_FILE 0x0020
  41. #define CODE_LIBRARY 0x0040
  42. PackageDialog::PackageDialog(QWidget *parent_, bool create_)
  43. : QDialog(parent_, 0, TRUE, Qt::WDestructiveClose)
  44. {
  45. all = new QVBoxLayout(this);
  46. all->setMargin(5);
  47. all->setSpacing(6);
  48. QHBox *h2 = new QHBox(this);
  49. if(create_) { // create or extract package ?
  50. setCaption(tr("Create Project Package"));
  51. QHBox *h1 = new QHBox(this);
  52. all->addWidget(h1);
  53. new QLabel(tr("Package:"), h1);
  54. NameEdit = new QLineEdit(h1);
  55. QPushButton *ButtBrowse = new QPushButton(tr("Browse"), h1);
  56. connect(ButtBrowse, SIGNAL(clicked()), SLOT(slotBrowse()));
  57. LibraryCheck = new QCheckBox(tr("include user libraries"), this);
  58. all->addWidget(LibraryCheck);
  59. Group = new QVButtonGroup(tr("Choose projects:"), this);
  60. all->addWidget(Group);
  61. QScrollView *Dia_Scroll = new QScrollView(Group);
  62. Dia_Scroll->setMargin(5);
  63. QVBox *Dia_Box = new QVBox(Dia_Scroll->viewport());
  64. Dia_Scroll->addChild(Dia_Box);
  65. // ...........................................................
  66. all->addWidget(h2);
  67. QPushButton *ButtCreate = new QPushButton(tr("Create"), h2);
  68. connect(ButtCreate, SIGNAL(clicked()), SLOT(slotCreate()));
  69. QPushButton *ButtCancel = new QPushButton(tr("Cancel"), h2);
  70. connect(ButtCancel, SIGNAL(clicked()), SLOT(reject()));
  71. // ...........................................................
  72. // insert all projects
  73. QStringList PrDirs = QucsHomeDir.entryList("*", QDir::Dirs, QDir::Name);
  74. QStringList::iterator it;
  75. for(it = PrDirs.begin(); it != PrDirs.end(); it++)
  76. if((*it).right(4) == "_prj") // project directories end with "_prj"
  77. BoxList.append(new QCheckBox((*it).left((*it).length()-4), Dia_Box));
  78. QColor theColor;
  79. if(BoxList.isEmpty()) {
  80. ButtCreate->setEnabled(false);
  81. theColor =
  82. (new QLabel(tr("No projects!"), Dia_Box))->paletteBackgroundColor();
  83. }
  84. else
  85. theColor = BoxList.current()->paletteBackgroundColor();
  86. Dia_Scroll->viewport()->setPaletteBackgroundColor(theColor);
  87. }
  88. else { // of "if(create_)"
  89. setCaption(tr("Extract Project Package"));
  90. MsgText = new QTextEdit(this);
  91. MsgText->setTextFormat(Qt::PlainText);
  92. MsgText->setWordWrap(QTextEdit::NoWrap);
  93. MsgText->setReadOnly(true);
  94. all->addWidget(MsgText);
  95. all->addWidget(h2);
  96. h2->setStretchFactor(new QWidget(h2), 5); // stretchable placeholder
  97. ButtClose = new QPushButton(tr("Close"), h2);
  98. ButtClose->setDisabled(true);
  99. connect(ButtClose, SIGNAL(clicked()), SLOT(accept()));
  100. resize(400, 250);
  101. }
  102. }
  103. PackageDialog::~PackageDialog()
  104. {
  105. delete all;
  106. }
  107. // ---------------------------------------------------------------
  108. void PackageDialog::slotBrowse()
  109. {
  110. QString s = QFileDialog::getSaveFileName(
  111. lastDir.isEmpty() ? QString(".") : lastDir,
  112. tr("Qucs Packages")+" (*.qucs);;"+
  113. tr("Any File")+" (*)",
  114. this, 0, tr("Enter a Package File Name"));
  115. if(s.isEmpty()) return;
  116. QFileInfo Info(s);
  117. lastDir = Info.dirPath(true); // remember last directory
  118. if(Info.extension().isEmpty())
  119. s += ".qucs";
  120. NameEdit->setText(s);
  121. }
  122. // ***************************************************************
  123. // ***** Functions for creating package *****
  124. // ***************************************************************
  125. int PackageDialog::insertFile(const QString& FileName, QFile& File,
  126. QDataStream& Stream)
  127. {
  128. QByteArray FileContent;
  129. if(!File.open(IO_ReadOnly)) {
  130. QMessageBox::critical(this, tr("Error"),
  131. tr("Cannot open \"%1\"!").arg(FileName));
  132. return -1;
  133. }
  134. Q_ULONG Count = File.size();
  135. char *p = (char*)malloc(Count+FileName.length()+2);
  136. strcpy(p, FileName.latin1());
  137. File.readBlock(p+FileName.length()+1, Count);
  138. File.close();
  139. Count += FileName.length()+1;
  140. FileContent = qCompress((unsigned char*)p, Count);
  141. free(p);
  142. Stream.writeBytes(FileContent.data(), FileContent.size());
  143. return 0;
  144. }
  145. // ---------------------------------------------------------------
  146. int PackageDialog::insertDirectory(const QString& DirName,
  147. QDataStream& Stream)
  148. {
  149. QFile File;
  150. QDir myDir(DirName);
  151. // Put all files of this directory into the package.
  152. QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
  153. QStringList::iterator it;
  154. for(it = Entries.begin(); it != Entries.end(); ++it) {
  155. File.setName(myDir.absFilePath(*it));
  156. Stream << Q_UINT32(CODE_FILE);
  157. if(insertFile(*it, File, Stream) < 0)
  158. return -1;
  159. }
  160. // Put all subdirectories into the package.
  161. Entries = myDir.entryList("*", QDir::Dirs, QDir::Name);
  162. Entries.pop_front(); // delete "." from list
  163. Entries.pop_front(); // delete ".." from list
  164. for(it = Entries.begin(); it != Entries.end(); ++it) {
  165. Stream << Q_UINT32(CODE_DIR) << (*it).latin1();
  166. if(insertDirectory(myDir.absPath()+QDir::separator()+(*it), Stream) < 0)
  167. return -1;
  168. Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
  169. }
  170. return 0;
  171. }
  172. // ---------------------------------------------------------------
  173. int PackageDialog::insertLibraries(QDataStream& Stream)
  174. {
  175. QFile File;
  176. QDir myDir(QucsHomeDir.absPath() + QDir::separator() + "user_lib");
  177. QStringList Entries = myDir.entryList("*", QDir::Files, QDir::Name);
  178. QStringList::iterator it;
  179. for(it = Entries.begin(); it != Entries.end(); ++it) {
  180. File.setName(myDir.absFilePath(*it));
  181. Stream << Q_UINT32(CODE_LIBRARY);
  182. if(insertFile(*it, File, Stream) < 0)
  183. return -1;
  184. }
  185. return 0;
  186. }
  187. // ---------------------------------------------------------------
  188. void PackageDialog::slotCreate()
  189. {
  190. if(NameEdit->text().isEmpty()) {
  191. QMessageBox::critical(this, tr("Error"), tr("Please insert a package name!"));
  192. return;
  193. }
  194. QCheckBox *p;
  195. if(!LibraryCheck->isChecked()) {
  196. int count=0;
  197. for(p = BoxList.first(); p != 0; p = BoxList.next())
  198. if(p->isChecked())
  199. count++;
  200. if(count < 1) {
  201. QMessageBox::critical(this, tr("Error"), tr("Please choose at least one project!"));
  202. return;
  203. }
  204. }
  205. QString s(NameEdit->text());
  206. QFileInfo Info(s);
  207. if(Info.extension().isEmpty())
  208. s += ".qucs";
  209. NameEdit->setText(s);
  210. QFile PkgFile(s);
  211. if(PkgFile.exists())
  212. if(QMessageBox::information(this, tr("Info"),
  213. tr("Output file already exists!")+"\n"+tr("Overwrite it?"),
  214. tr("&Yes"), tr("&No"), 0,1,1))
  215. return;
  216. if(!PkgFile.open(IO_ReadWrite)) {
  217. QMessageBox::critical(this, tr("Error"), tr("Cannot create package!"));
  218. return;
  219. }
  220. QDataStream Stream(&PkgFile);
  221. // First write header.
  222. char Header[HEADER_LENGTH];
  223. memset(Header, 0, HEADER_LENGTH);
  224. strcpy(Header, "Qucs package " PACKAGE_VERSION);
  225. PkgFile.writeBlock(Header, HEADER_LENGTH);
  226. // Write project files to package.
  227. for(p = BoxList.first(); p != 0; p = BoxList.next())
  228. if(p->isChecked()) {
  229. s = p->text() + "_prj";
  230. Stream << Q_UINT32(CODE_DIR) << s.latin1();
  231. s = QucsHomeDir.absPath() + QDir::separator() + s;
  232. if(insertDirectory(s, Stream) < 0) {
  233. PkgFile.close();
  234. PkgFile.remove();
  235. return;
  236. }
  237. Stream << Q_UINT32(CODE_DIR_END) << Q_UINT32(0);
  238. }
  239. // Write user libraries to package if desired.
  240. if(LibraryCheck->isChecked())
  241. if(insertLibraries(Stream) < 0) {
  242. PkgFile.close();
  243. PkgFile.remove();
  244. return;
  245. }
  246. // Calculate checksum and write it to package file.
  247. PkgFile.at(0);
  248. QByteArray Content = PkgFile.readAll();
  249. Q_UINT16 Checksum = qChecksum(Content.data(), Content.size());
  250. PkgFile.at(HEADER_LENGTH-sizeof(Q_UINT16));
  251. Stream << Checksum;
  252. PkgFile.close();
  253. QMessageBox::information(this, tr("Info"),
  254. tr("Successfully created Qucs package!"));
  255. accept();
  256. }
  257. // ***************************************************************
  258. // ***** Functions for extracting package *****
  259. // ***************************************************************
  260. void PackageDialog::extractPackage()
  261. {
  262. QString s = QFileDialog::getOpenFileName(
  263. lastDir.isEmpty() ? QString(".") : lastDir,
  264. tr("Qucs Packages")+" (*.qucs);;"+
  265. tr("Any File")+" (*)",
  266. this, 0, tr("Enter a Package File Name"));
  267. if(s.isEmpty()) {
  268. reject();
  269. return;
  270. }
  271. QFileInfo Info(s);
  272. lastDir = Info.dirPath(true); // remember last directory
  273. QFile PkgFile(s);
  274. if(!PkgFile.open(IO_ReadOnly)) {
  275. if(Info.extension().isEmpty()) s += ".qucs";
  276. PkgFile.setName(s);
  277. if(!PkgFile.open(IO_ReadOnly)) {
  278. MsgText->append(tr("ERROR: Cannot open package!"));
  279. ButtClose->setDisabled(false);
  280. return;
  281. }
  282. }
  283. QDataStream Stream(&PkgFile);
  284. QDir currDir = QucsHomeDir;
  285. QString Version;
  286. Q_UINT16 Checksum;
  287. Q_UINT32 Code, Length;
  288. // First read and check header.
  289. QByteArray Content = PkgFile.readAll();
  290. if(strncmp(Content.data(), "Qucs package ", 13) != 0) {
  291. MsgText->append(tr("ERROR: File contains wrong header!"));
  292. goto ErrorEnd;
  293. }
  294. Version = QString(Content.data()+13);
  295. if(!checkVersion(Version)) {
  296. MsgText->append(tr("ERROR: Wrong version number!"));
  297. goto ErrorEnd;
  298. }
  299. // checksum correct ?
  300. PkgFile.at(HEADER_LENGTH-2);
  301. Stream >> Checksum;
  302. *((Q_UINT16*)(Content.data()+HEADER_LENGTH-2)) = 0;
  303. if(Checksum != qChecksum(Content.data(), Content.size())) {
  304. MsgText->append(tr("ERROR: Checksum mismatch!"));
  305. goto ErrorEnd;
  306. }
  307. Content.resize(0); // dispose memory
  308. // work on all files and directories in the package
  309. for(;;) {
  310. if(PkgFile.atEnd()) break;
  311. Stream >> Code >> Length;
  312. switch(Code) {
  313. case CODE_DIR:
  314. if(extractDirectory(PkgFile, Length, currDir) > 0)
  315. break;
  316. goto ErrorEnd;
  317. case CODE_DIR_END:
  318. MsgText->append(tr("Leave directory \"%1\"").arg(currDir.absPath()));
  319. currDir.cdUp();
  320. break;
  321. case CODE_FILE:
  322. if(extractFile(PkgFile, Length, currDir) > 0)
  323. break;
  324. goto ErrorEnd;
  325. case CODE_LIBRARY:
  326. if(extractLibrary(PkgFile, Length) > 0)
  327. break;
  328. goto ErrorEnd;
  329. default:
  330. MsgText->append(tr("ERROR: Package is corrupt!"));
  331. goto ErrorEnd;
  332. }
  333. }
  334. MsgText->append(" ");
  335. MsgText->append(tr("Successfully extracted package!"));
  336. ErrorEnd:
  337. MsgText->append(" ");
  338. ButtClose->setDisabled(false);
  339. PkgFile.close();
  340. }
  341. // ---------------------------------------------------------------
  342. int PackageDialog::extractDirectory(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
  343. {
  344. char *p = (char*)malloc(Count);
  345. PkgFile.readBlock(p, Count);
  346. if(currDir.cd(QString(p))) { // directory exists ?
  347. MsgText->append(tr("ERROR: Project directory \"%1\" already exists!").arg(QString(p)));
  348. return -1;
  349. }
  350. if(!currDir.mkdir(QString(p))) {
  351. MsgText->append(tr("ERROR: Cannot create directory \"%1\"!").arg(QString(p)));
  352. return -2;
  353. }
  354. currDir.cd(QString(p));
  355. MsgText->append(tr("Create and enter directory \"%1\"").arg(currDir.absPath()));
  356. free(p);
  357. return 1;
  358. }
  359. // ---------------------------------------------------------------
  360. int PackageDialog::extractFile(QFile& PkgFile, Q_UINT32 Count, QDir& currDir)
  361. {
  362. char *p = (char*)malloc(Count);
  363. PkgFile.readBlock(p, Count);
  364. QByteArray Content = qUncompress((unsigned char*)p, Count);
  365. free(p);
  366. p = Content.data();
  367. QFile File(currDir.absFilePath(QString(p)));
  368. if(!File.open(IO_WriteOnly)) {
  369. MsgText->append(tr("ERROR: Cannot create file \"%1\"!").arg(QString(p)));
  370. return -1;
  371. }
  372. File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
  373. File.close();
  374. MsgText->append(tr("Create file \"%1\"").arg(QString(p)));
  375. return 1;
  376. }
  377. // ---------------------------------------------------------------
  378. int PackageDialog::extractLibrary(QFile& PkgFile, Q_UINT32 Count)
  379. {
  380. char *p = (char*)malloc(Count);
  381. PkgFile.readBlock(p, Count);
  382. QByteArray Content = qUncompress((unsigned char*)p, Count);
  383. free(p);
  384. p = Content.data();
  385. QFile File(QucsHomeDir.absPath() +
  386. QDir::convertSeparators("/user_lib/") + QString(p));
  387. if(File.exists()) {
  388. MsgText->append(tr("ERROR: User library \"%1\" already exists!").arg(QString(p)));
  389. return -1;
  390. }
  391. if(!File.open(IO_WriteOnly)) {
  392. MsgText->append(tr("ERROR: Cannot create library \"%1\"!").arg(QString(p)));
  393. return -1;
  394. }
  395. File.writeBlock(p+strlen(p)+1, Content.size()-strlen(p)-1);
  396. File.close();
  397. MsgText->append(tr("Create library \"%1\"").arg(QString(p)));
  398. return 1;
  399. }