23 #include <QFileSystemWatcher>
24 #include <QGridLayout>
25 #include <QInputDialog>
26 #include <QMessageBox>
27 #include <QPushButton>
28 #include <QSpacerItem>
29 #include <QTextStream>
30 #include <QApplication>
32 #include <QRegularExpression>
34 #include <QJsonDocument>
35 #include <QJsonObject>
41 mSettingAutosave =
new SettingsItemCheckbox(
45 "eXpert Settings:Autosave",
46 "Specifies wheather HAL should autosave."
49 mSettingAutosaveInterval =
new SettingsItemSpinbox(
51 "advanced/autosave_interval",
53 "eXpert Settings:Autosave",
54 "Sets after how much time in seconds an autosave will occur."
57 mAutosaveEnabled = mSettingAutosave->value().toBool();
58 mAutosaveInterval = mSettingAutosaveInterval->value().toInt();
60 if (mAutosaveInterval < 30)
61 mAutosaveInterval = 30;
63 connect(mSettingAutosave, &SettingsItemCheckbox::boolChanged,
this, [
this](
bool value){
64 mAutosaveEnabled = value;
65 if (mTimer->isActive())
66 mTimer->start(mAutosaveInterval * 1000);
69 connect(mSettingAutosaveInterval, &SettingsItemSpinbox::intChanged,
this, [
this](
int value){
70 mAutosaveInterval = value;
71 if (mTimer->isActive())
72 mTimer->start(mAutosaveInterval * 1000);
87 bool FileManager::fileOpen()
const
92 void FileManager::autosave()
95 if (pm->
get_project_status() != ProjectManager::ProjectStatus::NONE && mAutosaveEnabled)
99 log_info(
"gui",
"Autosave deferred while python script is running...");
102 log_info(
"gui",
"saving a backup in case something goes wrong...");
116 void FileManager::watchFile(
const QString& fileName)
118 if (fileName == mFileName)
123 if (!mFileName.isEmpty())
125 mFileWatcher->removePath(mFileName);
126 removeShadowDirectory();
139 mTimer->start(mAutosaveInterval * 1000);
141 mFileName = fileName;
142 mFileWatcher->addPath(mFileName);
144 updateRecentFiles(mFileName);
150 Q_EMIT projectSaved(projectDir, file);
153 void FileManager::projectSuccessfullyLoaded(
QString& projectDir,
QString& file)
156 Q_EMIT projectOpened(projectDir, file);
166 if (!info.
exists())
return NotExisting;
173 return InvalidExtension;
193 if (nl.
isEmpty())
return NetlistError;
201 if (!
QFileInfo(
QDir(pathname).absoluteFilePath(nl)).exists())
205 if (gl.
isEmpty())
return GatelibError;
213 if (!
QFileInfo(
QDir(pathname).absoluteFilePath(gl)).exists())
219 return OtherDirectory;
222 return UnknownDirectoryEntry;
230 return QString(
"seems to be a HAL project");
232 return QString(
"no HAL project file found in current directory");
234 return QString(
"entry is not a directory but a file");
236 return QString(
"directory does not exist");
237 case InvalidExtension:
238 return QString(
"HAL project directory must not have an extension");
240 return QString(
"HAL project file parse error");
242 return QString(
"cannot find HAL netlist");
244 return QString(
"cannot find HAL gate library");
245 case UnknownDirectoryEntry:
246 return QString(
"entry is neither directory nor file");
252 void FileManager::fileSuccessfullyLoaded(
QString file)
255 Q_EMIT fileOpened(file);
259 void FileManager::removeShadowDirectory()
262 if (pm->get_project_status() == ProjectManager::ProjectStatus::NONE)
return;
266 shDir.removeRecursively();
272 void FileManager::newProject()
283 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Cannot create project <" + projdir +
">, no gate library selected");
290 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Cannot create project <" + projdir +
">, cannot load gate library <" + gatelib +
">");
297 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Error creating project directory <" + projdir +
">");
301 QDir projectDir(projdir);
308 gatelib = targetGateLib;
312 LogManager::get_instance()->set_file_name(lpath);
319 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Failed to create <" + projdir +
"> with gate library <" + gatelib +
">");
327 projectSuccessfullyLoaded(projdir,netlistFilename);
331 void FileManager::importFile(
QString filename)
334 QString testProjectExists(filename);
336 if (directoryStatus(testProjectExists) == FileManager::ProjectDirectory)
341 msgBox.
setText(
"A hal project exists for the selected netlist.");
354 openProject(testProjectExists);
370 if (!
QFileInfo(projdir).suffix().isEmpty())
372 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"selected project directory name must not have suffix ." +
QFileInfo(projdir).suffix());
379 QMessageBox::warning(qApp->activeWindow(),
"Aborted",
"Error creating project directory <" + projdir +
380 ">\nYou might want to try a different name or location");
384 QDir projectDir(projdir);
385 QString netlistFilename = filename;
398 gatelib = targetGateLib;
402 LogManager::get_instance()->set_file_name(lpath);
404 if (deprecatedOpenFile(netlistFilename, gatelib))
418 log_info(
"gui",
"Project directory removed since import failed.");
420 log_warning(
"gui",
"Failed to remove project directory after failed import attempt");
427 void FileManager::moveShadowToProject(
const QDir& shDir)
const
432 QString targetPath(finfo.absoluteFilePath());
433 targetPath.replace(replaceToken,
"/");
438 moveShadowToProject(
QDir(finfo.absoluteFilePath()));
440 else if (finfo.isFile())
444 log_info(
"gui",
"File restored from autosave: {}.", targetPath.toStdString());
448 log_info(
"gui",
"Cannot move {} from autosave to project directory.", finfo.absoluteFilePath().toStdString());
453 void FileManager::openProject(
QString projPath)
463 "It seems that HAL crashed during your last session. Last autosave was on " +
467 moveShadowToProject(shDir);
472 ProjectJson projFile(
QDir(projPath).absoluteFilePath(
".project.json"));
480 loadGateLibrary(glPath);
486 displayErrorMessage(errorMsg);
493 projectSuccessfullyLoaded(projPath, filename);
498 LogManager::get_instance()->set_file_name(lpath);
503 QString logical_file_name = filename;
516 QString errorMsg(
"Unable to open file. File name is empty");
518 displayErrorMessage(errorMsg);
522 QFile file(filename);
526 std::string error_message(
"Unable to open file" + filename.
toStdString());
527 log_error(
"gui",
"Unable to open file '{}'", error_message);
533 if (nlInfo.
suffix()==
"hal")
546 fileSuccessfullyLoaded(logical_file_name);
552 std::string error_message(
"Failed to create netlist from .hal file");
565 if (!gatelibraryPath.
isEmpty())
573 loadGateLibrary(gatelibraryPath);
581 fileSuccessfullyLoaded(logical_file_name);
588 displayErrorMessage(
"Failed to open netlist\nwith user selected gate library\n"+gatelibraryPath);
609 fileSuccessfullyLoaded(logical_file_name);
619 log_info(
"gui",
"Searching for (other) compatible netlists.");
627 if (netlists.empty())
629 std::string error_message(
"Unable to find a compatible gate library. Deserialization failed!");
634 else if (netlists.size() == 1)
636 log_info(
"gui",
"One compatible gate library found.");
644 log_info(
"gui",
"{} compatible gate libraries found. User has to select one.", netlists.size());
649 for (
auto& n : netlists)
656 dialog.
setLabelText(
"The specified file can be processed with more than one gate library. Please select which library should be used:");
660 std::string selection = dialog.
textValue().toStdString();
662 for (
auto& n : netlists)
664 if (n->get_gate_library()->get_name() == selection)
679 fileSuccessfullyLoaded(logical_file_name);
683 void FileManager::closeFile()
689 Q_EMIT fileAboutToClose(mFileName);
694 mFileWatcher->removePath(mFileName);
698 removeShadowDirectory();
709 void FileManager::handleFileChanged(
const QString& path)
711 Q_EMIT fileChanged(path);
714 void FileManager::handleDirectoryChanged(
const QString& path)
716 Q_EMIT fileDirectoryChanged(path);
719 void FileManager::updateRecentFiles(
const QString& file)
const
724 for (
int i = 0; i < 14; ++i)
748 std::vector<std::filesystem::path> files;
751 std::filesystem::path file_path(
string.toStdString());
753 for (
const auto& other : files)
755 if (std::filesystem::equivalent(file_path, other))
779 if (glib || !glInfo.
isFile() || GateLibraryParser::get_parse_status() != GateLibraryParser::ParseStatus::NeedsUpgrade)
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.")
789 GateLibraryParser::request_upgrade();
793 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.
std::unique_ptr< BasePluginInterface > instance
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
QString completeBaseName() const const
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