- fix: Crash when a project is removed from the disk while it is openned in RedPanda-C++.

This commit is contained in:
Roy Qu 2023-03-19 20:51:12 +08:00
parent 56cd6c4d76
commit b951ac6636
10 changed files with 516 additions and 439 deletions

View File

@ -2,6 +2,7 @@ Red Panda C++ Version 2.19
- fix: Crash when directive line ends with '\' and at the last line. - fix: Crash when directive line ends with '\' and at the last line.
- fix: The option "Minimal indent for a continuous conditional beloning to a conditional header:" for formatter is not correct. - fix: The option "Minimal indent for a continuous conditional beloning to a conditional header:" for formatter is not correct.
- fix: Crash when a project is removed from the disk while it is openned in RedPanda-C++.
Red Panda C++ Version 2.18 Red Panda C++ Version 2.18

View File

@ -1430,10 +1430,11 @@ void Editor::hideEvent(QHideEvent */*event*/)
this, this,
&Editor::onEndParsing); &Editor::onEndParsing);
} }
pMainWindow->updateForEncodingInfo(nullptr); if (!pMainWindow->isQuitting()) {
pMainWindow->updateStatusbarForLineCol(nullptr); pMainWindow->updateForEncodingInfo(nullptr);
pMainWindow->updateForStatusbarModeInfo(nullptr); pMainWindow->updateStatusbarForLineCol(nullptr);
pMainWindow->updateForStatusbarModeInfo(nullptr);
}
setHideTime(QDateTime::currentDateTime()); setHideTime(QDateTime::currentDateTime());
} }

View File

