HAL
import_project_dialog.cpp
Go to the documentation of this file.
5 #include <QRegularExpression>
6 #include <QGridLayout>
7 #include <QVBoxLayout>
8 #include <QFileDialog>
9 #include <QLabel>
10 #include <QUuid>
11 #include <QMessageBox>
12 #include <JlCompress.h>
13 
14 namespace hal {
15  FileSelectWidget::FileSelectWidget(const QString &defaultEntry, bool existingDir, QWidget* parent)
16  : QFrame(parent), mExistingDir(existingDir), mValid(false)
17  {
18  setMaximumHeight(48);
20  setLineWidth(3);
22 
23  QGridLayout* layout = new QGridLayout(this);
24  mEditor = new QLineEdit(this);
26  mEditor->setMinimumWidth(320);
27  mEditor->setText(defaultEntry);
28  connect(mEditor,&QLineEdit::textChanged,this,&FileSelectWidget::handleTextChanged);
29  layout->addWidget(mEditor,0,0);
30 
31  mButton = new QPushButton(gui_utility::getStyledSvgIcon("all->#3192C5",":/icons/folder"),"",this);
33  connect(mButton,&QPushButton::clicked,this,&FileSelectWidget::handleActivateFileDialog);
34  layout->addWidget(mButton,0,1);
35  handleTextChanged(defaultEntry);
36  }
37 
38  void FileSelectWidget::handleActivateFileDialog()
39  {
40  QString entry = mExistingDir
41  ? QFileDialog::getExistingDirectory(this, "Select directory:", mEditor->text())
42  : QFileDialog::getOpenFileName(this, "Select file:", mEditor->text(), "Zipped files (*.zip)");
43  mEditor->setText(entry);
44  }
45 
46  void FileSelectWidget::handleTextChanged(const QString &txt)
47  {
48  bool val = !txt.isEmpty();
49  if (val) val = QFileInfo(txt).exists();
50  if (val == mValid) return;
51  mValid = val;
53  }
54 
56  : QDialog(parent), mStatus(NoImport)
57  {
58  setWindowTitle("Import Project");
59  QVBoxLayout* layout = new QVBoxLayout(this);
60  layout->addWidget(new QLabel("Zipped HAL project file:",this));
61  mZippedFile = new FileSelectWidget("", false, this);
62  connect(mZippedFile,&FileSelectWidget::selectionStatusChanged, this, &ImportProjectDialog::handleSelectionStatusChanged);
63  layout->addWidget(mZippedFile);
64 
65  layout->addStretch();
66 
67  layout->addWidget(new QLabel("Decompress in directory:",this));
68  mTargetDirectory = new FileSelectWidget(QDir::currentPath(), true, this);
69  connect(mTargetDirectory,&FileSelectWidget::selectionStatusChanged, this, &ImportProjectDialog::handleSelectionStatusChanged);
70  layout->addWidget(mTargetDirectory);
71 
72  layout->addStretch();
73 
74  layout->addWidget(new QLabel("Decompressed HAL project name:"));
75  mExtractProjectEdit = new QLineEdit(this);
76  layout->addWidget(mExtractProjectEdit);
77 
78  layout->addStretch();
79 
83  layout->addWidget(mButtonBox);
84  handleSelectionStatusChanged();
85  }
86 
87  void ImportProjectDialog::handleSelectionStatusChanged()
88  {
89  bool valid = mTargetDirectory->valid() && mZippedFile->valid();
90  if (valid)
91  {
92  QRegularExpression reProj("(.*)/\\.project.json$");
93  QStringList zipFlist = JlCompress::getFileList(mZippedFile->selection());
94  int inx = zipFlist.indexOf(reProj);
95  if (inx < 0)
96  {
97  QMessageBox::warning(this,"Invalid ZIP-file", "The zipped file " + mZippedFile->selection() + " does not seem to be a hal project.\n");
98  valid = false;
99  }
100  else
101  {
102  QRegularExpressionMatch match = reProj.match(zipFlist.at(inx));
103  mTargetProjectName = match.captured(1);
104  QString suggestedDir = suggestedProjectDir(QDir(mTargetDirectory->selection()).absoluteFilePath(mTargetProjectName));
105  mExtractProjectEdit->setText(QFileInfo(suggestedDir).fileName());
106  }
107  }
108  mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
109  }
110 
112  {
113  mStatus = NoFileSelected;
114  if (mZippedFile->selection().isEmpty()) return false;
115 
116  mExtractedProjectAbsolutePath = QDir(mTargetDirectory->selection()).absoluteFilePath(mExtractProjectEdit->text());
117  if (QFileInfo(mExtractedProjectAbsolutePath).exists())
118  {
119  QMessageBox::warning(this, "Cannot Create Project", "Direcotry " + mExtractedProjectAbsolutePath + " already exists");
120  return false;
121  }
122  QStringList extracted;
123  QString tempdir;
124  if (mExtractProjectEdit->text() != mTargetProjectName)
125  {
126  tempdir = QDir(mTargetDirectory->selection()).absoluteFilePath("hal_temp_" + QUuid::createUuid().toString(QUuid::WithoutBraces));
127  QDir().mkpath(tempdir);
128  extracted = JlCompress::extractDir(mZippedFile->selection(),tempdir);
129  }
130  else
131  {
132  extracted = JlCompress::extractDir(mZippedFile->selection(),mTargetDirectory->selection());
133  }
134  mStatus = ErrorDecompress;
135  if (extracted.isEmpty()) return false;
136 
137  QString extractedDir = extracted.at(0);
138  while (extractedDir.back().unicode() == '/' || extractedDir.back().unicode() == '\\')
139  extractedDir.chop(1);
140 
141  switch (FileManager::directoryStatus(extractedDir))
142  {
144  mStatus = Ok;
145  break;
147  log_warning("gui", "No hal project file found in '{}' archive.", mZippedFile->selection().toStdString());
148  mStatus = NotAHalProject;
149  break;
150  case FileManager::IsFile:
151  log_warning("gui", "Archive '{}' contains single file, not a hal project directory.", mZippedFile->selection().toStdString());
152  mStatus = NotAHalProject;
153  break;
155  log_warning("gui", "Failed to decompress archive '{}', extracted HAL directory not found.", mZippedFile->selection().toStdString());
156  mStatus = NotAHalProject;
157  break;
159  log_warning("gui", "HAL directory extracted from archive '{}' must not have an extension.", mZippedFile->selection().toStdString());
160  mStatus = NotAHalProject;
161  break;
163  log_warning("gui", "Failed to parse HAL project file from archive '{}'.", mZippedFile->selection().toStdString());
164  mStatus = NotAHalProject;
165  break;
167  log_warning("gui", "Failed to find netlist in archiv '{}'.", mZippedFile->selection().toStdString());
168  mStatus = NotAHalProject;
169  break;
171  log_warning("gui", "Failed to find gate library in archiv '{}'.", mZippedFile->selection().toStdString());
172  mStatus = NotAHalProject;
173  break;
175  log_warning("gui", "Failed to decompress archive '{}', result is neither a file nor a directory.", mZippedFile->selection().toStdString());
176  mStatus = NotAHalProject;
177  break;
178  }
179 
180  if (!tempdir.isEmpty())
181  {
182  if (!QFile::rename(extractedDir,mExtractedProjectAbsolutePath))
183  {
184  log_warning("gui", "Failed to move decompressed archive to new location '{}'.", mExtractedProjectAbsolutePath.toStdString());
185  mStatus = ErrorDecompress;
186  }
187  else
188  {
189  // delete everything left in tempdir after moving project to project dir
190  deleteFilesRecursion(tempdir);
191  }
192  }
193 
194  if (mStatus != Ok)
195  {
196  // Not a hal project, delete all extracted
197  deleteFilesList(extracted);
198  return false;
199  }
200 
201  return true;
202  }
203 
204  void ImportProjectDialog::deleteFilesRecursion(QString dir)
205  {
206  for (QFileInfo finfo : QDir(dir).entryInfoList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot))
207  {
208  if (finfo.isDir())
209  deleteFilesRecursion(finfo.absoluteFilePath());
210  else
211  QFile::remove(finfo.absoluteFilePath());
212  }
213  QDir().rmdir(dir);
214  }
215 
216  void ImportProjectDialog::deleteFilesList(QStringList files)
217  {
218  // Delete files, keep directories (might be not empty)
219  auto it = files.begin();
220  while (it != files.end())
221  if (QFileInfo(*it).isDir())
222  ++it;
223  else
224  {
225  QFile::remove(*it);
226  it = files.erase(it);
227  }
228 
229  // Delete directories in revers order
230  if (!files.isEmpty())
231  {
232  for (;;)
233  {
234  --it;
235  QFile::remove(*it);
236  if (it == files.begin())
237  break;
238  }
239  }
240  }
241 
243  {
244  QString retval = filename;
245  retval.remove(QRegularExpression("\\.\\w*$"));
246 
247  QString basedir = retval;
248  int count = 2;
249 
250  for (;;) // loop until non existing directory found
251  {
252  if (!QFileInfo(retval).exists())
253  return retval;
254  retval = QString("%1_%2").arg(basedir).arg(count++);
255  }
256  return retval;
257  }
258 }
Copyright The Montserrat Project in Original or Modified may be sold by itself Original or Modified Versions of the Font Software may be redistributed and or sold with any provided that each copy contains the above copyright notice and this license These can be included either as stand alone text files
Definition: OFL.txt:59
static DirectoryStatus directoryStatus(const QString &pathname)
FileSelectWidget(const QString &defaultEntry, bool existingDir, QWidget *parent=nullptr)
static QString suggestedProjectDir(const QString &filename)
ImportProjectDialog(QWidget *parent=nullptr)
#define log_warning(channel,...)
Definition: log.h:76
QIcon getStyledSvgIcon(const QString &from_to_colors_enabled, const QString &svg_path, QString from_to_colors_disabled=QString())
Definition: graphics.cpp:60
void clicked(bool checked)
ushort unicode() const const
virtual void accept()
virtual void reject()
QPushButton * button(QDialogButtonBox::StandardButton which) const const
QString absoluteFilePath(const QString &fileName) const const
QString currentPath()
bool mkpath(const QString &dirPath) const const
bool rmdir(const QString &dirName) const const
bool remove()
bool rename(const QString &newName)
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options)
bool exists() const const
bool isDir() const const
void setLineWidth(int)
void setFrameStyle(int style)
void addWidget(QWidget *w)
void setText(const QString &)
void textChanged(const QString &text)
const T & at(int i) const const
bool isEmpty() const const
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString captured(int nth) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QChar back() const const
void chop(int n)
bool isEmpty() const const
QString & remove(int position, int n)
std::string toStdString() const const
int indexOf(QStringView str, int from) const const
QUuid createUuid()
void setEnabled(bool)
QLayout * layout() const const
void setMaximumHeight(int maxh)
void setMinimumWidth(int minw)
void setSizePolicy(QSizePolicy)
void setWindowTitle(const QString &)