22 #include <QFileSystemWatcher>
23 #include <QGridLayout>
24 #include <QInputDialog>
25 #include <QMessageBox>
26 #include <QPushButton>
27 #include <QSpacerItem>
28 #include <QTextStream>
29 #include <QApplication>
31 #include <QRegularExpression>
33 #include <QJsonDocument>
34 #include <QJsonObject>
40 mSettingAutosave =
new SettingsItemCheckbox(
44 "eXpert Settings:Autosave",
45 "Specifies wheather HAL should autosave."
48 mSettingAutosaveInterval =
new SettingsItemSpinbox(
50 "advanced/autosave_interval",
52 "eXpert Settings:Autosave",
53 "Sets after how much time in seconds an autosave will occur."
56 mAutosaveEnabled = mSettingAutosave->value().toBool();
57 mAutosaveInterval = mSettingAutosaveInterval->value().toInt();
59 if (mAutosaveInterval < 30)
60 mAutosaveInterval = 30;
62 connect(mSettingAutosave, &SettingsItemCheckbox::boolChanged,
this, [
this](
bool value){
63 mAutosaveEnabled = value;
64 if (mTimer->isActive())
65 mTimer->start(mAutosaveInterval * 1000);
68 connect(mSettingAutosaveInterval, &SettingsItemSpinbox::intChanged,
this, [
this](
int value){
69 mAutosaveInterval = value;
70 if (mTimer->isActive())
71 mTimer->start(mAutosaveInterval * 1000);
86 bool FileManager::fileOpen()
const
91 void FileManager::autosave()
94 if (pm->
get_project_status() != ProjectManager::ProjectStatus::NONE && mAutosaveEnabled)
98 log_info(
"gui",
"Autosave deferred while python script is running...");
101 log_info(
"gui",
"saving a backup in case something goes wrong...");
102 if (!ProjectManager::instance()->serialize_project(
gNetlist,
true))
115 void FileManager::watchFile(
const QString& fileName)
117 if (fileName == mFileName)
122 if (!mFileName.isEmpty())
124 mFileWatcher->removePath(mFileName);
125 removeShadowDirectory();
138 mTimer->start(mAutosaveInterval * 1000);
140 mFileName = fileName;
141 mFileWatcher->addPath(mFileName);
143 updateRecentFiles(mFileName);
149 Q_EMIT projectSaved(projectDir, file);
152 void FileManager::projectSuccessfullyLoaded(
QString& projectDir,
QString& file)
155 Q_EMIT projectOpened(projectDir, file);
158 ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::OPENED);
165 if (!info.
exists())
return NotExisting;
172 return InvalidExtension;
192 if (nl.
isEmpty())
return NetlistError;
200 if (!
QFileInfo(
QDir(pathname).absoluteFilePath(nl)).exists())
204 if (gl.
isEmpty())
return GatelibError;
212 if (!
QFileInfo(
QDir(pathname).absoluteFilePath(gl)).exists())
218 return OtherDirectory;
221 return UnknownDirectoryEntry;
229 return QString(
"seems to be a HAL project");
231 return QString(
"no HAL project file found in current directory");
233 return QString(
"entry is not a directory but a file");
235 return QString(
"directory does not exist");
236 case InvalidExtension:
237 return QString(
"HAL project directory must not have an extension");
239 return QString(
"HAL project file parse error");
241 return QString(
"cannot find HAL netlist");
243 return QString(
"cannot find HAL gate library");
244 case UnknownDirectoryEntry:
245 return QString(
"entry is neither directory nor file");
251 void FileManager::fileSuccessfullyLoaded(
QString file)
254 Q_EMIT fileOpened(file);
255 ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::OPENED);
258 void FileManager::removeShadowDirectory()
260 ProjectManager* pm = ProjectManager::instance();
261 if (pm->get_project_status() == ProjectManager::ProjectStatus::NONE)
return;
265 shDir.removeRecursively();
271 void FileManager::newProject()
282 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Cannot create project <" + projdir +
">, no gate library selected");
288 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Cannot create project <" + projdir +
">, cannot load gate library <" + gatelib +
">");
295 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Error creating project directory <" + projdir +
">");
299 QDir projectDir(projdir);
306 gatelib = targetGateLib;
310 LogManager::get_instance()->set_file_name(lpath);
317 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Failed to create <" + projdir +
"> with gate library <" + gatelib +
">");
325 projectSuccessfullyLoaded(projdir,netlistFilename);
329 void FileManager::importFile(
QString filename)
332 QString testProjectExists(filename);
334 if (directoryStatus(testProjectExists) == FileManager::ProjectDirectory)
339 msgBox.
setText(
"A hal project exists for the selected netlist.");
352 openProject(testProjectExists);
368 if (!
QFileInfo(projdir).suffix().isEmpty())
370 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"selected project directory name must not have suffix ." +
QFileInfo(projdir).suffix());
377 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Error creating project directory <" + projdir +
378 ">\nYou might want to try a different name or location");
382 QDir projectDir(projdir);
383 QString netlistFilename = filename;
396 gatelib = targetGateLib;
400 LogManager::get_instance()->set_file_name(lpath);
402 if (deprecatedOpenFile(netlistFilename, gatelib))
416 log_info(
"gui",
"Project directory removed since import failed.");
418 log_warning(
"gui",
"Failed to remove project directory after failed import attempt");
425 void FileManager::moveShadowToProject(
const QDir& shDir)
const
430 QString targetPath(finfo.absoluteFilePath());
431 targetPath.replace(replaceToken,
"/");
436 moveShadowToProject(
QDir(finfo.absoluteFilePath()));
438 else if (finfo.isFile())
442 log_info(
"gui",
"File restored from autosave: {}.", targetPath.toStdString());
446 log_info(
"gui",
"Cannot move {} from autosave to project directory.", finfo.absoluteFilePath().toStdString());
451 void FileManager::openProject(
QString projPath)
461 "It seems that HAL crashed during your last session. Last autosave was on " +
465 moveShadowToProject(shDir);
470 ProjectJson projFile(
QDir(projPath).absoluteFilePath(
".project.json"));
480 displayErrorMessage(errorMsg);
487 projectSuccessfullyLoaded(projPath, filename);
492 LogManager::get_instance()->set_file_name(lpath);
497 QString logical_file_name = filename;
510 QString errorMsg(
"Unable to open file. File name is empty");
512 displayErrorMessage(errorMsg);
516 QFile file(filename);
520 std::string error_message(
"Unable to open file" + filename.
toStdString());
521 log_error(
"gui",
"Unable to open file '{}'", error_message);
527 if (nlInfo.
suffix()==
"hal")
540 fileSuccessfullyLoaded(logical_file_name);
546 std::string error_message(
"Failed to create netlist from .hal file");
559 if (!gatelibraryPath.
isEmpty())
573 fileSuccessfullyLoaded(logical_file_name);
580 displayErrorMessage(
"Failed to open netlist\nwith user selected gate library\n"+gatelibraryPath);
601 fileSuccessfullyLoaded(logical_file_name);
611 log_info(
"gui",
"Searching for (other) compatible netlists.");
619 if (netlists.empty())
621 std::string error_message(
"Unable to find a compatible gate library. Deserialization failed!");
626 else if (netlists.size() == 1)
628 log_info(
"gui",
"One compatible gate library found.");
636 log_info(
"gui",
"{} compatible gate libraries found. User has to select one.", netlists.size());
641 for (
auto& n : netlists)
648 dialog.
setLabelText(
"The specified file can be processed with more than one gate library. Please select which library should be used:");
652 std::string selection = dialog.
textValue().toStdString();
654 for (
auto& n : netlists)
656 if (n->get_gate_library()->get_name() == selection)
671 fileSuccessfullyLoaded(logical_file_name);
675 void FileManager::closeFile()
681 Q_EMIT fileAboutToClose(mFileName);
686 mFileWatcher->removePath(mFileName);
690 removeShadowDirectory();
696 ProjectManager::instance()->set_project_status(ProjectManager::ProjectStatus::NONE);
701 void FileManager::handleFileChanged(
const QString& path)
703 Q_EMIT fileChanged(path);
706 void FileManager::handleDirectoryChanged(
const QString& path)
708 Q_EMIT fileDirectoryChanged(path);
711 void FileManager::updateRecentFiles(
const QString& file)
const
716 for (
int i = 0; i < 14; ++i)
740 std::vector<std::filesystem::path> files;
743 std::filesystem::path file_path(
string.toStdString());
745 for (
const auto& other : files)
747 if (std::filesystem::equivalent(file_path, other))
765 void FileManager::displayErrorMessage(
QString error_message)
void handleOpenDocument(const QString &fileName)
Stores information about the currently opened netlist.
void loadFeature(FacExtensionInterface::Feature ft, const QString &extension=QString())
bool isCopyGatelibChecked() const
QString projectDirectory() const
QString gateLibraryPath() const
bool isMoveNetlistChecked() const
void registerNetlistCallbacks()
void unregisterNetlistCallbacks()
void debugHandleFileClosed()
void debugHandleFileOpened()
bool isCopyGatelibChecked() const
QString projectDirectory() const
QString gateLibraryPath() const
GuiPluginTable * mGuiPluginTable
std::filesystem::path get_default_filename(const std::string &extension=std::string()) const
std::filesystem::path get_shadow_dir() const
QString gateLibraryFilename() const
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
bool remove_project_directory()
void set_project_directory(const std::string &path)
PythonThread * pythonThread() const
#define log_error(channel,...)
#define log_info(channel,...)
#define log_warning(channel,...)
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)
PythonContext * gPythonContext
ContentManager * gContentManager
PluginRelay * gPluginRelay
FileStatusManager * gFileStatusManager
NetlistRelay * gNetlistRelay
std::shared_ptr< Netlist > gNetlistOwner
This file contains various functions to create and load netlists.
QString toString(Qt::DateFormat format) const const
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 exists() const const
QString fileName() 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 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)
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 setWindowTitle(const QString &title)
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 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
QString toString() const const