HAL  v4.5.0-236-gacaa6651c
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
file_manager.cpp
Go to the documentation of this file.
2 
3 #include "gui/gui_globals.h"
10 #include "hal_core/utilities/log.h"
19 
20 #include <QDateTime>
21 #include <QFile>
22 #include <QFileInfo>
23 #include <QFileSystemWatcher>
24 #include <QGridLayout>
25 #include <QInputDialog>
26 #include <QMessageBox>
27 #include <QPushButton>
28 #include <QSpacerItem>
29 #include <QTextStream>
30 #include <QApplication>
31 #include <QDir>
32 #include <QRegularExpression>
33 #include <QDebug>
34 #include <QJsonDocument>
35 #include <QJsonObject>
36 
37 namespace hal
38 {
39  FileManager::FileManager(QObject* parent) : QObject(parent), mFileWatcher(new QFileSystemWatcher(this)), mFileOpen(false)
40  {
41  mSettingAutosave = new SettingsItemCheckbox(
42  "Autosave",
43  "advanced/autosave",
44  true,
45  "eXpert Settings:Autosave",
46  "Specifies wheather HAL should autosave."
47  );
48 
49  mSettingAutosaveInterval = new SettingsItemSpinbox(
50  "Autosave Interval",
51  "advanced/autosave_interval",
52  30,
53  "eXpert Settings:Autosave",
54  "Sets after how much time in seconds an autosave will occur."
55  );
56 
57  mAutosaveEnabled = mSettingAutosave->value().toBool();
58  mAutosaveInterval = mSettingAutosaveInterval->value().toInt();
59 
60  if (mAutosaveInterval < 30) // failsafe in case somebody sets "0" in the .ini
61  mAutosaveInterval = 30;
62 
63  connect(mSettingAutosave, &SettingsItemCheckbox::boolChanged, this, [this](bool value){
64  mAutosaveEnabled = value;
65  if (mTimer->isActive())
66  mTimer->start(mAutosaveInterval * 1000);
67  });
68 
69  connect(mSettingAutosaveInterval, &SettingsItemSpinbox::intChanged, this, [this](int value){
70  mAutosaveInterval = value;
71  if (mTimer->isActive())
72  mTimer->start(mAutosaveInterval * 1000);
73  });
74 
75  connect(mFileWatcher, &QFileSystemWatcher::fileChanged, this, &FileManager::handleFileChanged);
76  connect(mFileWatcher, &QFileSystemWatcher::directoryChanged, this, &FileManager::handleDirectoryChanged);
77  mTimer = new QTimer(this);
78  connect(mTimer, &QTimer::timeout, this, &FileManager::autosave);
79  }
80 
81  FileManager* FileManager::get_instance()
82  {
83  static FileManager manager;
84  return &manager;
85  }
86 
87  bool FileManager::fileOpen() const
88  {
89  return mFileOpen;
90  }
91 
92  void FileManager::autosave()
93  {
95  if (pm->get_project_status() != ProjectManager::ProjectStatus::NONE && mAutosaveEnabled)
96  {
98  {
99  log_info("gui", "Autosave deferred while python script is running...");
100  return;
101  }
102  log_info("gui", "saving a backup in case something goes wrong...");
103  if (!ProjectManager::instance()->serialize_project(gNetlist, true))
104  log_warning("gui", "Autosave failed to create project backup to directory '{}'.", pm->get_project_directory().get_shadow_dir().string());
105  }
106  }
107 
108  QString FileManager::fileName() const
109  {
110  if (mFileOpen)
111  return mFileName;
112 
113  return QString();
114  }
115 
116  void FileManager::watchFile(const QString& fileName)
117  {
118  if (fileName == mFileName)
119  {
120  return;
121  }
122 
123  if (!mFileName.isEmpty())
124  {
125  mFileWatcher->removePath(mFileName);
126  removeShadowDirectory();
127  }
128 
129  mTimer->stop();
130 
131  if (!fileName.isEmpty())
132  {
133  log_info("gui", "watching current file '{}'", fileName.toStdString());
134 
135  // autosave periodically
136  // (we also start the timer if autosave is disabled since it's way
137  // easier to just do nothing when the timer fires instead of messing
138  // with complicated start/stop conditions)
139  mTimer->start(mAutosaveInterval * 1000);
140 
141  mFileName = fileName;
142  mFileWatcher->addPath(mFileName);
143  mFileOpen = true;
144  updateRecentFiles(mFileName);
145  }
146  }
147 
148  void FileManager::emitProjectSaved(QString& projectDir, QString& file)
149  {
150  Q_EMIT projectSaved(projectDir, file);
151  }
152 
153  void FileManager::projectSuccessfullyLoaded(QString& projectDir, QString& file)
154  {
155  watchFile(file);
156  Q_EMIT projectOpened(projectDir, file);
159  ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::OPENED);
160  }
161 
162 
163  FileManager::DirectoryStatus FileManager::directoryStatus(const QString& pathname)
164  {
165  QFileInfo info(pathname);
166  if (!info.exists()) return NotExisting;
167 
168  if (info.isFile())
169  {
171  return IsFile;
172  else
173  return InvalidExtension;
174  }
175 
176  if (info.isDir())
177  {
178  if (!info.suffix().isEmpty()) return InvalidExtension;
179  QFile ff(QDir(pathname).absoluteFilePath(QString::fromStdString(ProjectManager::s_project_file)));
180  if (ff.exists())
181  {
182  if (!ff.open(QIODevice::ReadOnly))
183  return ParseError;
184  QJsonParseError err;
185  QJsonDocument doc = QJsonDocument::fromJson(ff.readAll(),&err);
186  if (err.error != QJsonParseError::NoError)
187  return ParseError;
188  if (!doc.isObject())
189  return ParseError;
190  if (!doc.object().contains("netlist"))
191  return NetlistError;
192  QString nl = doc.object()["netlist"].toString();
193  if (nl.isEmpty()) return NetlistError;
194  if (QFileInfo(nl).isAbsolute())
195  {
196  if (!QFileInfo(nl).exists())
197  return NetlistError;
198  }
199  else
200  {
201  if (!QFileInfo(QDir(pathname).absoluteFilePath(nl)).exists())
202  return NetlistError;
203  }
204  QString gl = doc.object()["gate_library"].toString();
205  if (gl.isEmpty()) return GatelibError;
206  if (QFileInfo(gl).isAbsolute())
207  {
208  if (!QFileInfo(gl).exists())
209  return GatelibError;
210  }
211  else
212  {
213  if (!QFileInfo(QDir(pathname).absoluteFilePath(gl)).exists())
214  return GatelibError;
215  }
216  return ProjectDirectory;
217  }
218  else
219  return OtherDirectory;
220  }
221 
222  return UnknownDirectoryEntry;
223  }
224 
225  QString FileManager::directoryStatusText(DirectoryStatus stat)
226  {
227  switch (stat)
228  {
229  case ProjectDirectory:
230  return QString("seems to be a HAL project");
231  case OtherDirectory:
232  return QString("no HAL project file found in current directory");
233  case IsFile:
234  return QString("entry is not a directory but a file");
235  case NotExisting:
236  return QString("directory does not exist");
237  case InvalidExtension:
238  return QString("HAL project directory must not have an extension");
239  case ParseError:
240  return QString("HAL project file parse error");
241  case NetlistError:
242  return QString("cannot find HAL netlist");
243  case GatelibError:
244  return QString("cannot find HAL gate library");
245  case UnknownDirectoryEntry:
246  return QString("entry is neither directory nor file");
247  }
248 
249  return QString();
250  }
251 
252  void FileManager::fileSuccessfullyLoaded(QString file)
253  {
254  watchFile(file);
255  Q_EMIT fileOpened(file);
256  ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::OPENED);
257  }
258 
259  void FileManager::removeShadowDirectory()
260  {
261  ProjectManager* pm = ProjectManager::instance();
262  if (pm->get_project_status() == ProjectManager::ProjectStatus::NONE) return;
263  QDir shDir(QString::fromStdString(pm->get_project_directory().get_shadow_dir()));
264  if (shDir.exists())
265  {
266  shDir.removeRecursively();
267  QDir().mkpath(shDir.absolutePath());
268  }
269 
270  }
271 
272  void FileManager::newProject()
273  {
274  NewProjectDialog npr(qApp->activeWindow());
275  if (npr.exec() != QDialog::Accepted) return;
276 
277  QString projdir = npr.projectDirectory();
278  if (projdir.isEmpty()) return;
279 
280  QString gatelib = npr.gateLibraryPath();
281  if (gatelib.isEmpty())
282  {
283  QMessageBox::warning(qApp->activeWindow(),"Aborted", "Cannot create project <" + projdir + ">, no gate library selected");
284  return;
285  }
286  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,"."+QFileInfo(gatelib).suffix());
287  GateLibrary* glib = loadGateLibrary(gatelib);
288  if (!glib)
289  {
290  QMessageBox::warning(qApp->activeWindow(),"Aborted", "Cannot create project <" + projdir + ">, cannot load gate library <" + gatelib + ">");
291  return;
292  }
293 
295  if (!pm->create_project_directory(projdir.toStdString()))
296  {
297  QMessageBox::warning(qApp->activeWindow(),"Aborted", "Error creating project directory <" + projdir + ">");
298  return;
299  }
300 
301  QDir projectDir(projdir);
302  QString netlistFilename = QString::fromStdString(pm->get_netlist_filename());
303  if (npr.isCopyGatelibChecked())
304  {
305  QFileInfo glInfo(gatelib);
306  QString targetGateLib = projectDir.absoluteFilePath(glInfo.fileName());
307  if (QFile::copy(gatelib,targetGateLib))
308  gatelib = targetGateLib;
309  }
310 
311  std::filesystem::path lpath = pm->get_project_directory().get_default_filename(".log");
312  LogManager::get_instance()->set_file_name(lpath);
313 
315  gNetlist = gNetlistOwner.get();
316 
317  if (!gNetlist)
318  {
319  QMessageBox::warning(qApp->activeWindow(),"Aborted", "Failed to create <" + projdir + "> with gate library <" + gatelib + ">");
320  return;
321  }
325  if (pm->serialize_project(gNetlist))
327  projectSuccessfullyLoaded(projdir,netlistFilename);
328  log_info("gui", "Created empty project '{}' with gate library '{}'.", projdir.toStdString(), gatelib.toStdString());
329  }
330 
331  void FileManager::importFile(QString filename)
332  {
333  // check whether there is already a project with the same name as file-to-be-imported
334  QString testProjectExists(filename);
335  testProjectExists.remove(QRegularExpression("\\.\\w*$"));
336  if (directoryStatus(testProjectExists) == FileManager::ProjectDirectory)
337  {
338  QMessageBox msgBox;
340  msgBox.setWindowTitle("Resume previous work");
341  msgBox.setText("A hal project exists for the selected netlist.");
342  auto butLoadProject = msgBox.addButton("Load hal project", QMessageBox::ActionRole);
343  auto butImportNetlist = msgBox.addButton("Parse " + QFileInfo(filename).suffix() + " file", QMessageBox::ActionRole);
344  msgBox.addButton("Abort", QMessageBox::RejectRole);
345 
346  QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
347  QGridLayout* layout = (QGridLayout*)msgBox.layout();
348  layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
349 
350  msgBox.exec();
351 
352  if (msgBox.clickedButton() == (QAbstractButton*)butLoadProject)
353  {
354  openProject(testProjectExists);
355  return;
356  }
357  else if (msgBox.clickedButton() != (QAbstractButton*)butImportNetlist)
358  {
359  return;
360  }
361  }
362 
363  for (;;) // loop upon wrong suffix or upon error creating project directory
364  {
365  ImportNetlistDialog ind(filename, qApp->activeWindow());
366  if (ind.exec() != QDialog::Accepted) return;
367  QString projdir = ind.projectDirectory();
368  if (projdir.isEmpty()) return;
369 
370  if (!QFileInfo(projdir).suffix().isEmpty())
371  {
372  QMessageBox::warning(qApp->activeWindow(),"Aborted", "selected project directory name must not have suffix ." + QFileInfo(projdir).suffix());
373  continue;
374  }
375 
377  if (!pm->create_project_directory(projdir.toStdString()))
378  {
379  QMessageBox::warning(qApp->activeWindow(),"Aborted", "Error creating project directory <" + projdir +
380  ">\nYou might want to try a different name or location");
381  continue;
382  }
383 
384  QDir projectDir(projdir);
385  QString netlistFilename = filename;
386  if (ind.isMoveNetlistChecked())
387  {
388  netlistFilename = projectDir.absoluteFilePath(QFileInfo(filename).fileName());
389  QDir().rename(filename,netlistFilename);
390  }
391 
392  QString gatelib = ind.gateLibraryPath();
393  if (ind.isCopyGatelibChecked() && !gatelib.isEmpty())
394  {
395  QFileInfo glInfo(gatelib);
396  QString targetGateLib = projectDir.absoluteFilePath(glInfo.fileName());
397  if (QFile::copy(gatelib,targetGateLib))
398  gatelib = targetGateLib;
399  }
400 
401  std::filesystem::path lpath = pm->get_project_directory().get_default_filename(".log");
402  LogManager::get_instance()->set_file_name(lpath);
403 
404  if (deprecatedOpenFile(netlistFilename, gatelib))
405  {
407  if (gNetlist)
408  if (pm->serialize_project(gNetlist))
410  Q_EMIT projectOpened(projectDir.absolutePath(),QString::fromStdString(pm->get_netlist_filename()));
411  }
412  else
413  {
414  // failed to create project: if netlist was moved move back before deleting directory
415  if (ind.isMoveNetlistChecked())
416  QDir().rename(netlistFilename,filename);
417  if (pm->remove_project_directory())
418  log_info("gui", "Project directory removed since import failed.");
419  else
420  log_warning("gui", "Failed to remove project directory after failed import attempt");
421  }
422 
423  return; // break loop
424  }
425  }
426 
427  void FileManager::moveShadowToProject(const QDir& shDir) const
428  {
429  QString replaceToken = "/" + QString::fromStdString(ProjectDirectory::s_shadow_dir) + "/";
431  {
432  QString targetPath(finfo.absoluteFilePath());
433  targetPath.replace(replaceToken,"/");
434 
435  if (finfo.isDir())
436  {
437  QDir().mkpath(targetPath);
438  moveShadowToProject(QDir(finfo.absoluteFilePath()));
439  }
440  else if (finfo.isFile())
441  {
442  if (QFileInfo(targetPath).exists()) QFile::remove(targetPath);
443  QFile::copy(finfo.absoluteFilePath(),targetPath);
444  log_info("gui", "File restored from autosave: {}.", targetPath.toStdString());
445  }
446  else
447  {
448  log_info("gui","Cannot move {} from autosave to project directory.", finfo.absoluteFilePath().toStdString());
449  }
450  }
451  }
452 
453  void FileManager::openProject(QString projPath)
454  {
456  pm->set_project_directory(projPath.toStdString());
457 
459  QFileInfo shInfo(shDir.absoluteFilePath(QString::fromStdString(ProjectManager::s_project_file)));
460  if (shInfo.exists() && shInfo.isFile())
461  {
462  QString message =
463  "It seems that HAL crashed during your last session. Last autosave was on " +
464  shInfo.lastModified().toString("dd.MM.yyyy hh:mm") + ". Restore that state?";
465  if (QMessageBox::question(nullptr, "HAL did not exit cleanly", message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
466  {
467  moveShadowToProject(shDir);
469  }
470  }
471 
472  ProjectJson projFile(QDir(projPath).absoluteFilePath(".project.json"));
473  QString glExtension = QFileInfo(projFile.gateLibraryFilename()).suffix();
474  if (!glExtension.isEmpty() && gPluginRelay->mGuiPluginTable)
475  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,"." +glExtension);
476 
477  // the project loads its gate library without asking, so an outdated one gets the chance to be upgraded beforehand
478  QString glPath = QDir(projPath).absoluteFilePath(projFile.gateLibraryFilename());
479  if (!projFile.gateLibraryFilename().isEmpty() && QFileInfo(glPath).isFile())
480  loadGateLibrary(glPath);
481 
482  if (!pm->open_project())
483  {
484  QString errorMsg = QString("Error opening project <%1>").arg(projPath);
485  log_error("gui", "{}", errorMsg.toStdString());
486  displayErrorMessage(errorMsg);
487  return;
488  }
489 
490  gNetlistOwner = std::move(pm->get_netlist());
491  gNetlist = gNetlistOwner.get();
493  projectSuccessfullyLoaded(projPath, filename);
496 
497  std::filesystem::path lpath = pm->get_project_directory().get_default_filename(".log");
498  LogManager::get_instance()->set_file_name(lpath);
499  }
500 
501  bool FileManager::deprecatedOpenFile(QString filename, QString gatelibraryPath)
502  {
503  QString logical_file_name = filename;
504 
505  QString glSuffix = QFileInfo(gatelibraryPath).suffix();
506  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,"."+glSuffix);
507 
508  if (gNetlist)
509  {
510  // ADD ERROR MESSAGE
511  return false;
512  }
513 
514  if (filename.isEmpty())
515  {
516  QString errorMsg("Unable to open file. File name is empty");
517  log_error("gui", "{}", errorMsg.toStdString());
518  displayErrorMessage(errorMsg);
519  return false;
520  }
521 
522  QFile file(filename);
523 
524  if (!file.open(QFile::ReadOnly))
525  {
526  std::string error_message("Unable to open file" + filename.toStdString());
527  log_error("gui", "Unable to open file '{}'", error_message);
528  displayErrorMessage(QString::fromStdString(error_message));
529  return false;
530  }
531 
532  QFileInfo nlInfo(filename);
533  if (nlInfo.suffix()=="hal")
534  {
535  QHash<int,int> errorCount;
536  for (;;) // try loading hal file until exit by return
537  {
538  // event_controls::enable_all(false); won't get events until callbacks are registered
539  auto netlist = netlist_factory::load_netlist(filename.toStdString(),gatelibraryPath.toStdString());
540  // event_controls::enable_all(true);
541  if (netlist)
542  {
543  gNetlistOwner = std::move(netlist);
544  gNetlist = gNetlistOwner.get();
546  fileSuccessfullyLoaded(logical_file_name);
548  return true;
549  }
550  else
551  {
552  std::string error_message("Failed to create netlist from .hal file");
553  log_error("gui", "{}", error_message);
554  displayErrorMessage(QString::fromStdString(error_message));
555  return false;
556  }
557  }
558  }
559  else
560  {
562  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacNetlistParser,"."+nlInfo.suffix());
563  }
564 
565  if (!gatelibraryPath.isEmpty())
566  {
567  log_info("gui", "Trying to use gate library {}.", gatelibraryPath.toStdString());
568  QFileInfo glInfo(gatelibraryPath);
570  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,"."+glInfo.suffix());
571 
572  // the netlist loads its gate library without asking, so an outdated one gets the chance to be upgraded beforehand
573  loadGateLibrary(gatelibraryPath);
574  auto netlist = netlist_factory::load_netlist(filename.toStdString(), gatelibraryPath.toStdString());
575 
576  if (netlist)
577  {
578  gNetlistOwner = std::move(netlist);
579  gNetlist = gNetlistOwner.get();
581  fileSuccessfullyLoaded(logical_file_name);
583  return true;
584  }
585  else
586  {
587  log_error("gui", "Failed using gate library {}.", gatelibraryPath.toStdString());
588  displayErrorMessage("Failed to open netlist\nwith user selected gate library\n"+gatelibraryPath);
589  return false;
590  }
591  }
592 
593  QString lib_file_name = filename.left(filename.lastIndexOf('.')) + ".lib";
594  if (QFileInfo::exists(lib_file_name) && QFileInfo(lib_file_name).isFile())
595  {
596  log_info("gui", "Trying to use gate library {}.", lib_file_name.toStdString());
598  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser,".lib");
599 
600  // event_controls::enable_all(false);
601  auto netlist = netlist_factory::load_netlist(filename.toStdString(), lib_file_name.toStdString());
602  // event_controls::enable_all(true);
603 
604  if (netlist)
605  {
606  gNetlistOwner = std::move(netlist);
607  gNetlist = gNetlistOwner.get();
609  fileSuccessfullyLoaded(logical_file_name);
611  return true;
612  }
613  else
614  {
615  log_error("gui", "Failed using gate library {}.", lib_file_name.toStdString());
616  }
617  }
618 
619  log_info("gui", "Searching for (other) compatible netlists.");
621  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacGatelibParser);
622 
623  // event_controls::enable_all(false);
624  std::vector<std::unique_ptr<Netlist>> netlists = netlist_factory::load_netlists(filename.toStdString());
625  // event_controls::enable_all(true);
626 
627  if (netlists.empty())
628  {
629  std::string error_message("Unable to find a compatible gate library. Deserialization failed!");
630  log_error("gui", "{}", error_message);
631  displayErrorMessage(QString::fromStdString(error_message));
632  return false;
633  }
634  else if (netlists.size() == 1)
635  {
636  log_info("gui", "One compatible gate library found.");
637  gNetlistOwner = std::move(netlists.at(0));
638  gNetlist = gNetlistOwner.get();
641  }
642  else
643  {
644  log_info("gui", "{} compatible gate libraries found. User has to select one.", netlists.size());
645 
646  QInputDialog dialog;
647  QStringList libs;
648 
649  for (auto& n : netlists)
650  {
651  libs.append(QString::fromStdString(n->get_gate_library()->get_name()));
652  }
653 
654  dialog.setComboBoxItems(libs);
655  dialog.setWindowTitle("Select gate library");
656  dialog.setLabelText("The specified file can be processed with more than one gate library. Please select which library should be used:");
657 
658  if (dialog.exec())
659  {
660  std::string selection = dialog.textValue().toStdString();
661 
662  for (auto& n : netlists)
663  {
664  if (n->get_gate_library()->get_name() == selection)
665  {
666  gNetlistOwner = std::move(n);
667  gNetlist = gNetlistOwner.get();
670  }
671  }
672  }
673  else
674  {
675  return false;
676  }
677  }
678 
679  fileSuccessfullyLoaded(logical_file_name);
680  return true;
681  }
682 
683  void FileManager::closeFile()
684  {
685  if (!mFileOpen)
686  return;
687 
688  mTimer->stop();
689  Q_EMIT fileAboutToClose(mFileName);
690 
691  // CHECK DIRTY AND TRIGGER SAVE ROUTINE
692 
694  mFileWatcher->removePath(mFileName);
695  mFileName = "";
696  mFileOpen = false;
697 
698  removeShadowDirectory();
699 
700  gNetlistOwner.reset();
701  gNetlist = nullptr;
702 
704  ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::NONE);
705 
706  Q_EMIT fileClosed();
707  }
708 
709  void FileManager::handleFileChanged(const QString& path)
710  {
711  Q_EMIT fileChanged(path);
712  }
713 
714  void FileManager::handleDirectoryChanged(const QString& path)
715  {
716  Q_EMIT fileDirectoryChanged(path);
717  }
718 
719  void FileManager::updateRecentFiles(const QString& file) const
720  {
721  QStringList list;
722 
723  gGuiState->beginReadArray("recent_files");
724  for (int i = 0; i < 14; ++i)
725  {
727  QString state_file = gGuiState->value("file").toString();
728 
729  if (state_file.isEmpty())
730  continue;
731 
732  list.append(gGuiState->value("file").toString());
733  }
734  gGuiState->endArray();
735 
736  int index = list.indexOf(file);
737  if (index == -1)
738  list.prepend(file);
739  else
740  list.move(index, 0);
741 
742  gGuiState->beginGroup("recent_files");
743  gGuiState->remove("");
744  gGuiState->endGroup();
745 
746  gGuiState->beginWriteArray("recent_files");
747  int i = 0;
748  std::vector<std::filesystem::path> files;
749  for (QString& string : list)
750  {
751  std::filesystem::path file_path(string.toStdString());
752  bool skip = false;
753  for (const auto& other : files)
754  {
755  if (std::filesystem::equivalent(file_path, other))
756  {
757  skip = true;
758  break;
759  }
760  }
761  if (!skip)
762  {
764  gGuiState->setValue("file", string);
765  ++i;
766  if (i == 14)
767  break;
768  }
769  }
770  gGuiState->endArray();
771  }
772 
773  GateLibrary* FileManager::loadGateLibrary(const QString& path)
774  {
775  std::filesystem::path glPath(path.toStdString());
776  GateLibrary* glib = gate_library_manager::load(glPath);
777  // the parse status is only meaningful if a parser was involved, which requires an existing file
778  QFileInfo glInfo(path);
779  if (glib || !glInfo.isFile() || GateLibraryParser::get_parse_status() != GateLibraryParser::ParseStatus::NeedsUpgrade)
780  return glib;
781 
782  QString message = QString("The gate library <%1> uses an outdated file format.\n\n"
783  "Upgrade it now? The original file will be kept as <%2>. "
784  "Cells that cannot be upgraded automatically are listed in the log.")
785  .arg(path, glInfo.completeBaseName() + ".json");
786  if (QMessageBox::question(qApp->activeWindow(), "Outdated gate library", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) != QMessageBox::Yes)
787  return nullptr;
788 
789  GateLibraryParser::request_upgrade();
790  return gate_library_manager::load(glPath);
791  }
792 
793  void FileManager::displayErrorMessage(QString error_message)
794  {
795  QMessageBox msgBox;
796  msgBox.setText("Error");
797  msgBox.setInformativeText(error_message);
798  msgBox.setStyleSheet("QLabel{min-width: 600px;}");
801  msgBox.exec();
802  }
803 } // namespace hal
void handleOpenDocument(const QString &fileName)
Stores information about the currently opened netlist.
Definition: file_manager.h:49
void loadFeature(FacExtensionInterface::Feature ft, const QString &extension=QString())
void registerNetlistCallbacks()
void unregisterNetlistCallbacks()
QString projectDirectory() const
QString gateLibraryPath() const
GuiPluginTable * mGuiPluginTable
Definition: plugin_relay.h:68
std::filesystem::path get_default_filename(const std::string &extension=std::string()) const
std::filesystem::path get_shadow_dir() const
QString gateLibraryFilename() const
Definition: project_json.h:51
bool create_project_directory(const std::string &path)
bool serialize_project(Netlist *netlist, bool shadow=false)
std::unique_ptr< Netlist > & get_netlist()
ProjectStatus get_project_status() const
void restore_project_file_from_autosave()
std::string get_netlist_filename() const
bool open_project(const std::string &path="")
const ProjectDirectory & get_project_directory() const
void set_project_directory(const std::string &path)
PythonThread * pythonThread() const
#define log_error(channel,...)
Definition: log.h:78
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
GateLibrary * load(std::filesystem::path file_path, bool reload=false)
std::vector< std::unique_ptr< Netlist > > load_netlists(const std::filesystem::path &netlist_file)
Create a netlist from a given file for each matching pre-loaded gate library.
std::unique_ptr< Netlist > create_netlist(const GateLibrary *gate_library)
Create a new empty netlist using the specified gate library.
std::unique_ptr< Netlist > load_netlist(const std::filesystem::path &netlist_file, const std::filesystem::path &gate_library_file=std::filesystem::path())
Create a netlist from the given file.
bool can_parse(const std::filesystem::path &file_name)
Definition: defines.h:45
PythonContext * gPythonContext
Definition: plugin_gui.cpp:89
QSettings * gGuiState
Definition: plugin_gui.cpp:78
ContentManager * gContentManager
Definition: plugin_gui.cpp:79
PluginRelay * gPluginRelay
Definition: plugin_gui.cpp:83
FileStatusManager * gFileStatusManager
Definition: plugin_gui.cpp:85
Netlist * gNetlist
Definition: gui_globals.h:69
NetlistRelay * gNetlistRelay
Definition: gui_globals.h:74
std::shared_ptr< Netlist > gNetlistOwner
Definition: plugin_gui.cpp:80
This file contains various functions to create and load netlists.
std::unique_ptr< BasePluginInterface > instance
QString toString(Qt::DateFormat format) const const
virtual int exec()
QString absoluteFilePath(const QString &fileName) const const
QString absolutePath() const const
QFileInfoList entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const const
bool mkpath(const QString &dirPath) const const
bool rename(const QString &oldName, const QString &newName)
bool copy(const QString &newName)
virtual bool open(QIODevice::OpenMode mode) override
bool remove()
QString completeBaseName() const const
bool exists() const const
QString fileName() const const
bool isDir() const const
bool isFile() const const
QDateTime lastModified() const const
QString suffix() const const
void directoryChanged(const QString &path)
void fileChanged(const QString &path)
void addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
int columnCount() const const
int rowCount() const const
void setComboBoxItems(const QStringList &items)
void setLabelText(const QString &text)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isObject() const const
QJsonObject object() const const
bool contains(const QString &key) const const
void append(const T &value)
void move(int from, int to)
void prepend(const T &value)
void addButton(QAbstractButton *button, QMessageBox::ButtonRole role)
QAbstractButton * clickedButton() const const
virtual int exec() override
void setIcon(QMessageBox::Icon)
void setInformativeText(const QString &text)
QMessageBox::StandardButton question(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
void setDefaultButton(QPushButton *button)
void setWindowTitle(const QString &title)
void setStandardButtons(QMessageBox::StandardButtons buttons)
void setText(const QString &text)
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
void beginGroup(const QString &prefix)
int beginReadArray(const QString &prefix)
void beginWriteArray(const QString &prefix, int size)
void endArray()
void endGroup()
void remove(const QString &key)
void setArrayIndex(int i)
void setValue(const QString &key, const QVariant &value)
QVariant value(const QString &key, const QVariant &defaultValue) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString left(int n) const const
QString & remove(int position, int n)
std::string toStdString() const const
int indexOf(QStringView str, int from) const const
void timeout()
QString toString() const const
QLayout * layout() const const
void setStyleSheet(const QString &styleSheet)
void setWindowTitle(const QString &)