diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp
index a2401e3627..93329fea62 100644
--- a/app/src/mainwindow2.cpp
+++ b/app/src/mainwindow2.cpp
@@ -1,4 +1,4 @@
-/*
+/*
Pencil - Traditional Animation Software
Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
@@ -132,9 +132,6 @@ MainWindow2::MainWindow2(QWidget* parent) :
ui->background->init(mEditor->preference());
setWindowTitle(PENCIL_WINDOW_TITLE);
-
- if (!loadMostRecent())
- tryLoadPreset();
}
MainWindow2::~MainWindow2()
@@ -519,6 +516,19 @@ void MainWindow2::closeEvent(QCloseEvent* event)
}
}
+void MainWindow2::showEvent(QShowEvent*)
+{
+ static bool firstShowEvent = true;
+ if (firstShowEvent)
+ {
+ firstShowEvent = false;
+ if (tryRecoverUnsavedProject()) { return; }
+ if (loadMostRecent()) { return; }
+ if (tryLoadPreset()) { return; }
+ newObject();
+ }
+}
+
void MainWindow2::tabletEvent(QTabletEvent* event)
{
event->ignore();
@@ -528,7 +538,10 @@ void MainWindow2::newDocument()
{
if (maybeSave())
{
- tryLoadPreset();
+ if (!tryLoadPreset())
+ {
+ newObject();
+ }
}
}
@@ -641,7 +654,7 @@ bool MainWindow2::openObject(QString strFilePath)
dd.collect(error.details());
ErrorDialog errorDialog(error.title(), error.description(), dd.str());
errorDialog.exec();
- newEmptyDocumentAfterErrorOccurred();
+ emptyDocumentWhenErrorOccurred();
return false;
}
@@ -651,7 +664,7 @@ bool MainWindow2::openObject(QString strFilePath)
tr("An unknown error occurred while trying to load the file and we are not able to load your file."),
QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fullPath));
errorDialog.exec();
- newEmptyDocumentAfterErrorOccurred();
+ emptyDocumentWhenErrorOccurred();
return false;
}
@@ -816,7 +829,7 @@ bool MainWindow2::autoSave()
return false;
}
-void MainWindow2::newEmptyDocumentAfterErrorOccurred()
+void MainWindow2::emptyDocumentWhenErrorOccurred()
{
newObject();
@@ -1062,19 +1075,21 @@ bool MainWindow2::newObject()
bool MainWindow2::newObjectFromPresets(int presetIndex)
{
Object* object = nullptr;
- QString presetFilePath = (presetIndex > 0) ? PresetDialog::getPresetPath(presetIndex) : "";
- if (!presetFilePath.isEmpty())
+ QString presetFilePath = PresetDialog::getPresetPath(presetIndex);
+
+ if (presetFilePath.isEmpty())
{
- FileManager fm(this);
- object = fm.load(presetFilePath);
- if (fm.error().ok() == false) object = nullptr;
+ return false;
}
- if (object == nullptr)
+
+ FileManager fm(this);
+ object = fm.load(presetFilePath);
+
+ if (fm.error().ok() == false || object == nullptr)
{
- object = new Object();
- object->init();
- object->createDefaultLayers();
+ return false;
}
+
mEditor->setObject(object);
object->setFilePath(QString());
@@ -1099,7 +1114,7 @@ bool MainWindow2::loadMostRecent()
return false;
}
-void MainWindow2::tryLoadPreset()
+bool MainWindow2::tryLoadPreset()
{
if (mEditor->preference()->isOn(SETTING::ASK_FOR_PRESET))
{
@@ -1110,12 +1125,15 @@ void MainWindow2::tryLoadPreset()
if (result == QDialog::Accepted)
{
int presetIndex = presetDialog->getPresetIndex();
- if (presetDialog->shouldAlwaysUse()) {
+ if (presetDialog->shouldAlwaysUse())
+ {
mEditor->preference()->set(SETTING::ASK_FOR_PRESET, false);
mEditor->preference()->set(SETTING::DEFAULT_PRESET, presetIndex);
}
- newObjectFromPresets(presetIndex);
- qDebug() << "Accepted!";
+ if (!newObjectFromPresets(presetIndex))
+ {
+ newObject();
+ }
}
});
presetDialog->open();
@@ -1123,8 +1141,9 @@ void MainWindow2::tryLoadPreset()
else
{
int defaultPreset = mEditor->preference()->getInt(SETTING::DEFAULT_PRESET);
- newObjectFromPresets(defaultPreset);
+ return newObjectFromPresets(defaultPreset);
}
+ return true;
}
void MainWindow2::readSettings()
@@ -1541,3 +1560,66 @@ void MainWindow2::displayMessageBoxNoTitle(const QString& body)
{
QMessageBox::information(this, nullptr, tr(qPrintable(body)), QMessageBox::Ok);
}
+
+bool MainWindow2::tryRecoverUnsavedProject()
+{
+ FileManager fm;
+ QStringList recoverables = fm.searchForUnsavedProjects();
+
+ if (recoverables.size() == 0)
+ {
+ return false;
+ }
+
+ QString caption = tr("Restore Project?");
+ QString text = tr("Pencil2D didn't close correctly. Would you like to restore the project?");
+
+ QString recoverPath = recoverables[0];
+
+ QMessageBox* msgBox = new QMessageBox(this);
+ msgBox->setWindowTitle(tr("Restore project"));
+ msgBox->setWindowModality(Qt::ApplicationModal);
+ msgBox->setAttribute(Qt::WA_DeleteOnClose);
+ msgBox->setIconPixmap(QPixmap(":/icons/logo.png"));
+ msgBox->setText(QString("
%1 %2").arg(caption).arg(text));
+ msgBox->setInformativeText(QString("%1 ").arg(retrieveProjectNameFromTempPath(recoverPath)));
+ msgBox->setStandardButtons(QMessageBox::Open | QMessageBox::Discard);
+ msgBox->setProperty("RecoverPath", recoverPath);
+ hideQuestionMark(*msgBox);
+
+ connect(msgBox, &QMessageBox::finished, this, &MainWindow2::startProjectRecovery);
+ msgBox->open();
+ return true;
+}
+
+void MainWindow2::startProjectRecovery(int result)
+{
+ const QMessageBox* msgBox = dynamic_cast(QObject::sender());
+ const QString recoverPath = msgBox->property("RecoverPath").toString();
+
+ if (result == QMessageBox::Discard)
+ {
+ // The user presses discard
+ QDir(recoverPath).removeRecursively();
+ tryLoadPreset();
+ return;
+ }
+ Q_ASSERT(result == QMessageBox::Open);
+
+ FileManager fm;
+ Object* o = fm.recoverUnsavedProject(recoverPath);
+ if (!fm.error().ok())
+ {
+ Q_ASSERT(o == nullptr);
+ const QString title = tr("Recovery Failed.");
+ const QString text = tr("Sorry! Pencil2D is unable to restore your project");
+ QMessageBox::information(this, title, QString("%1 %2").arg(title).arg(text));
+ }
+
+ mEditor->setObject(o);
+ updateSaveState();
+
+ const QString title = tr("Recovery Succeeded!");
+ const QString text = tr("Please save your work immediately to prevent loss of data");
+ QMessageBox::information(this, title, QString("%1 %2").arg(title).arg(text));
+}
diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h
index c3d4f3bb32..07adc52232 100644
--- a/app/src/mainwindow2.h
+++ b/app/src/mainwindow2.h
@@ -77,7 +77,7 @@ public slots:
bool saveAsNewDocument();
bool maybeSave();
bool autoSave();
- void newEmptyDocumentAfterErrorOccurred();
+ void emptyDocumentWhenErrorOccurred();
// import
void importImage();
@@ -96,7 +96,7 @@ public slots:
void setSoundScrubMsec(int msec);
void setOpacity(int opacity);
void preferences();
-
+
void openFile(QString filename);
PreferencesDialog* getPrefDialog() { return mPrefDialog; }
@@ -111,6 +111,7 @@ public slots:
protected:
void tabletEvent(QTabletEvent*) override;
void closeEvent(QCloseEvent*) override;
+ void showEvent(QShowEvent*) override;
private slots:
void resetAndDockAllSubWidgets();
@@ -128,7 +129,7 @@ private slots:
void clearKeyboardShortcuts();
void updateZoomLabel();
bool loadMostRecent();
- void tryLoadPreset();
+ bool tryLoadPreset();
void openPalette();
void importPalette();
@@ -151,6 +152,9 @@ private slots:
void bindActionWithSetting(QAction*, const SETTING&);
+ bool tryRecoverUnsavedProject();
+ void startProjectRecovery(int result);
+
// UI: Dock widgets
ColorBox* mColorBox = nullptr;
ColorPaletteWidget* mColorPalette = nullptr;
@@ -182,7 +186,6 @@ private slots:
// whether we are currently importing an image sequence.
bool mIsImportingImageSequence = false;
-// bool mLoadMostRecent = true;
Ui::MainWindow2* ui = nullptr;
};
diff --git a/app/src/presetdialog.cpp b/app/src/presetdialog.cpp
index db738bb9c7..d7623a9d4f 100644
--- a/app/src/presetdialog.cpp
+++ b/app/src/presetdialog.cpp
@@ -45,11 +45,19 @@ bool PresetDialog::shouldAlwaysUse()
QString PresetDialog::getPresetPath(int index)
{
- QString filename = QString("%1.pclx").arg(index);
+ if (index == 0)
+ {
+ return QString();
+ }
+
+ const QString filename = QString("%1.pclx").arg(index);
QDir dataDir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (dataDir.cd("presets"))
{
- return dataDir.filePath(filename);
+ if (dataDir.exists(filename))
+ {
+ return dataDir.filePath(filename);
+ }
}
return QString();
}
@@ -77,7 +85,7 @@ void PresetDialog::initPresets()
return;
}
QSettings presets(dataDir.filePath("presets.ini"), QSettings::IniFormat, this);
-
+
bool ok = true;
for (const QString& key : presets.allKeys())
{
diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp
index 1ab0e78b0e..f60c74e81c 100644
--- a/core_lib/src/structure/filemanager.cpp
+++ b/core_lib/src/structure/filemanager.cpp
@@ -630,3 +630,246 @@ Status FileManager::verifyObject(Object* obj)
}
return Status::OK;
}
+
+QStringList FileManager::searchForUnsavedProjects()
+{
+ QDir pencil2DTempDir = QDir::temp();
+ bool folderExists = pencil2DTempDir.cd("Pencil2D");
+ if (!folderExists)
+ {
+ return QStringList();
+ }
+
+ const QStringList nameFilter("*_" PFF_TMP_DECOMPRESS_EXT "_*"); // match name pattern like "Default_Y2xD_0a4e44e9"
+ QStringList entries = pencil2DTempDir.entryList(nameFilter, QDir::Dirs | QDir::Readable);
+
+ QStringList recoverables;
+ for (const QString path : entries)
+ {
+ QString fullPath = pencil2DTempDir.filePath(path);
+ if (isProjectRecoverable(fullPath))
+ {
+ qDebug() << "Found debris at" << fullPath;
+ recoverables.append(fullPath);
+ }
+ }
+ return recoverables;
+}
+
+bool FileManager::isProjectRecoverable(const QString& projectFolder)
+{
+ QDir dir(projectFolder);
+ if (!dir.exists()) { return false; }
+
+ // There must be a subfolder called "data"
+ if (!dir.exists("data")) { return false; }
+
+ bool ok = dir.cd("data");
+ Q_ASSERT(ok);
+
+ QStringList nameFiler;
+ nameFiler << "*.png" << "*.vec" << "*.xml";
+ QStringList entries = dir.entryList(nameFiler, QDir::Files);
+
+ return (entries.size() > 0);
+}
+
+Object* FileManager::recoverUnsavedProject(QString intermeidatePath)
+{
+ qDebug() << "TODO: recover project" << intermeidatePath;
+
+ QDir projectDir(intermeidatePath);
+ const QString mainXMLPath = projectDir.filePath(PFF_XML_FILE_NAME);
+ const QString dataFolder = projectDir.filePath(PFF_DATA_DIR);
+
+ std::unique_ptr object(new Object);
+ object->setWorkingDir(intermeidatePath);
+ object->setMainXMLFile(mainXMLPath);
+ object->setDataDir(dataFolder);
+
+ Status st = recoverObject(object.get());
+ if (!st.ok())
+ {
+ mError = st;
+ return nullptr;
+ }
+ // Transfer ownership to the caller
+ return object.release();
+}
+
+Status FileManager::recoverObject(Object* object)
+{
+ // Check whether the main.xml is fine, if not we should make a valid one.
+ bool mainXmlOK = true;
+
+ QFile file(object->mainXMLFile());
+ mainXmlOK &= file.exists();
+ mainXmlOK &= file.open(QFile::ReadOnly);
+ file.close();
+
+ QDomDocument xmlDoc;
+ mainXmlOK &= xmlDoc.setContent(&file);
+
+ QDomDocumentType type = xmlDoc.doctype();
+ mainXmlOK &= (type.name() == "PencilDocument" || type.name() == "MyObject");
+
+ QDomElement root = xmlDoc.documentElement();
+ mainXmlOK &= (!root.isNull());
+
+ QDomElement objectTag = root.firstChildElement("object");
+ mainXmlOK &= (objectTag.isNull() == false);
+
+ if (mainXmlOK == false)
+ {
+ // the main.xml is broken, try to rebuild one
+ rebuildMainXML(object);
+
+ // Load the newly built main.xml
+ QFile file(object->mainXMLFile());
+ file.open(QFile::ReadOnly);
+ xmlDoc.setContent(&file);
+ root = xmlDoc.documentElement();
+ objectTag = root.firstChildElement("object");
+ }
+ loadPalette(object);
+
+ bool ok = loadObject(object, root);
+ verifyObject(object);
+
+ return ok ? Status::OK : Status::FAIL;
+}
+
+/** Create a new main.xml based on the png/vec filenames left in the data folder */
+Status FileManager::rebuildMainXML(Object* object)
+{
+ QDir dataDir(object->dataDir());
+
+ QStringList nameFiler;
+ nameFiler << "*.png" << "*.vec";
+ const QStringList entries = dataDir.entryList(nameFiler, QDir::Files | QDir::Readable, QDir::Name);
+
+ QMap keyFrameGroups;
+
+ // grouping keyframe files by layers
+ for (const QString& s : entries)
+ {
+ int layerIndex = layerIndexFromFilename(s);
+ if (layerIndex > 0)
+ {
+ keyFrameGroups[layerIndex].append(s);
+ }
+ }
+
+ // build the new main XML file
+ const QString mainXMLPath = object->mainXMLFile();
+ QFile file(mainXMLPath);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ {
+ return Status::ERROR_FILE_CANNOT_OPEN;
+ }
+
+ QDomDocument xmlDoc("PencilDocument");
+ QDomElement root = xmlDoc.createElement("document");
+ QDomProcessingInstruction encoding = xmlDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ xmlDoc.appendChild(encoding);
+ xmlDoc.appendChild(root);
+
+ // save editor information
+ QDomElement projDataXml = saveProjectData(object->data(), xmlDoc);
+ root.appendChild(projDataXml);
+
+ // save object
+ QDomElement elemObject = xmlDoc.createElement("object");
+ root.appendChild(elemObject);
+
+ for (const int layerIndex : keyFrameGroups.keys())
+ {
+ const QStringList& frames = keyFrameGroups.value(layerIndex);
+ Status st = rebuildLayerXmlTag(xmlDoc, elemObject, layerIndex, frames);
+ }
+
+ QTextStream fout(&file);
+ xmlDoc.save(fout, 2);
+ fout.flush();
+ file.close();
+
+ return Status::OK;
+}
+/**
+ * Rebuild a layer xml tag. example:
+ *
+ *
+ *
+ */
+Status FileManager::rebuildLayerXmlTag(QDomDocument& doc,
+ QDomElement& elemObject,
+ const int layerIndex,
+ const QStringList& frames)
+{
+ Q_ASSERT(frames.length() > 0);
+
+ Layer::LAYER_TYPE type = frames[0].endsWith(".png") ? Layer::BITMAP : Layer::VECTOR;
+
+ QDomElement elemLayer = doc.createElement("layer");
+ elemLayer.setAttribute("id", layerIndex + 1); // starts from 1, not 0.
+ elemLayer.setAttribute("name", recoverLayerName(type, layerIndex));
+ elemLayer.setAttribute("visibility", true);
+ elemLayer.setAttribute("type", type);
+ elemObject.appendChild(elemLayer);
+
+ for (const QString& s : frames)
+ {
+ const int framePos = framePosFromFilename(s);
+ if (framePos < 0) { continue; }
+
+ QDomElement elemFrame = doc.createElement("image");
+ elemFrame.setAttribute("frame", framePos);
+ elemFrame.setAttribute("src", s);
+
+ if (type == Layer::BITMAP)
+ {
+ // Since we have no way to know the original img position
+ // Put it at the top left corner of the default camera
+ elemFrame.setAttribute("topLeftX", -800);
+ elemFrame.setAttribute("topLeftY", -600);
+ }
+ elemLayer.appendChild(elemFrame);
+ }
+ return Status::OK;
+}
+
+QString FileManager::recoverLayerName(Layer::LAYER_TYPE type, int index)
+{
+ switch (type)
+ {
+ case Layer::BITMAP:
+ return QString("%1 %2").arg(tr("Bitmap Layer")).arg(index);
+ case Layer::VECTOR:
+ return QString("%1 %2").arg(tr("Vector Layer")).arg(index);
+ case Layer::SOUND:
+ return QString("%1 %2").arg(tr("Sound Layer")).arg(index);
+ default:
+ Q_ASSERT(false);
+ }
+ return "";
+}
+
+int FileManager::layerIndexFromFilename(const QString& filename)
+{
+ const QStringList tokens = filename.split("."); // e.g., 001.019.png or 012.132.vec
+ if (tokens.length() >= 3) // a correct file name must have 3 tokens
+ {
+ return tokens[0].toInt();
+ }
+ return -1;
+}
+
+int FileManager::framePosFromFilename(const QString& filename)
+{
+ const QStringList tokens = filename.split("."); // e.g., 001.019.png or 012.132.vec
+ if (tokens.length() >= 3) // a correct file name must have 3 tokens
+ {
+ return tokens[1].toInt();
+ }
+ return -1;
+}
diff --git a/core_lib/src/structure/filemanager.h b/core_lib/src/structure/filemanager.h
index ee4d257a2c..d4816ff2ef 100644
--- a/core_lib/src/structure/filemanager.h
+++ b/core_lib/src/structure/filemanager.h
@@ -26,6 +26,7 @@ GNU General Public License for more details.
#include "pencildef.h"
#include "pencilerror.h"
#include "colorref.h"
+#include "layer.h"
class Object;
class ObjectData;
@@ -45,6 +46,9 @@ class FileManager : public QObject
Status error() const { return mError; }
Status verifyObject(Object* obj);
+ QStringList searchForUnsavedProjects();
+ Object* recoverUnsavedProject(QString projectIntermediatePath);
+
Q_SIGNALS:
void progressChanged(int progress);
void progressRangeChanged(int maxValue);
@@ -68,6 +72,17 @@ class FileManager : public QObject
void progressForward();
+
+private: // Project recovery
+ bool isProjectRecoverable(const QString& projectFolder);
+ Status recoverObject(Object* object);
+ Status rebuildMainXML(Object* object);
+ Status rebuildLayerXmlTag(QDomDocument& doc, QDomElement& elemObject,
+ const int layerIndex, const QStringList& frames);
+ QString recoverLayerName(Layer::LAYER_TYPE, int index);
+ int layerIndexFromFilename(const QString& filename);
+ int framePosFromFilename(const QString& filename);
+
private:
Status mError = Status::OK;
QString mstrLastTempFolder;
diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp
index 7c98e5349c..bdfea0b0d3 100644
--- a/core_lib/src/structure/layerbitmap.cpp
+++ b/core_lib/src/structure/layerbitmap.cpp
@@ -149,7 +149,7 @@ QString LayerBitmap::fileName(KeyFrame* key) const
}
bool LayerBitmap::needSaveFrame(KeyFrame* key, const QString& savePath)
-{
+{
if (key->isModified()) // keyframe was modified
return true;
if (QFile::exists(savePath) == false) // hasn't been saved before
diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp
index c8e738f529..83d751c2b0 100644
--- a/core_lib/src/structure/object.cpp
+++ b/core_lib/src/structure/object.cpp
@@ -163,15 +163,15 @@ LayerCamera* Object::addNewCameraLayer()
void Object::createWorkingDir()
{
- QString strFolderName;
+ QString projectName;
if (mFilePath.isEmpty())
{
- strFolderName = "Default";
+ projectName = "Default";
}
else
{
QFileInfo fileInfo(mFilePath);
- strFolderName = fileInfo.completeBaseName();
+ projectName = fileInfo.completeBaseName();
}
QDir dir(QDir::tempPath());
@@ -180,7 +180,7 @@ void Object::createWorkingDir()
{
strWorkingDir = QString("%1/Pencil2D/%2_%3_%4/")
.arg(QDir::tempPath())
- .arg(strFolderName)
+ .arg(projectName)
.arg(PFF_TMP_DECOMPRESS_EXT)
.arg(uniqueString(8));
}
@@ -200,10 +200,18 @@ void Object::deleteWorkingDir() const
if (!mWorkingDirPath.isEmpty())
{
QDir dir(mWorkingDirPath);
- dir.removeRecursively();
+ bool ok = dir.removeRecursively();
+ Q_ASSERT(ok);
}
}
+void Object::setWorkingDir(const QString& path)
+{
+ QDir dir(path);
+ Q_ASSERT(dir.exists());
+ mWorkingDirPath = path;
+}
+
void Object::createDefaultLayers()
{
// default layers
diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h
index b21917af0b..77d55e0db1 100644
--- a/core_lib/src/structure/object.h
+++ b/core_lib/src/structure/object.h
@@ -62,6 +62,7 @@ class Object : public QObject
void init();
void createWorkingDir();
void deleteWorkingDir() const;
+ void setWorkingDir(const QString& path); // used by crash recovery
void createDefaultLayers();
QString filePath() const { return mFilePath; }
diff --git a/core_lib/src/util/fileformat.cpp b/core_lib/src/util/fileformat.cpp
index 217d93c01c..7f7fbed570 100644
--- a/core_lib/src/util/fileformat.cpp
+++ b/core_lib/src/util/fileformat.cpp
@@ -17,25 +17,25 @@ GNU General Public License for more details.
#include "fileformat.h"
#include
+#include
-bool removePFFTmpDirectory (const QString& dirName)
+bool removePFFTmpDirectory(const QString& dirName)
{
- if ( dirName.isEmpty() )
+ if (dirName.isEmpty())
{
return false;
}
- QDir dir( dirName );
-
- if ( !dir.exists() )
+ QDir dir(dirName);
+
+ if (!dir.exists())
{
- Q_ASSERT( false );
+ Q_ASSERT(false);
return false;
}
bool result = dir.removeRecursively();
-
- return result;
+ return result;
}
QString uniqueString(int len)
@@ -53,3 +53,13 @@ QString uniqueString(int len)
s[len] = 0;
return QString::fromUtf8(s);
}
+
+QString retrieveProjectNameFromTempPath(const QString& path)
+{
+ QFileInfo info(path);
+ QString fileName = info.completeBaseName();
+
+ QStringList tokens = fileName.split("_");
+ //qDebug() << tokens;
+ return tokens[0];
+}
diff --git a/core_lib/src/util/fileformat.h b/core_lib/src/util/fileformat.h
index 5fe61ffbbd..0e28e565c4 100644
--- a/core_lib/src/util/fileformat.h
+++ b/core_lib/src/util/fileformat.h
@@ -71,8 +71,9 @@ GNU General Public License for more details.
#define PFF_TMP_DECOMPRESS_EXT "Y2xD"
#define PFF_PALETTE_FILE "palette.xml"
-bool removePFFTmpDirectory (const QString& dirName);
+bool removePFFTmpDirectory(const QString& dirName);
QString uniqueString(int len);
+QString retrieveProjectNameFromTempPath(const QString& path);
#endif
diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp
index 0fdfb70621..e5236eb352 100644
--- a/tests/src/test_filemanager.cpp
+++ b/tests/src/test_filemanager.cpp
@@ -1,4 +1,4 @@
-/*
+/*
Pencil - Traditional Animation Software
Copyright (C) 2012-2020 Matthew Chiawen Chang
@@ -430,7 +430,7 @@ TEST_CASE("Empty Sound Frames")
REQUIRE(newObj->getLayer(0)->type() == 4);
REQUIRE(newObj->getLayer(0)->id() == 5);
REQUIRE(newObj->getLayer(0)->name() == "GoodLayer");
- REQUIRE(newObj->getLayer(0)->getVisibility() == 1);
+ REQUIRE(newObj->getLayer(0)->getVisibility() == true);
REQUIRE(newObj->getLayer(0)->getKeyFrameAt(1) == nullptr);
delete newObj;