Skip to content

Added File Change Detection #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/FileManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,18 @@ class FileManager : public QObject
static OperationResult duplicatePath(const QFileInfo &pathInfo);
static OperationResult deletePath(const QFileInfo &pathInfo);

int buildUnsavedChangesMessage() const;
bool hasUnsavedChanges();

public slots:
void newFile();
void saveFile();
void saveFileAs();
void openFile();
void loadFileInEditor(const QString &filePath);

bool promptUnsavedChanges();

QString getDirectoryPath() const;

private:
Expand All @@ -69,4 +74,5 @@ public slots:
MainWindow *m_mainWindow;
QSyntaxHighlighter *m_currentHighlighter = nullptr;
QString m_currentFileName;
bool m_isDirty = false;
};
155 changes: 105 additions & 50 deletions src/FileManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <iostream>
#include <fstream>


FileManager::FileManager(CodeEditor *editor, MainWindow *mainWindow)
: m_editor(editor), m_mainWindow(mainWindow)
{
Expand All @@ -23,6 +24,8 @@ void FileManager::initialize(CodeEditor *editor, MainWindow *mainWindow)
{
m_editor = editor;
m_mainWindow = mainWindow;

connect(m_editor, &QPlainTextEdit::textChanged, this, [this](){m_isDirty = true;});
}

QString FileManager::getCurrentFileName() const
Expand All @@ -35,65 +38,102 @@ void FileManager::setCurrentFileName(const QString fileName)
m_currentFileName = fileName;
}

void FileManager::newFile()
QString getLastSaved(const QFileInfo& file)
{
QString currentFileName = getCurrentFileName();
bool isFileSaved = !currentFileName.isEmpty();
bool isTextEditorEmpty = this->m_editor->toPlainText().isEmpty();
// File has not been saved and the text editor is not empty
if (!isFileSaved && !isTextEditorEmpty)
{
// Create box to prompt user to save changes to file
QMessageBox promptBox;
promptBox.setWindowTitle("Save Current File");
promptBox.setText("Would you like to save the file?");
promptBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
promptBox.setDefaultButton(QMessageBox::Save);

int option = promptBox.exec();
// return if the user hit Cancel button
if (option == QMessageBox::Cancel)
{
return;
}
const auto lastSaved = file.lastModified();
const auto now = QDateTime::currentDateTime();
const auto seconds = lastSaved.secsTo(now);

const int days = seconds / (60 * 60 * 24);
if (days == 0)
return "today";
if (days == 1)
return "yesterday";

return QString::number(days) + " days ago";
}

saveFile();
bool FileManager::hasUnsavedChanges()
{
if(!m_isDirty)
{
return false;
}
// File has been previously saved
else if (isFileSaved)

// Additional safeguard if content still matches file on disk
if (!m_currentFileName.isEmpty())
{
// Read from saved file and compare to current file
QFile file(currentFileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
QString savedFileContents = in.readAll();
file.close();
if (savedFileContents != this->m_editor->toPlainText().trimmed())
QFile file(m_currentFileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
// Create box to prompt user to save changes to file
QMessageBox promptBox;
promptBox.setWindowTitle("Changes Detected");
promptBox.setText("Would you like to save the current changes to the file?");
promptBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
promptBox.setDefaultButton(QMessageBox::Save);
int option = promptBox.exec();
// return if the user hit Cancel button
if (option == QMessageBox::Cancel)
QTextStream in(&file);
QString diskContents = in.readAll();
if (diskContents == m_editor->toPlainText())
{
return;
m_isDirty = false;
return false;
}
saveFile();
}
}

return true; // nothing changed
}

int FileManager::buildUnsavedChangesMessage() const
{
QString infoText = "Your changes will be lost if you don't save.";
if (!m_currentFileName.isEmpty())
{
setCurrentFileName("");
m_editor->clear();
m_mainWindow->setWindowTitle("Code Astra ~ untitled");
QFileInfo file(m_currentFileName);
if (file.exists())
{
QString timeSinceSave = getLastSaved(file);
infoText = "The document has been modified. It was last edited " + timeSinceSave + ".";
}
}


QMessageBox promptBox;
promptBox.setWindowTitle("Unsaved changes");
promptBox.setText("Would you like to save your changes?");
promptBox.setInformativeText(infoText);
promptBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
promptBox.setDefaultButton(QMessageBox::Save);

return promptBox.exec();
}

bool FileManager::promptUnsavedChanges()
{
if (!hasUnsavedChanges())
{
return true;
}

int option = buildUnsavedChangesMessage();
if (option == QMessageBox::Save)
{
saveFile();
}
else if (option == QMessageBox::Cancel)
{
return false;
}

// if discard selected, continue without saving.
return true;
}

void FileManager::newFile()
{
if (!promptUnsavedChanges())
{
return;
}

m_currentFileName = "";
m_editor->clear();
m_mainWindow->setWindowTitle("Untitle ~ Code Astra");
m_isDirty = false;
}

void FileManager::saveFile()
Expand All @@ -104,7 +144,7 @@ void FileManager::saveFile()
return;
}

qDebug() << "Saving file:" << m_currentFileName;
// qDebug() << "Saving file:" << m_currentFileName;

QFile file(m_currentFileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
Expand All @@ -125,6 +165,16 @@ void FileManager::saveFile()
}
file.close();

if (m_mainWindow)
{
m_mainWindow->setWindowTitle("CodeAstra ~ " + QFileInfo(m_currentFileName).fileName());
}
else
{
qWarning() << "MainWindow is not initialized in FileManager.";
}

m_isDirty = false;
emit m_editor->statusMessageChanged("File saved successfully.");
}

