HAL
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 
62  MainWindow::MainWindow(QWidget* parent) : QWidget(parent)
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);
75  mMenuBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
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));
88  mLeftToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
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));
96  mRightToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
97  mRightToolBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
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);
313  connect(mActionAbout, &Action::triggered, this, &MainWindow::handleActionAbout);
314  connect(mActionSettings, &Action::triggered, this, &MainWindow::openSettings);
315  connect(mActionPluginManager, &Action::triggered, this, &MainWindow::openPluginManager);
316  connect(mSettings, &MainSettingsWidget::close, this, &MainWindow::closeSettings);
317  connect(mGateLibraryManager, &GateLibraryManager::close, this, &MainWindow::closeGateLibraryManager);
318  connect(mActionExportProject, &Action::triggered, this, &MainWindow::handleExportProjectTriggered);
319  connect(mActionImportProject, &Action::triggered, this, &MainWindow::handleImportProjectTriggered);
320  connect(mActionGateLibraryManager, &Action::triggered, this, &MainWindow::handleActionGatelibraryManager);
321  connect(mActionQuit, &Action::triggered, this, &MainWindow::onActionQuitTriggered);
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);
326  connect(mActionUndo, &Action::triggered, this, &MainWindow::handleActionUndo);
327 
329  connect(sSettingStyle, &SettingsItemDropdown::intChanged, this, &MainWindow::reloadStylsheet);
330  enableUndo(false);
331 
332  restoreState();
333  }
334 
335  void MainWindow::reloadStylsheet(int istyle)
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 
355  QString MainWindow::halIconPath() const
356  {
357  return mHalIconPath;
358  }
359 
360  QString MainWindow::halIconStyle() const
361  {
362  return mHalIconStyle;
363  }
364 
365  QString MainWindow::openFileIconPath() const
366  {
367  return mOpenFileIconPath;
368  }
369 
370  QString MainWindow::openFileIconStyle() const
371  {
372  return mOpenFileIconStyle;
373  }
374 
375  QString MainWindow::quitIconPath() const
376  {
377  return mQuitIconPath;
378  }
379 
380  QString MainWindow::quitIconStyle() const
381  {
382  return mQuitIconStyle;
383  }
384 
385  QString MainWindow::settingsIconPath() const
386  {
387  return mSettingsIconPath;
388  }
389 
390  QString MainWindow::settingsIconStyle() const
391  {
392  return mSettingsIconStyle;
393  }
394 
395  QString MainWindow::pluginsIconPath() const
396  {
397  return mPluginsIconPath;
398  }
399 
400  QString MainWindow::pluginsIconStyle() const
401  {
402  return mPluginsIconStyle;
403  }
404 
405  QString MainWindow::undoIconPath() const
406  {
407  return mUndoIconPath;
408  }
409 
410  QString MainWindow::undoIconStyle() const
411  {
412  return mUndoIconStyle;
413  }
414 
415  QString MainWindow::neGateIconPath() const
416  {
417  return mNeGateIconPath;
418  }
419  QString MainWindow::neGateIconStyle() const
420  {
421  return mNeGateIconStyle;
422  }
423 
424  QString MainWindow::disabledIconStyle() const
425  {
426  return mDisabledIconStyle;
427  }
428 
429  void MainWindow::setHalIconPath(const QString& path)
430  {
431  mHalIconPath = path;
432  }
433 
434  void MainWindow::setHalIconStyle(const QString& style)
435  {
436  mHalIconStyle = style;
437  }
438 
439  void MainWindow::setOpenFileIconPath(const QString& path)
440  {
441  mOpenFileIconPath = path;
442  }
443 
444  void MainWindow::setOpenFileIconStyle(const QString& style)
445  {
446  mOpenFileIconStyle = style;
447  }
448 
449  void MainWindow::setQuitIconPath(const QString& path)
450  {
451  mQuitIconPath = path;
452  }
453 
454  void MainWindow::setQuitIconStyle(const QString& style)
455  {
456  mQuitIconStyle = style;
457  }
458 
459  void MainWindow::setSettingsIconPath(const QString& path)
460  {
461  mSettingsIconPath = path;
462  }
463 
464  void MainWindow::setSettingsIconStyle(const QString& style)
465  {
466  mSettingsIconStyle = style;
467  }
468 
469  void MainWindow::setPluginsIconPath(const QString& path)
470  {
471  mPluginsIconPath = path;
472  }
473 
474  void MainWindow::setPluginsIconStyle(const QString& style)
475  {
476  mPluginsIconStyle = style;
477  }
478 
479  void MainWindow::setUndoIconPath(const QString& path)
480  {
481  mUndoIconPath = path;
482  }
483 
484  void MainWindow::setUndoIconStyle(const QString& style)
485  {
486  mUndoIconStyle = style;
487  }
488 
489  void MainWindow::setNeGateIconPath(const QString& path)
490  {
491  mNeGateIconPath = path;
492  }
493  void MainWindow::setNeGateIconStyle(const QString& style)
494  {
495  mNeGateIconStyle = style;
496  }
497 
498  void MainWindow::setDisabledIconStyle(const QString& style)
499  {
500  mDisabledIconStyle = style;
501  }
502 
503  void MainWindow::addContent(ContentWidget* widget, int index, content_anchor anchor)
504  {
505  mLayoutArea->addContent(widget, index, anchor);
506  }
507 
508  void MainWindow::removeContent(ContentWidget* widget)
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 
526  void MainWindow::onActionCloseDocumentTriggered()
527  {
528  //mLayoutArea->removeContent();
529  }
530 
531  void MainWindow::openSettings()
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 
544  void MainWindow::closeSettings()
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 
554  void MainWindow::closeGateLibraryManager()
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 
564  void MainWindow::openPluginManager()
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 
584  void MainWindow::closePluginManager()
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 
599  void MainWindow::handleActionNew()
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 
613  ActionOpenNetlistFile* act = new ActionOpenNetlistFile(ActionOpenNetlistFile::CreateNew);
614  act->exec();
615  }
616 
617  void MainWindow::handleActionOpenProject()
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  }
642  ActionOpenNetlistFile* act = new ActionOpenNetlistFile(ActionOpenNetlistFile::OpenProject, pdd.selectedFiles().at(inx));
643  act->exec();
644  break;
645  }
646  }
647 
648  void MainWindow::handleActionImportNetlist()
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";
663  SupportedFileFormats sff = gPluginRelay->mGuiPluginTable->listFacFeature(FacExtensionInterface::FacNetlistParser);
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())
678  gPluginRelay->mGuiPluginTable->loadFeature(FacExtensionInterface::FacNetlistParser,ext);
679 
680  gGuiState->setValue("FileDialog/Path/MainWindow", fileName);
681 
682  ActionOpenNetlistFile* actOpenfile = new ActionOpenNetlistFile(ActionOpenNetlistFile::ImportFile, fileName);
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  }
703  gPythonContext->updateNetlist();
704 
705  mMenuPlugins->clear();
706  mPluginManager->addPluginActions(mMenuPlugins);
707  }
708 
709  void MainWindow::handleActionExport()
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 
721  void MainWindow::handleActionGatelibraryManager()
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  {
766  ActionOpenNetlistFile* act = new ActionOpenNetlistFile(ActionOpenNetlistFile::OpenProject,
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:
793  handleSaveTriggered();
794  break;
795  }
796  }
797  ExportProjectDialog epd(this);
798  if (epd.exec() == QDialog::Accepted)
799  {
800  epd.exportProject();
801  }
802  }
803 
804  void MainWindow::handleSaveAsTriggered()
805  {
806  QString filename = saveHandler();
807  if (!filename.isEmpty())
808  gContentManager->setWindowTitle(filename);
809  }
810 
811  void MainWindow::handleSaveTriggered()
812  {
813  ProjectManager* pm = ProjectManager::instance();
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 
826  ProjectManager* pm = ProjectManager::instance();
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 
874  void MainWindow::handleActionStartRecording()
875  {
876  mActionStartRecording->setEnabled(false);
877  mActionStopRecording->setEnabled(true);
878  mActionPlayMacro->setEnabled(false);
879  UserActionManager::instance()->setStartRecording();
880  }
881 
882  void MainWindow::handleActionStopRecording()
883  {
884  UserActionManager* uam = UserActionManager::instance();
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 
911  void MainWindow::handleActionPlayMacro()
912  {
913  QString macroFile = QFileDialog::getOpenFileName(this, "Load macro file", ".", "Macro files (*.xml);;All files(*)");
914  if (!macroFile.isEmpty())
915  UserActionManager::instance()->playMacro(macroFile);
916  }
917 
918  void MainWindow::handleActionAbout()
919  {
920  AboutDialog ad;
921  ad.exec();
922  }
923 
924  void MainWindow::handleActionUndo()
925  {
926  UserActionManager::instance()->undoLastAction();
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 
936  void MainWindow::handleActionCloseFile()
937  {
938  if (FileManager::get_instance()->fileOpen())
939  tryToCloseFile();
940  }
941 
942  void MainWindow::onActionQuitTriggered()
943  {
944  close();
945  }
946 
947  void MainWindow::closeEvent(QCloseEvent* event)
948  {
949  if (gFileStatusManager->isGatelibModified() || FileManager::get_instance()->fileOpen())
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 
1008  gPythonContext->abortThreadAndWait();
1009 
1011 
1012  clear();
1013 
1015  // PYTHON ???
1018 
1019  FileManager::get_instance()->closeFile();
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  {
1036  QPoint pos = SettingsManager::instance()->mainWindowPosition();
1037  move(pos);
1038  QSize size = SettingsManager::instance()->mainWindowSize();
1039  resize(size);
1040  //restore state of all subwindows
1041  mLayoutArea->initSplitterSize(size);
1042  }
1043 
1044  void MainWindow::saveState()
1045  {
1046  SettingsManager::instance()->mainWindowSaveGeometry(pos(), size());
1047  }
1048 
1049 
1050 } // 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
Manages the layout of all ContentWidgets.
Manages all ContentWidgets.
void setWindowTitle(const QString &filename)
Abstract class for Widgets within HAL's ContentArea.
Utility class to export (save) different hal files.
static FileManager * get_instance()
void projectOpened(QString projectDir, QString fileName)
void fileOpened(const QString &fileName)
QList< QString > getUnsavedChangeDescriptors() const
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 handleActionAbout()
void handleActionGatelibraryManager()
void handleActionUndo()
void closePluginManager()
void reloadStylsheet(int istyle)
void handleActionStopRecording()
void handleActionStartRecording()
void enableUndo(bool enable=true)
void handleProjectOpened(const QString &projDir, const QString &fileName)
void handleActionPlayMacro()
void onActionQuitTriggered()
void handleFileOpened(const QString &fileName)
void handleActionExport()
static SettingsItemDropdown * sSettingStyle
Definition: main_window.h:302
GuiPluginTable * mGuiPluginTable
Definition: plugin_relay.h:68
std::filesystem::path get_default_filename(const std::string &extension=std::string()) const
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
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)
QString toFileDialog(bool addHalFormat) const
Handles and manages user actions related proccesses.
void canUndoLastAction(bool yesWeCan)
static UserActionManager * instance()
QMessageBox::StandardButton setStopRecording(const QString &macroFilename)
Hal's welcome screen.
#define log_warning(channel,...)
Definition: log.h:76
action
Definition: control.py:16
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.
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: plugin_gui.cpp:80
NetlistRelay * gNetlistRelay
Definition: plugin_gui.cpp:81
This file contains various functions to create and load netlists.
QVariant data() const const
void setDisabled(bool b)
void trigger()
void triggered(bool checked)
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 append(const T &value)
const T & at(int i) const const
int size() const const
QAction * addAction(const QString &text)
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)
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)
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
bool isNull() const const
bool toBool() const const
QString toString() const const
QStringList toStringList() const const
void setStyleSheet(const QString &styleSheet)
void setToolTip(const QString &)