HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
main_window.cpp
Go to the documentation of this file.
2 
3 #include "gui/action/action.h"
12 #include "gui/gui_def.h"
13 #include "gui/gui_globals.h"
26 #include "hal_core/defines.h"
28 #include "hal_core/netlist/gate.h"
31 #include "hal_core/netlist/net.h"
39 #include "hal_core/utilities/log.h"
41 
42 #include <QApplication>
43 #include <QCloseEvent>
44 #include <QDesktopWidget>
45 #include <QDir>
46 #include <QFileDialog>
47 #include <QInputDialog>
48 #include <QMessageBox>
49 #include <QPushButton>
50 #include <QRegExp>
51 #include <QShortcut>
52 #include <QStringList>
53 #include <QtConcurrent>
54 
55 
56 namespace hal
57 {
58  const char* MSG_PROJECT_ALREADY_OPEN = "You are already working on a HAL project. Close current project first.";
59 
61 
63  {
64  mFileActions = new FileActions(this);
65  ensurePolished(); // ADD REPOLISH METHOD
68 
69  mLayout = new QVBoxLayout(this);
70  mLayout->setContentsMargins(0, 0, 0, 0);
71  mLayout->setSpacing(0);
72 
73  mMenuBar = new QMenuBar();
74  mMenuBar->setNativeMenuBar(true);
76  mLayout->addWidget(mMenuBar);
77 
78  mToolBarLayout = new QHBoxLayout();
79  mToolBarLayout->setContentsMargins(0, 0, 0, 0);
80  mToolBarLayout->setSpacing(0);
81  mLayout->addLayout(mToolBarLayout);
82 
83  mLeftToolBar = new QToolBar();
84  mLeftToolBar->setObjectName("Toolbar");
85  mLeftToolBar->setMovable(false);
86  mLeftToolBar->setFloatable(false);
87  mLeftToolBar->setIconSize(QSize(18, 18));
89  mToolBarLayout->addWidget(mLeftToolBar);
90 
91  mRightToolBar = new QToolBar();
92  mRightToolBar->setObjectName("Toolbar");
93  mRightToolBar->setMovable(false);
94  mRightToolBar->setFloatable(false);
95  mRightToolBar->setIconSize(QSize(18, 18));
98  mToolBarLayout->addWidget(mRightToolBar);
99 
100  mStackedWidget = new QStackedWidget();
101  mLayout->addWidget(mStackedWidget);
102 
103  mSettings = new MainSettingsWidget;
104  mStackedWidget->addWidget(mSettings);
105 
106  mPluginManager = new GuiPluginManager(this);
108  mStackedWidget->addWidget(mPluginManager);
109 
110  mLayoutArea = new ContentLayoutArea();
111  mStackedWidget->addWidget(mLayoutArea);
112 
113  // mContainer = new QWidget();
114  // mStackedWidget->addWidget(mContainer);
115 
116  // mContainerLayout = new QVBoxLayout(mContainer);
117 
118  // mContainerLayout->setContentsMargins(0, 0, 0, 0);
119  // mContainerLayout->setSpacing(0);
120 
121  // m_tool_bar = new QToolBar();
122  // m_tool_bar->setMovable(false);
123  // m_tool_bar->setFloatable(false);
124  // m_tool_bar->setIconSize(QSize(18, 18));
125  // m_tool_bar->setToolButtonStyle(Qt::ToolButtonIconOnly);
126  // mContainerLayout->addWidget(m_tool_bar);
127 
128  // mLayoutArea = new hal_content_layout_area();
129  // mContainerLayout->addWidget(mLayoutArea);
130 
131  //welcome screen + other screens (?)
132 
133  mWelcomeScreen = new WelcomeScreen();
134  mStackedWidget->addWidget(mWelcomeScreen);
135  mGateLibraryManager = new GateLibraryManager(this);
136  mStackedWidget->addWidget(mGateLibraryManager);
137 
138  mStackedWidget->setCurrentWidget(mWelcomeScreen);
139 
141 
142  mActionImportNetlist = new Action(this);
143  mActionExportProject = new Action(this);
144  mActionImportProject = new Action(this);
145  mActionGateLibraryManager = new Action(this);
146  mActionAbout = new Action(this);
147 
148  mActionStartRecording = new Action(this);
149  mActionStopRecording = new Action(this);
150  mActionPlayMacro = new Action(this);
151  mActionUndo = new Action(this);
152 
153  mActionSettings = new Action(this);
154  mActionPluginManager = new Action(this);
155  mActionQuit = new Action(this);
156 
157  // //mOpenIconStyle = "all->#fcfcb0";
158  // //mOpenIconStyle = "all->#f2e4a4";
159  // mOpenIconStyle = "all->#3192C5";
160  // mOpenIconPath = ":/icons/folder";
161 
162  // mSaveIconStyle = "all->#3192C5";
163  // mSaveIconPath = ":/icons/folder-down";
164 
165  // //mScheduleIconStyle = "all->#08d320";
166  // //mScheduleIconStyle = "all->#05c61c";
167  // mScheduleIconStyle = "all->#2BAD4A";
168  // mScheduleIconPath = ":/icons/list";
169 
170  // //mRunIconStyle = "all->#05c61c";
171  // mRunIconStyle = "all->#2BAD4A";
172  // mRunIconPath = ":/icons/run";
173 
174  // mContentIconStyle = "all->#AFB1B3";
175  // mContentIconPath = ":/icons/content";
176 
177  // mSettingsIconStyle = "all->#AFB1B3";
178  // mSettingsIconPath = ":/icons/settings";
179 
180  setWindowIcon(gui_utility::getStyledSvgIcon(mHalIconStyle, mHalIconPath));
181 
182  mActionImportNetlist->setIcon(gui_utility::getStyledSvgIcon(mOpenFileIconStyle, mOpenFileIconPath));
183  mActionQuit->setIcon(gui_utility::getStyledSvgIcon(mQuitIconStyle, mQuitIconPath));
184  mActionGateLibraryManager->setIcon(gui_utility::getStyledSvgIcon(mNeGateIconStyle, mNeGateIconPath));
185  mActionUndo->setIcon(gui_utility::getStyledSvgIcon(mUndoIconStyle, mUndoIconPath));
186  mActionSettings->setIcon(gui_utility::getStyledSvgIcon(mSettingsIconStyle, mSettingsIconPath));
187  mActionPluginManager->setIcon(gui_utility::getStyledSvgIcon(mPluginsIconStyle, mPluginsIconPath));
188 
189  mMenuFile = new QMenu(mMenuBar);
190  mMenuEdit = new QMenu(mMenuBar);
191  mMenuMacro = new QMenu(mMenuBar);
192  mMenuUtilities = new QMenu(mMenuBar);
193  mMenuPlugins = new QMenu(mMenuBar);
194  mMenuHelp = new QMenu(mMenuBar);
195 
196  mMenuBar->addAction(mMenuFile->menuAction());
197  mMenuBar->addAction(mMenuEdit->menuAction());
198  mMenuBar->addAction(mMenuMacro->menuAction());
199  mMenuBar->addAction(mMenuUtilities->menuAction());
200  mMenuBar->addAction(mMenuPlugins->menuAction());
201  mMenuBar->addAction(mMenuHelp->menuAction());
202  mMenuFile->addAction(mFileActions->create());
203  mMenuFile->addAction(mFileActions->open());
204  mMenuFile->addAction(mFileActions->close());
205  mMenuFile->addAction(mFileActions->save());
206  mMenuFile->addAction(mFileActions->saveAs());
207 
208  QMenu* menuImport = new QMenu("Import …", this);
209  menuImport->addAction(mActionImportNetlist);
210  menuImport->addAction(mActionImportProject);
211 
212  QMenu* menuExport = new QMenu("Export …", this);
213  bool hasExporter = false;
215  {
216  if (it.second.empty()) continue; // no extensions registered
217 
218  QString label = QString::fromStdString(it.first);
219  QRegExp re("Default (.*) Writer", Qt::CaseInsensitive);
220  QString txt = (re.indexIn(label) < 0)
221  ? label.remove(QChar(':'))
222  : QString("Export as ") + re.cap(1);
223 
224  QStringList extensions;
225  extensions.append(txt);
226  for (std::string ex : it.second)
227  extensions.append(QString::fromStdString(ex));
228 
229  hasExporter = true;
230  Action* action = new Action(txt, this);
231  action->setData(extensions);
233  menuExport->addAction(action);
234  }
235  if (hasExporter) mMenuFile->addSeparator();
236  mActionExportProject->setDisabled(true);
237  menuExport->addAction(mActionExportProject);
238 
239  mMenuFile->addMenu(menuImport);
240  mMenuFile->addMenu(menuExport);
241  mMenuFile->addSeparator();
242  mMenuFile->addAction(mActionQuit);
243 
244  SettingsItemCheckbox* evlogSetting = new SettingsItemCheckbox(
245  "Netlist event log",
246  "debug/event_log",
247  false,
248  "eXpert Settings:Debug",
249  "Specifies whether each netlist event gets dumped to event log. Might generate a lot of output thus slowing down hal system."
250  );
251  event_log::enable_event_log(evlogSetting->value().toBool());
252  connect(evlogSetting,&SettingsItemCheckbox::boolChanged,this,&MainWindow::handleEventLogEnabled);
253 
254  mMenuEdit->addAction(mActionUndo);
255  mMenuEdit->addSeparator();
256  mMenuEdit->addAction(mActionSettings);
257  mMenuMacro->addAction(mActionStartRecording);
258  mMenuMacro->addAction(mActionStopRecording);
259  mMenuMacro->addSeparator();
260  mMenuMacro->addAction(mActionPlayMacro);
261  mMenuPlugins->setDisabled(true); // enable when project open
262  mMenuUtilities->addAction(mActionPluginManager);
263  mMenuUtilities->addAction(mActionGateLibraryManager);
264  mMenuHelp->addAction(mActionAbout);
265  mLeftToolBar->addAction(mFileActions->create());
266  mLeftToolBar->addAction(mFileActions->open());
267  mLeftToolBar->addAction(mFileActions->save());
268  mLeftToolBar->addAction(mFileActions->saveAs());
269  mLeftToolBar->addAction(mActionUndo);
270  mRightToolBar->addAction(mActionPluginManager);
271  mRightToolBar->addAction(mActionGateLibraryManager);
272  mRightToolBar->addAction(mActionSettings);
273 
274  mActionStartRecording->setText("Start recording");
275  mActionStopRecording->setText("Stop recording");
276  mActionPlayMacro->setText("Play macro");
277 
278  mActionStartRecording->setEnabled(true);
279  mActionStopRecording->setEnabled(false);
280  mActionPlayMacro->setEnabled(true);
281 
282  setWindowTitle("HAL");
283  mActionImportNetlist->setText("Import Netlist");
284  mActionImportProject->setText("Import Project");
285  mActionExportProject->setText("Export Project");
286  mActionGateLibraryManager->setText("Gate Library Manager");
287  mActionUndo->setText("Undo");
288  mActionAbout->setText("About");
289  mActionSettings->setText("Settings");
290  mActionPluginManager->setText("Plugin Manager");
291  mActionQuit->setText("Quit");
292  mMenuFile->setTitle("File");
293  mMenuEdit->setTitle("Edit");
294  mMenuMacro->setTitle("Macro");
295  mMenuUtilities->setTitle("Utilities");
296  mMenuPlugins->setTitle("Plugins");
297  mMenuHelp->setTitle("Help");
298 
299  gPythonContext = new PythonContext(this);
300 
301  gContentManager = new ContentManager(this);
302  gCommentManager = new CommentManager(this);
303 
304  mSettingUndoLast = new SettingsItemKeybind("Undo Last Action", "keybinds/action_undo", QKeySequence("Ctrl+Z"), "Keybindings:Global", "Keybind for having last user interaction undone.");
305 
306  QShortcut* shortCutUndoLast = new QShortcut(mSettingUndoLast->value().toString(), this);
307 
308  connect(mSettingUndoLast, &SettingsItemKeybind::keySequenceChanged, shortCutUndoLast, &QShortcut::setKey);
309 
310  connect(shortCutUndoLast, &QShortcut::activated, mActionUndo, &QAction::trigger);
311 
312  connect(mActionImportNetlist, &Action::triggered, this, &MainWindow::handleActionImportNetlist);
314  connect(mActionSettings, &Action::triggered, this, &MainWindow::openSettings);
315  connect(mActionPluginManager, &Action::triggered, this, &MainWindow::openPluginManager);
318  connect(mActionExportProject, &Action::triggered, this, &MainWindow::handleExportProjectTriggered);
319  connect(mActionImportProject, &Action::triggered, this, &MainWindow::handleImportProjectTriggered);
320  connect(mActionGateLibraryManager, &Action::triggered, this, &MainWindow::handleActionGatelibraryManager);
322 
323  connect(mActionStartRecording, &Action::triggered, this, &MainWindow::handleActionStartRecording);
324  connect(mActionStopRecording, &Action::triggered, this, &MainWindow::handleActionStopRecording);
325  connect(mActionPlayMacro, &Action::triggered, this, &MainWindow::handleActionPlayMacro);
327 
330  enableUndo(false);
331 
332  restoreState();
333  }
334 
336  {
337  QString styleSheetToOpen;
338 
339  switch (istyle)
340  {
341  case StyleSheetOption::Dark:
342  styleSheetToOpen = ":/style/dark";
343  break;
344  case StyleSheetOption::Light:
345  styleSheetToOpen = ":/style/light";
346  break;
347  default:
348  return;
349  }
350  QFile stylesheet(styleSheetToOpen);
351  stylesheet.open(QFile::ReadOnly);
352  qApp->setStyleSheet(QString(stylesheet.readAll()));
353  }
354 
356  {
357  return mHalIconPath;
358  }
359 
361  {
362  return mHalIconStyle;
363  }
364 
366  {
367  return mOpenFileIconPath;
368  }
369 
371  {
372  return mOpenFileIconStyle;
373  }
374 
376  {
377  return mQuitIconPath;
378  }
379 
381  {
382  return mQuitIconStyle;
383  }
384 
386  {
387  return mSettingsIconPath;
388  }
389 
391  {
392  return mSettingsIconStyle;
393  }
394 
396  {
397  return mPluginsIconPath;
398  }
399 
401  {
402  return mPluginsIconStyle;
403  }
404 
406  {
407  return mUndoIconPath;
408  }
409 
411  {
412  return mUndoIconStyle;
413  }
414 
416  {
417  return mNeGateIconPath;
418  }
420  {
421  return mNeGateIconStyle;
422  }
423 
425  {
426  return mDisabledIconStyle;
427  }
428 
430  {
431  mHalIconPath = path;
432  }
433 
435  {
436  mHalIconStyle = style;
437  }
438 
440  {
441  mOpenFileIconPath = path;
442  }
443 
445  {
446  mOpenFileIconStyle = style;
447  }
448 
450  {
451  mQuitIconPath = path;
452  }
453 
455  {
456  mQuitIconStyle = style;
457  }
458 
460  {
461  mSettingsIconPath = path;
462  }
463 
465  {
466  mSettingsIconStyle = style;
467  }
468 
470  {
471  mPluginsIconPath = path;
472  }
473 
475  {
476  mPluginsIconStyle = style;
477  }
478 
480  {
481  mUndoIconPath = path;
482  }
483 
485  {
486  mUndoIconStyle = style;
487  }
488 
490  {
491  mNeGateIconPath = path;
492  }
494  {
495  mNeGateIconStyle = style;
496  }
497 
499  {
500  mDisabledIconStyle = style;
501  }
502 
504  {
505  mLayoutArea->addContent(widget, index, anchor);
506  }
507 
509  {
510  Q_UNUSED(widget)
511  // IMPLEMENT
512  }
513 
515  {
516  mLayoutArea->clear();
517  }
518 
519  void MainWindow::handleEventLogEnabled(bool enable)
520  {
522  }
523 
524  extern void runMain(const QString fileName, const QList<QString> plugins);
525 
527  {
528  //mLayoutArea->removeContent();
529  }
530 
532  {
534  {
535  if(!mGateLibraryManager->callUnsavedChangesWindow()) return;
536  }
537  if (mStackedWidget->currentWidget() == mSettings)
538  return; //nothing todo, already fetchGateLibrary
539 
540  mSettings->activate();
541  mStackedWidget->setCurrentWidget(mSettings);
542  }
543 
545  {
546  if (!mSettings->handleAboutToClose())
547  return;
548  if (FileManager::get_instance()->fileOpen())
549  mStackedWidget->setCurrentWidget(mLayoutArea);
550  else
551  mStackedWidget->setCurrentWidget(mWelcomeScreen);
552  }
553 
555  {
556  bool isFileOpen = FileManager::get_instance()->fileOpen();
557  if(isFileOpen)
558  mStackedWidget->setCurrentWidget(mLayoutArea);
559  else
560  mStackedWidget->setCurrentWidget(mWelcomeScreen);
561  mFileActions->setup();
562  }
563 
565  {
567  {
568  if(!mGateLibraryManager->callUnsavedChangesWindow()) return;
569  }
570 
571  mPluginManager->repolish();
572  if (mStackedWidget->currentWidget() == mPluginManager)
573  return; //nothing todo, already fetchGateLibrary
574 
575  if (mStackedWidget->currentWidget() == mSettings)
576  {
577  if (!mSettings->handleAboutToClose())
578  return;
579  }
580  mStackedWidget->setCurrentWidget(mPluginManager);
581  mFileActions->setup(nullptr, mPluginManager);
582  }
583 
585  {
586  if (FileManager::get_instance()->fileOpen())
587  mStackedWidget->setCurrentWidget(mLayoutArea);
588  else
589  mStackedWidget->setCurrentWidget(mWelcomeScreen);
590 
591  mMenuPlugins->clear();
592  if (FileManager::get_instance()->fileOpen())
593  mPluginManager->addPluginActions(mMenuPlugins);
594  else
595  mMenuPlugins->setDisabled(true);
596  mFileActions->setup();
597  }
598 
600  {
601  if (gNetlist != nullptr)
602  {
603  QMessageBox msgBox;
604  msgBox.setText("Error: New Project");
606  msgBox.setStyleSheet("QLabel{min-width: 600px;}");
609  msgBox.exec();
610  return;
611  }
612 
614  act->exec();
615  }
616 
618  {
619  if (gNetlist != nullptr)
620  {
621  QMessageBox msgBox;
622  msgBox.setText("Error: Open Project");
624  msgBox.setStyleSheet("QLabel{min-width: 600px;}");
627  msgBox.exec();
628  return;
629  }
630 
631  ProjectDirDialog pdd("Open HAL project", QDir::currentPath(), this);
632  if (pdd.exec() != QDialog::Accepted) return;
633  QStringList projects = pdd.selectedFiles();
634  for (int inx = 0; inx < projects.size(); ++inx)
635  {
636  if (!QFileInfo(projects.at(inx)).suffix().isEmpty())
637  {
638  QMessageBox::warning(this,"Bad project directory", "HAL project directories must not have suffix (." +
639  QFileInfo(projects.at(inx)).suffix() + ") in name");
640  continue;
641  }
643  act->exec();
644  break;
645  }
646  }
647 
649  {
650  if (gNetlist != nullptr)
651  {
652  QMessageBox msgBox;
653  msgBox.setText("Error: Import Netlist");
655  msgBox.setStyleSheet("QLabel{min-width: 600px;}");
658  msgBox.exec();
659  return;
660  }
661 
662  QString title = "Import Netlist";
664  QString text = sff.toFileDialog(true);
665 
666  // Non native dialogs does not work on macOS. Therefore do net set DontUseNativeDialog!
667  QString path = QDir::currentPath();
668 
669  if (gGuiState->contains("FileDialog/Path/MainWindow"))
670  path = gGuiState->value("FileDialog/Path/MainWindow").toString();
671 
672  QString fileName = QFileDialog::getOpenFileName(nullptr, title, path, text, nullptr);
673 
674  if (!fileName.isNull())
675  {
676  QString ext = QFileInfo(fileName).suffix();
677  if (!ext.isEmpty())
679 
680  gGuiState->setValue("FileDialog/Path/MainWindow", fileName);
681 
683  actOpenfile->exec();
684  }
685  }
686 
687  void MainWindow::handleProjectOpened(const QString& projDir, const QString& fileName)
688  {
689  Q_UNUSED(projDir);
690  mActionExportProject->setEnabled(true);
691  mActionImportProject->setDisabled(true);
692  handleFileOpened(fileName);
693  }
694 
695  void MainWindow::handleFileOpened(const QString& fileName)
696  {
697  Q_UNUSED(fileName)
698  if (mStackedWidget->currentWidget() == mWelcomeScreen)
699  {
700  mStackedWidget->setCurrentWidget(mLayoutArea);
701  mWelcomeScreen->close();
702  }
704 
705  mMenuPlugins->clear();
706  mPluginManager->addPluginActions(mMenuPlugins);
707  }
708 
710  {
711  if (!gNetlist) return;
712  QAction* act = static_cast<QAction*>(sender());
713  if (!act || act->data().isNull()) return;
714 
716  if (erf.queryFilename())
717  erf.exportNetlist();
718 
719  }
720 
722  {
723  if(!gNetlist)
724  {
725  QMessageBox optBox;
726  QPushButton* newBtn = optBox.addButton("New", QMessageBox::AcceptRole);
727  newBtn->setToolTip("Create new gate library");
728  QPushButton* openBtn = optBox.addButton(QMessageBox::Open);
729  openBtn->setToolTip("Open existing gate library");
730  QPushButton* cancelBtn = optBox.addButton(QMessageBox::Cancel);
731  optBox.setWindowTitle("Please select …");
732  cancelBtn->setToolTip("Cancel");
733 
734  optBox.setText("Gate Library Manager");
735 
736  auto btn = optBox.exec();
737 
738  if(optBox.clickedButton() == newBtn)
739  {
740  mGateLibraryManager->handleCreateAction();
741  mStackedWidget->setCurrentWidget(mGateLibraryManager);
742  mFileActions->setup(mGateLibraryManager);
743  return;
744  }
745  else if (optBox.clickedButton() == cancelBtn)
746  return;
747  }
749  {
750  if(!mGateLibraryManager->callUnsavedChangesWindow()) return;
751  }
752  if(mGateLibraryManager->initialize())
753  {
754  mStackedWidget->setCurrentWidget(mGateLibraryManager);
755  mFileActions->setup(mGateLibraryManager);
756  }
757  }
758 
759  void MainWindow::handleImportProjectTriggered()
760  {
761  ImportProjectDialog ipd(this);
762  if (ipd.exec() == QDialog::Accepted)
763  {
764  if (ipd.importProject())
765  {
767  ipd.extractedProjectAbsolutePath());
768  act->exec();
769  }
770  else
772  "Import Project Failed",
773  "Failed to extract a HAL project from selected archive file.\n"
774  "You might want to uncompress the archive manually and try to fetchGateLibrary the project.");
775  }
776  }
777 
778  void MainWindow::handleExportProjectTriggered()
779  {
780  ProjectManager* pm = ProjectManager::instance();
781  if (pm->get_project_status() == ProjectManager::ProjectStatus::NONE) return;
783  {
784  switch (QMessageBox::warning(this, "Unsaved Changes", "The HAL project have been modified.\n"
785  "You might want to save the changes\n"
786  "before exporting the project.",
787  "Save",
788  "Export without save",
789  "Cancel", 0, 2)) {
790  case 2: // Escape
791  return;
792  case 0:
794  break;
795  }
796  }
797  ExportProjectDialog epd(this);
798  if (epd.exec() == QDialog::Accepted)
799  {
800  epd.exportProject();
801  }
802  }
803 
805  {
806  QString filename = saveHandler();
807  if (!filename.isEmpty())
808  gContentManager->setWindowTitle(filename);
809  }
810 
812  {
814  if (pm->get_project_status() == ProjectManager::ProjectStatus::NONE) return;
815  QString projectDir = QString::fromStdString(pm->get_project_directory().string());
816  saveHandler(projectDir);
817  gContentManager->setWindowTitle(projectDir);
818  }
819 
820  QString MainWindow::saveHandler(const QString &projectDir)
821  {
822  if (!gNetlist) return QString();
823 
824  QString saveProjectDir(projectDir);
825 
827 
828  if (saveProjectDir.isEmpty())
829  {
830  QString title = "Save Project";
831  QString filter = "HAL Directory Folder (*)";
832 
833  // Non native dialogs does not work on macOS. Therefore do net set DontUseNativeDialog!
834  saveProjectDir = QFileDialog::getSaveFileName(nullptr, title, QDir::currentPath(), filter, nullptr);
835  if (saveProjectDir.isEmpty()) return QString();
836 
837  QFileInfo finfo(saveProjectDir);
838 
839  if (!finfo.suffix().isEmpty())
840  {
841  QMessageBox::warning(this,"Save Error", "selected project directory name must not have suffix ." + finfo.suffix());
842  return QString();
843  }
844  if (finfo.exists())
845  {
846  QMessageBox::warning(this,"Save Error", "folder " + saveProjectDir + " already exists");
847  return QString();
848  }
849 
850  if (!pm->create_project_directory(saveProjectDir.toStdString()))
851  {
852  QMessageBox::warning(this,"Save Error", "cannot create folder " + saveProjectDir);
853  return QString();
854  }
855  }
856 
858 
859  if (!pm->serialize_project(gNetlist))
860  {
861  log_warning("gui", "error saving netlist to <" + qNetlistPath.toStdString() + ">");
862  return QString();
863  }
864 
866 
867  FileManager* fm = FileManager::get_instance();
868  fm->watchFile(qNetlistPath);
869  fm->emitProjectSaved(saveProjectDir, qNetlistPath);
870 
871  return QString::fromStdString(pm->get_project_directory().string());
872  }
873 
875  {
876  mActionStartRecording->setEnabled(false);
877  mActionStopRecording->setEnabled(true);
878  mActionPlayMacro->setEnabled(false);
880  }
881 
883  {
885  QString macroFile;
886  bool trySaveMacro = true;
887  while (trySaveMacro) {
888  if (uam->hasRecorded())
889  {
890  macroFile = QFileDialog::getSaveFileName(this, "Save macro to file", ".");
891  if (!macroFile.isEmpty() && !macroFile.contains(QChar('.')))
892  macroFile += ".xml";
893  }
894  switch (uam->setStopRecording(macroFile))
895  {
896  case QMessageBox::Retry:
897  break;
898  case QMessageBox::Cancel:
899  return;
900  default:
901  // Ok or Discard
902  trySaveMacro = false;
903  break;
904  }
905  }
906  mActionStartRecording->setEnabled(true);
907  mActionStopRecording->setEnabled(false);
908  mActionPlayMacro->setEnabled(true);
909  }
910 
912  {
913  QString macroFile = QFileDialog::getOpenFileName(this, "Load macro file", ".", "Macro files (*.xml);;All files(*)");
914  if (!macroFile.isEmpty())
916  }
917 
919  {
920  AboutDialog ad;
921  ad.exec();
922  }
923 
925  {
927  }
928 
929  void MainWindow::enableUndo(bool enable)
930  {
931  QString iconStyle = enable ? mUndoIconStyle : mDisabledIconStyle;
932  mActionUndo->setEnabled(enable);
933  mActionUndo->setIcon(gui_utility::getStyledSvgIcon(iconStyle, mUndoIconPath));
934  }
935 
937  {
938  if (FileManager::get_instance()->fileOpen())
939  tryToCloseFile();
940  }
941 
943  {
944  close();
945  }
946 
947  void MainWindow::closeEvent(QCloseEvent* event)
948  {
950  {
951  if (tryToCloseFile())
952  event->accept();
953  else
954  {
955  event->ignore();
956  return;
957  }
958  }
959 
960  saveState();
961  qApp->quit();
962  }
963 
964  bool MainWindow::tryToCloseFile()
965  {
967  {
968  QMessageBox msgBox(this);
969  msgBox.setStyleSheet("QLabel{min-width: 600px;}");
970  auto cancelButton = msgBox.addButton("Cancel", QMessageBox::RejectRole);
971  msgBox.addButton("Close Anyway", QMessageBox::ApplyRole);
972  msgBox.setDefaultButton(cancelButton);
973  msgBox.setInformativeText("Are you sure you want to close the application ?");
974 
975  msgBox.setText("There are unsaved modifications.");
976  QString detailed_text = "The following modifications have not been saved yet:\n";
978  detailed_text.append(" -> modified Gate Library\n");
979  for (const auto& s : gFileStatusManager->getUnsavedChangeDescriptors())
980  detailed_text.append(" -> " + s + "\n");
981 
982  msgBox.setDetailedText(detailed_text);
983 
984  for (const auto& button : msgBox.buttons())
985  {
986  // if (button->text() == "Show Details...")
987  if (msgBox.buttonRole(button) == QMessageBox::ActionRole)
988  {
989  button->click();
990  break;
991  }
992  }
993 
994  msgBox.exec();
995 
996  if (msgBox.clickedButton() == cancelButton)
997  return false;
998  }
999 
1000  // going to close
1001 
1002  for (GuiExtensionInterface* geif : GuiPluginManager::getGuiExtensions().values())
1003  geif->netlist_about_to_close(gNetlist);
1004 
1005  mActionExportProject->setDisabled(true);
1006  mActionImportProject->setEnabled(true);
1007 
1009 
1011 
1012  clear();
1013 
1015  // PYTHON ???
1018 
1020  setWindowTitle("HAL");
1021  gFileStatusManager->netlistClosed(); // disable save actions
1022 
1023  mStackedWidget->setCurrentWidget(mWelcomeScreen);
1024 
1025  gNetlistRelay->reset();
1026 
1027  mMenuPlugins->clear();
1028  mMenuPlugins->setDisabled(true);
1029 // mActionGateLibraryManager->setVisible(true);
1030 
1031  return true;
1032  }
1033 
1034  void MainWindow::restoreState()
1035  {
1037  move(pos);
1039  resize(size);
1040  //restore state of all subwindows
1041  mLayoutArea->initSplitterSize(size);
1042  }
1043 
1044  void MainWindow::saveState()
1045  {
1047  }
1048 
1050  {
1051  return mLayoutArea;
1052  }
1053 } // namespace hal
A dialog that displays the Qt version and our open source license.
Definition: about_dialog.h:43
Provides an interface for triggerable functionality that can be inserted into widgets and also connec...
Definition: action.h:42
void setText(const QString &text)
Definition: action.cpp:21
Manages the layout of all ContentWidgets.
void initSplitterSize(const QSize &size)
void addContent(ContentWidget *widget, int index, ContentLayout::Position anchor)
Manages all ContentWidgets.
void setWindowTitle(const QString &filename)
Abstract class for Widgets within HAL's ContentArea.
Utility class to export (save) different hal files.
Action * close() const
Definition: file_actions.h:229
void setup(GateLibraryManager *glcw=nullptr, GuiPluginManager *plmgr=nullptr)
Action * create() const
Definition: file_actions.h:227
Action * save() const
Definition: file_actions.h:230
Action * saveAs() const
Definition: file_actions.h:231
Action * open() const
Definition: file_actions.h:228
static FileManager * get_instance()
bool fileOpen() const
void projectOpened(QString projectDir, QString fileName)
void fileOpened(const QString &fileName)
QList< QString > getUnsavedChangeDescriptors() const
bool initialize(GateLibrary *gateLibrary=nullptr, bool readOnly=false)
void addPluginActions(QMenu *menu) const
static QMap< QString, GuiExtensionInterface * > getGuiExtensions()
SupportedFileFormats listFacFeature(FacExtensionInterface::Feature ft) const
void loadFeature(FacExtensionInterface::Feature ft, const QString &extension=QString())
The top-level widget that displays all settings.
void closeGateLibraryManager()
void openPluginManager()
void handleActionImportNetlist()
void handleActionOpenProject()
void setUndoIconStyle(const QString &style)
QString neGateIconStyle() const
void handleActionAbout()
QString pluginsIconStyle() const
void handleActionGatelibraryManager()
void setHalIconPath(const QString &path)
void handleSaveAsTriggered()
void handleActionUndo()
void closePluginManager()
void handleActionCloseFile()
void reloadStylsheet(int istyle)
QString halIconPath() const
void handleActionStopRecording()
void setNeGateIconStyle(const QString &style)
void setSettingsIconStyle(const QString &style)
QString undoIconPath() const
void handleActionNew()
ContentLayoutArea * layoutArea() const
QString disabledIconStyle() const
QString quitIconStyle() const
void setOpenFileIconPath(const QString &path)
void handleActionStartRecording()
void enableUndo(bool enable=true)
void handleProjectOpened(const QString &projDir, const QString &fileName)
void addContent(ContentWidget *widget, int index, ContentLayout::Position anchor)
void setNeGateIconPath(const QString &path)
void setOpenFileIconStyle(const QString &style)
QString quitIconPath() const
void setUndoIconPath(const QString &path)
void handleActionPlayMacro()
void onActionQuitTriggered()
void handleFileOpened(const QString &fileName)
void setSettingsIconPath(const QString &path)
MainWindow(QWidget *parent=nullptr)
Definition: main_window.cpp:62
void removeContent(ContentWidget *widget)
void setQuitIconPath(const QString &path)
QString settingsIconPath() const
void setHalIconStyle(const QString &style)
QString openFileIconStyle() const
void onActionCloseDocumentTriggered()
void handleSaveTriggered()
QString undoIconStyle() const
QString halIconStyle() const
void setQuitIconStyle(const QString &style)
QString neGateIconPath() const
void handleActionExport()
static SettingsItemDropdown * sSettingStyle
Definition: main_window.h:302
QString openFileIconPath() const
void setDisabledIconStyle(const QString &style)
void setPluginsIconStyle(const QString &style)
void setPluginsIconPath(const QString &path)
QString pluginsIconPath() const
QString settingsIconStyle() const
GuiPluginTable * mGuiPluginTable
Definition: plugin_relay.h:68
std::filesystem::path get_default_filename(const std::string &extension=std::string()) const
static ProjectManager * instance()
bool create_project_directory(const std::string &path)
bool serialize_project(Netlist *netlist, bool shadow=false)
ProjectStatus get_project_status() const
const ProjectDirectory & get_project_directory() const
Interface for pybind11.
A SettingsItem representing a Checkbox.
virtual QVariant value() const override
A SettingsItem that represents a dropdown menu.
void intChanged(int value)
A SettingsItem to modify keybinds.
void keySequenceChanged(QKeySequence value)
virtual QVariant value() const override
void mainWindowSaveGeometry(const QPoint &pos, const QSize &size)
static SettingsManager * instance()
QSize mainWindowSize() const
QPoint mainWindowPosition() const
QString toFileDialog(bool addHalFormat) const
Handles and manages user actions related proccesses.
void canUndoLastAction(bool yesWeCan)
static UserActionManager * instance()
void playMacro(const QString &macroFilename)
QMessageBox::StandardButton setStopRecording(const QString &macroFilename)
Hal's welcome screen.
#define log_warning(channel,...)
Definition: log.h:76
void enable_event_log(bool enable)
Definition: event_log.cpp:20
QIcon getStyledSvgIcon(const QString &from_to_colors_enabled, const QString &svg_path, QString from_to_colors_disabled=QString())
Definition: graphics.cpp:60
const std::unordered_map< std::string, std::vector< std::string > > & get_writer_extensions()
Retrieve the extensions for which extensions have been registered.
Definition: defines.h:45
const char * MSG_PROJECT_ALREADY_OPEN
Definition: main_window.cpp:58
PythonContext * gPythonContext
Definition: plugin_gui.cpp:88
QSettings * gGuiState
Definition: plugin_gui.cpp:77
ContentManager * gContentManager
Definition: plugin_gui.cpp:78
PluginRelay * gPluginRelay
Definition: plugin_gui.cpp:82
FileStatusManager * gFileStatusManager
Definition: plugin_gui.cpp:84
void runMain(const QString fileName, const QList< QString > plugins)
GraphContextManager * gGraphContextManager
Definition: plugin_gui.cpp:85
SelectionRelay * gSelectionRelay
Definition: plugin_gui.cpp:83
CommentManager * gCommentManager
Definition: plugin_gui.cpp:87
Netlist * gNetlist
Definition: gui_globals.h:69
NetlistRelay * gNetlistRelay
Definition: gui_globals.h:74
This file contains various functions to create and load netlists.
QVariant data() const const
void setEnabled(bool)
void setIcon(const QIcon &icon)
void setData(const QVariant &userData)
void setDisabled(bool b)
void trigger()
void triggered(bool checked)
void addLayout(QLayout *layout, int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void setSpacing(int spacing)
virtual int exec()
QString currentPath()
virtual bool open(QIODevice::OpenMode mode) override
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QStringList selectedFiles() const const
QString suffix() const const
QByteArray readAll()
void setContentsMargins(int left, int top, int right, int bottom)
void append(const T &value)
const T & at(int i) const const
int size() const const
QAction * addAction(const QString &text)
QAction * addMenu(QMenu *menu)
QAction * addSeparator()
void clear()
QAction * menuAction() const const
void setTitle(const QString &title)
QAction * addAction(const QString &text)
void setNativeMenuBar(bool nativeMenuBar)
void addButton(QAbstractButton *button, QMessageBox::ButtonRole role)
QAbstractButton * clickedButton() const const
virtual int exec() override
void setInformativeText(const QString &text)
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)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setObjectName(const QString &name)
QObject * sender() const const
QString cap(int nth) const const
int indexIn(const QString &str, int offset, QRegExp::CaretMode caretMode) const const
bool contains(const QString &key) const const
void setValue(const QString &key, const QVariant &value)
QVariant value(const QString &key, const QVariant &defaultValue) const const
void activated()
void setKey(const QKeySequence &key)
int addWidget(QWidget *widget)
QWidget * currentWidget() const const
void setCurrentWidget(QWidget *widget)
QString & append(QChar ch)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
bool isNull() const const
QString & remove(int position, int n)
std::string toStdString() const const
CaseInsensitive
ToolButtonIconOnly
QAction * addAction(const QString &text)
void setFloatable(bool floatable)
void setIconSize(const QSize &iconSize)
void setMovable(bool movable)
void setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
bool isNull() const const
bool toBool() const const
QString toString() const const
QStringList toStringList() const const
bool close()
void ensurePolished() const const
void setLocale(const QLocale &locale)
void move(int x, int y)
void resize(int w, int h)
void setDisabled(bool disable)
void setSizePolicy(QSizePolicy)
QStyle * style() const const
void setStyleSheet(const QString &styleSheet)
void setToolTip(const QString &)
void setWindowIcon(const QIcon &icon)
void setWindowTitle(const QString &)