@ -185,8 +185,12 @@ bool EditorList::closeEditor(Editor* editor, bool transferFocus, bool force) {
// } // }
if (editor->inProject() && pMainWindow->project()) { if (editor->inProject() && pMainWindow->project()) {
PProjectUnit unit = pMainWindow->project()->findUnit(editor); if (fileExists(pMainWindow->project()->directory())) {
pMainWindow->project()->closeUnit(unit); PProjectUnit unit = pMainWindow->project()->findUnit(editor);
pMainWindow->project()->closeUnit(unit);
} else {
editor->setProject(nullptr);
}
} else { } else {
if (!editor->isNew() && pMainWindow->visitHistoryManager()->addFile(editor->filename())) { if (!editor->isNew() && pMainWindow->visitHistoryManager()->addFile(editor->filename())) {
pMainWindow->rebuildOpenedFileHisotryMenu(); pMainWindow->rebuildOpenedFileHisotryMenu();

View File

@ -402,6 +402,8 @@ MainWindow::MainWindow(QWidget *parent)
connect(&mFileSystemWatcher,&QFileSystemWatcher::fileChanged, connect(&mFileSystemWatcher,&QFileSystemWatcher::fileChanged,
this, &MainWindow::onFileChanged); this, &MainWindow::onFileChanged);
connect(&mFileSystemWatcher,&QFileSystemWatcher::directoryChanged,
this, &MainWindow::onDirChanged);
mStatementColors = std::make_shared<QHash<StatementKind, PColorSchemeItem> >(); mStatementColors = std::make_shared<QHash<StatementKind, PColorSchemeItem> >();
mCompletionPopup = std::make_shared<CodeCompletionPopup>(); mCompletionPopup = std::make_shared<CodeCompletionPopup>();
@ -463,6 +465,8 @@ MainWindow::MainWindow(QWidget *parent)
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
mQuitting=true; mQuitting=true;
if (mProject)
mProject=nullptr;
delete mProjectProxyModel; delete mProjectProxyModel;
delete mEditorList; delete mEditorList;
delete ui; delete ui;
@ -5106,51 +5110,56 @@ void MainWindow::closeProject(bool refreshEditor)
//save all files //save all files
// TODO: should we save watches? // TODO: should we save watches?
if (mEditorList->projectEditorsModified()) { if (fileExists(mProject->directory())){
QString s; if (mEditorList->projectEditorsModified()) {
if (mProject->name().isEmpty()) { QString s;
s = mProject->filename(); if (mProject->name().isEmpty()) {
} else { s = mProject->filename();
s = mProject->name(); } else {
} s = mProject->name();
if (mSystemTurnedOff) { }
mProject->saveAll(); if (mSystemTurnedOff) {
mEditorList->saveAllForProject();
} else {
int answer = QMessageBox::question(
this,
tr("Save project"),
tr("The project '%1' has modifications.").arg(s)
+ "<br />"
+ tr("Do you want to save it?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Yes);
switch (answer) {
case QMessageBox::Yes:
mProject->saveAll(); mProject->saveAll();
mEditorList->saveAllForProject(); mEditorList->saveAllForProject();
break; } else {
case QMessageBox::No: int answer = QMessageBox::question(
mEditorList->clearProjectEditorsModified(); this,
mProject->setModified(false); tr("Save project"),
mProject->saveLayout(); tr("The project '%1' has modifications.").arg(s)
break; + "<br />"
case QMessageBox::Cancel: + tr("Do you want to save it?"),
mProject->saveLayout(); QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
return; QMessageBox::Yes);
switch (answer) {
case QMessageBox::Yes:
mProject->saveAll();
mEditorList->saveAllForProject();
break;
case QMessageBox::No:
mEditorList->clearProjectEditorsModified();
mProject->setModified(false);
mProject->saveLayout();
break;
case QMessageBox::Cancel:
mProject->saveLayout();
return;
}
} }
} } else
} else mProject->saveAll(); // always save layout, but not when SaveAll has been called
mProject->saveAll(); // always save layout, but not when SaveAll has been called }
mClosingProject=true; mClosingProject=true;
mBookmarkModel->saveProjectBookmarks(
changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT),
mProject->directory());
mDebugger->saveForProject( if (fileExists(mProject->directory())){
changeFileExt(mProject->filename(), PROJECT_DEBUG_EXT), mBookmarkModel->saveProjectBookmarks(
mProject->directory()); changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT),
mProject->directory());
mDebugger->saveForProject(
changeFileExt(mProject->filename(), PROJECT_DEBUG_EXT),
mProject->directory());
}
mClassBrowserModel.beginUpdate(); mClassBrowserModel.beginUpdate();
// Remember it // Remember it
@ -5251,6 +5260,22 @@ void MainWindow::onFileChanged(const QString &path)
mFilesChangedNotifying.remove(path); mFilesChangedNotifying.remove(path);
} }
void MainWindow::onDirChanged(const QString &path)
{
if (mFilesChangedNotifying.contains(path))
return;
mFilesChangedNotifying.insert(path);
if (mProject && QString::compare(mProject->directory(),path,PATH_SENSITIVITY)==0
&& !fileExists(path)) {
QMessageBox::information(this,tr("Project folder removed."),
tr("Folder for project '%1' was removed.").arg(path)
+"<BR /><BR />"
+ tr("It will be closed."));
closeProject(false);
}
mFilesChangedNotifying.remove(path);
}
void MainWindow::onFilesViewPathChanged() void MainWindow::onFilesViewPathChanged()
{ {
QString filesPath = ui->cbFilesPath->currentText(); QString filesPath = ui->cbFilesPath->currentText();

View File

@ -340,6 +340,7 @@ private slots:
void onEditorRenamed(const QString &oldFilename, const QString &newFilename, bool firstSave); void onEditorRenamed(const QString &oldFilename, const QString &newFilename, bool firstSave);
void onAutoSaveTimeout(); void onAutoSaveTimeout();
void onFileChanged(const QString &path); void onFileChanged(const QString &path);
void onDirChanged(const QString &path);
void onFilesViewPathChanged(); void onFilesViewPathChanged();
void onWatchViewContextMenu(const QPoint& pos); void onWatchViewContextMenu(const QPoint& pos);
void onBookmarkContextMenu(const QPoint& pos); void onBookmarkContextMenu(const QPoint& pos);

View File

@ -61,6 +61,7 @@ Project::Project(const QString &filename, const QString &name,
std::bind( std::bind(
&EditorList::getContentFromOpenedEditor,mEditorList, &EditorList::getContentFromOpenedEditor,mEditorList,
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
mFileSystemWatcher->addPath(directory());
} }
std::shared_ptr<Project> Project::load(const QString &filename, EditorList *editorList, QFileSystemWatcher *fileSystemWatcher, QObject *parent) std::shared_ptr<Project> Project::load(const QString &filename, EditorList *editorList, QFileSystemWatcher *fileSystemWatcher, QObject *parent)
@ -103,12 +104,14 @@ std::shared_ptr<Project> Project::create(
Project::~Project() Project::~Project()
{ {
mFileSystemWatcher->removePath(directory());
mEditorList->beginUpdate(); mEditorList->beginUpdate();
foreach (const PProjectUnit& unit, mUnits) { foreach (const PProjectUnit& unit, mUnits) {
Editor * editor = unitEditor(unit); Editor * editor = unitEditor(unit);
if (editor) { if (editor) {
editor->setProject(nullptr); editor->setProject(nullptr);
mEditorList->forceCloseEditor(editor); if (fileExists(directory()))
mEditorList->forceCloseEditor(editor);
} }
} }
mEditorList->endUpdate(); mEditorList->endUpdate();
@ -259,15 +262,15 @@ void Project::open()
} }
} }
void Project::setFileName(QString value) //void Project::setFileName(QString value)
{ //{
value = QFileInfo(value).absoluteFilePath(); // value = QFileInfo(value).absoluteFilePath();
if (mFilename!=value) { // if (mFilename!=value) {
QFile::rename(mFilename,value); // QFile::rename(mFilename,value);
mFilename = value; // mFilename = value;
setModified(true); // setModified(true);
} // }
} //}
void Project::setModified(bool value) void Project::setModified(bool value)
{ {
@ -611,6 +614,9 @@ void Project::saveAll()
void Project::saveLayout() void Project::saveLayout()
{ {
if (!fileExists(directory()))
return;
QHash<QString, PProjectEditorLayout> oldLayouts = loadLayout(); QHash<QString, PProjectEditorLayout> oldLayouts = loadLayout();
QHash<QString,int> editorOrderSet; QHash<QString,int> editorOrderSet;
@ -669,9 +675,6 @@ void Project::saveLayout()
QJsonDocument doc(jsonLayouts); QJsonDocument doc(jsonLayouts);
file.write(doc.toJson(QJsonDocument::Indented)); file.write(doc.toJson(QJsonDocument::Indented));
file.close(); file.close();
} else {
throw FileError(QObject::tr("Can't open file '%1' for write.")
.arg(jsonFilename));
} }
} }
@ -711,6 +714,8 @@ void Project::renameUnit(PProjectUnit& unit, const QString &newFileName)
bool Project::saveUnits() bool Project::saveUnits()
{ {
if (!fileExists(directory()))
return false;
int count = 0; int count = 0;
SimpleIni ini; SimpleIni ini;
SI_Error error = ini.LoadFile(mFilename.toLocal8Bit()); SI_Error error = ini.LoadFile(mFilename.toLocal8Bit());
@ -1140,6 +1145,8 @@ void Project::setEncoding(const QByteArray &encoding)
void Project::saveOptions() void Project::saveOptions()
{ {
if (!fileExists(directory()))
return;
SimpleIni ini; SimpleIni ini;
ini.LoadFile(mFilename.toLocal8Bit()); ini.LoadFile(mFilename.toLocal8Bit());
ini.SetValue("Project","FileName", toByteArray(extractRelativePath(directory(), mFilename))); ini.SetValue("Project","FileName", toByteArray(extractRelativePath(directory(), mFilename)));

View File

@ -218,7 +218,7 @@ public:
bool unitsModifiedSince(const QDateTime& time); bool unitsModifiedSince(const QDateTime& time);
bool modified() const; bool modified() const;
bool modifiedSince(const QDateTime& time); bool modifiedSince(const QDateTime& time);
void setFileName(QString value); // void setFileName(QString value);
void setModified(bool value); void setModified(bool value);
PProjectModelNode addFolder(PProjectModelNode parentFolder, const QString& s); PProjectModelNode addFolder(PProjectModelNode parentFolder, const QString& s);

View File

@ -5187,6 +5187,18 @@
<source>Save settings failed!</source> <source>Save settings failed!</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Project folder removed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Folder for project &apos;%1&apos; was removed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>It will be closed.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MemoryModel</name> <name>MemoryModel</name>

File diff suppressed because it is too large Load Diff

View File

@ -4920,6 +4920,18 @@
<source>F11</source> <source>F11</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Project folder removed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Folder for project &apos;%1&apos; was removed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>It will be closed.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MemoryModel</name> <name>MemoryModel</name>