Expand Down Expand Up @@ -152,7 +202,7 @@ void FileManager::openFile()
"All Files (*);;C++ Files (*.cpp *.h);;Text Files (*.txt)");
if (!fileName.isEmpty())
{
qDebug() << "Opening file: " << fileName;
// qDebug() << "Opening file: " << fileName;
m_currentFileName = fileName;
loadFileInEditor(fileName);
}
Expand All @@ -164,7 +214,8 @@ void FileManager::openFile()

void FileManager::loadFileInEditor(const QString &filePath)
{
qDebug() << "Loading file:" << filePath;
// qDebug() << "Loading file:" << filePath;

QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
Expand All @@ -175,7 +226,9 @@ void FileManager::loadFileInEditor(const QString &filePath)
QTextStream in(&file);
if (m_editor)
{
m_editor->blockSignals(true);
m_editor->setPlainText(in.readAll());
m_editor->blockSignals(false);

delete m_currentHighlighter;

Expand All @@ -197,6 +250,8 @@ void FileManager::loadFileInEditor(const QString &filePath)
{
qWarning() << "MainWindow is not initialized in FileManager.";
}

m_isDirty = false;
}

QString FileManager::getFileExtension() const
Expand Down Expand Up @@ -296,6 +351,7 @@ OperationResult FileManager::deletePath(const QFileInfo &pathInfo)
{
return {false, "ERROR: invalid file path." + pathToDelete.filename().string()};
}

QString qPathToDelete = QString::fromStdString(pathToDelete.string());
if (!QFile::moveToTrash(qPathToDelete))
{
Expand Down Expand Up @@ -330,7 +386,6 @@ OperationResult FileManager::newFile(const QFileInfo &pathInfo, QString newFileP
{
file.close();
}
qDebug() << "New file created.";

FileManager::getInstance().setCurrentFileName(QString::fromStdString(filePath.string()));
return {true, filePath.filename().string() + " created successfully."};
Expand Down
4 changes: 1 addition & 3 deletions src/Syntax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ void Syntax::loadSyntaxRules(const YAML::Node &config)
continue;
}

qDebug() << "regex: " << regex;

QColor color;
try
{
Expand All @@ -76,7 +74,7 @@ void Syntax::loadSyntaxRules(const YAML::Node &config)
//checks if the color is a valid color
if(!color.isValid())
{
qWarning() << "Invalid COlor : Skipping...";
qWarning() << "Invalid Color : Skipping...";
continue;
}

Expand Down
13 changes: 11 additions & 2 deletions src/Tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,17 @@ void Tree::openFile(const QModelIndex &index)
return;
}

FileManager::getInstance().setCurrentFileName(filePath);
FileManager::getInstance().loadFileInEditor(filePath);
FileManager &fm = FileManager::getInstance();
if (fm.getCurrentFileName() != filePath)
{
if (!fm.promptUnsavedChanges())
{
return; // if user has cancelled
}

fm.setCurrentFileName(filePath);
fm.loadFileInEditor(filePath);
}
}

QFileSystemModel *Tree::getModel() const
Expand Down
Loading