mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support backup file
Add configs: - backup_directory - backup_extension - enable_backup_file
This commit is contained in:
parent
141b404240
commit
e6ce66ec7d
@ -116,7 +116,7 @@ tool_bar_icon_size=18
|
||||
; Markdown-it options
|
||||
; Enable HTML tags in source
|
||||
markdownit_opt_html=true
|
||||
; Convert '\n' in paragraphs into <br>
|
||||
; Convert '\n' in paragraphs into <br/>
|
||||
markdownit_opt_breaks=false
|
||||
; Auto-convert URL-like text to links
|
||||
markdownit_opt_linkify=true
|
||||
@ -155,6 +155,16 @@ startup_pages=
|
||||
; Timer interval to check file modification or save file to tmp file in milliseconds
|
||||
file_timer_interval=2000
|
||||
|
||||
; Directory for the backup file
|
||||
; A directory "." means to put the backup file in the same directory as the edited file
|
||||
backup_directory=.
|
||||
|
||||
; String which is appended to a file name to make the name of the backup file
|
||||
backup_extension=.vswp
|
||||
|
||||
; Enable back file
|
||||
enable_backup_file=true
|
||||
|
||||
[web]
|
||||
; Location and configuration for Mathjax
|
||||
mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML
|
||||
|
@ -891,7 +891,14 @@ bool VUtils::deleteFile(const VNotebook *p_notebook,
|
||||
bool VUtils::deleteFile(const QString &p_path)
|
||||
{
|
||||
QFile file(p_path);
|
||||
return file.remove();
|
||||
bool ret = file.remove();
|
||||
if (ret) {
|
||||
qDebug() << "deleted file" << p_path;
|
||||
} else {
|
||||
qWarning() << "fail to delete file" << p_path;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool VUtils::deleteFile(const VOrphanFile *p_file,
|
||||
|
@ -268,6 +268,18 @@ void VConfigManager::initialize()
|
||||
if (m_fileTimerInterval < 100) {
|
||||
m_fileTimerInterval = 100;
|
||||
}
|
||||
|
||||
m_backupDirectory = getConfigFromSettings("global",
|
||||
"backup_directory").toString();
|
||||
|
||||
m_backupExtension = getConfigFromSettings("global",
|
||||
"backup_extension").toString();
|
||||
if (m_backupExtension.isEmpty()) {
|
||||
m_backupExtension = ".";
|
||||
}
|
||||
|
||||
m_enableBackupFile = getConfigFromSettings("global",
|
||||
"enable_backup_file").toBool();
|
||||
}
|
||||
|
||||
void VConfigManager::initSettings()
|
||||
|
@ -375,6 +375,15 @@ public:
|
||||
// Return the timer interval for checking file.
|
||||
int getFileTimerInterval() const;
|
||||
|
||||
// Get the backup directory.
|
||||
const QString &getBackupDirectory() const;
|
||||
|
||||
// Get the backup file extension.
|
||||
const QString &getBackupExtension() const;
|
||||
|
||||
// Whether backup file is enabled.
|
||||
bool getEnableBackupFile() const;
|
||||
|
||||
private:
|
||||
// Look up a config from user and default settings.
|
||||
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
||||
@ -709,6 +718,15 @@ private:
|
||||
// Timer interval to check file in milliseconds.
|
||||
int m_fileTimerInterval;
|
||||
|
||||
// Directory for the backup file (relative or absolute path).
|
||||
QString m_backupDirectory;
|
||||
|
||||
// Extension of the backup file.
|
||||
QString m_backupExtension;
|
||||
|
||||
// Whether enable backup file.
|
||||
bool m_enableBackupFile;
|
||||
|
||||
// The name of the config file in each directory, obsolete.
|
||||
// Use c_dirConfigFile instead.
|
||||
static const QString c_obsoleteDirConfigFile;
|
||||
@ -1790,4 +1808,19 @@ inline int VConfigManager::getFileTimerInterval() const
|
||||
return m_fileTimerInterval;
|
||||
}
|
||||
|
||||
inline const QString &VConfigManager::getBackupDirectory() const
|
||||
{
|
||||
return m_backupDirectory;
|
||||
}
|
||||
|
||||
inline const QString &VConfigManager::getBackupExtension() const
|
||||
{
|
||||
return m_backupExtension;
|
||||
}
|
||||
|
||||
inline bool VConfigManager::getEnableBackupFile() const
|
||||
{
|
||||
return m_enableBackupFile;
|
||||
}
|
||||
|
||||
#endif // VCONFIGMANAGER_H
|
||||
|
@ -139,6 +139,11 @@ public:
|
||||
|
||||
void setVimMode(VimMode p_mode);
|
||||
|
||||
virtual QString getContent() const = 0;
|
||||
|
||||
// @p_modified: if true, delete the whole content and insert the new content.
|
||||
virtual void setContent(const QString &p_content, bool p_modified = false) = 0;
|
||||
|
||||
// Wrapper functions for QPlainTextEdit/QTextEdit.
|
||||
// Ends with W to distinguish it from the original interfaces.
|
||||
public:
|
||||
|
@ -15,7 +15,9 @@ VEditTab::VEditTab(VFile *p_file, VEditArea *p_editArea, QWidget *p_parent)
|
||||
m_currentHeader(p_file, -1),
|
||||
m_editArea(p_editArea),
|
||||
m_checkFileChange(true),
|
||||
m_fileDiverged(false)
|
||||
m_fileDiverged(false),
|
||||
m_ready(0),
|
||||
m_enableBackupFile(g_config->getEnableBackupFile())
|
||||
{
|
||||
connect(qApp, &QApplication::focusChanged,
|
||||
this, &VEditTab::handleFocusChanged);
|
||||
@ -181,3 +183,7 @@ void VEditTab::reloadFromDisk()
|
||||
m_checkFileChange = true;
|
||||
reload();
|
||||
}
|
||||
|
||||
void VEditTab::writeBackupFile()
|
||||
{
|
||||
}
|
||||
|
@ -124,6 +124,9 @@ protected:
|
||||
// Return true if succeed.
|
||||
virtual bool restoreFromTabInfo(const VEditTabInfo &p_info) = 0;
|
||||
|
||||
// Write modified buffer content to backup file.
|
||||
virtual void writeBackupFile();
|
||||
|
||||
// File related to this tab.
|
||||
QPointer<VFile> m_file;
|
||||
|
||||
@ -146,6 +149,12 @@ protected:
|
||||
// File has diverged from disk.
|
||||
bool m_fileDiverged;
|
||||
|
||||
// Tab has been ready or not.
|
||||
int m_ready;
|
||||
|
||||
// Whether backup file is enabled.
|
||||
bool m_enableBackupFile;
|
||||
|
||||
signals:
|
||||
void getFocused();
|
||||
|
||||
@ -161,6 +170,9 @@ signals:
|
||||
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
// Request to close itself.
|
||||
void closeRequested(VEditTab *p_tab);
|
||||
|
||||
private slots:
|
||||
// Called when app focus changed.
|
||||
void handleFocusChanged(QWidget *p_old, QWidget *p_now);
|
||||
|
@ -960,6 +960,8 @@ void VEditWindow::connectEditTab(const VEditTab *p_tab)
|
||||
this, &VEditWindow::handleTabStatusMessage);
|
||||
connect(p_tab, &VEditTab::vimStatusUpdated,
|
||||
this, &VEditWindow::handleTabVimStatusUpdated);
|
||||
connect(p_tab, &VEditTab::closeRequested,
|
||||
this, &VEditWindow::tabRequestToClose);
|
||||
}
|
||||
|
||||
void VEditWindow::setCurrentWindow(bool p_current)
|
||||
@ -1094,3 +1096,16 @@ void VEditWindow::checkFileChangeOutside()
|
||||
getTab(i)->checkFileChangeOutside();
|
||||
}
|
||||
}
|
||||
|
||||
void VEditWindow::tabRequestToClose(VEditTab *p_tab)
|
||||
{
|
||||
bool ok = p_tab->closeFile(false);
|
||||
if (ok) {
|
||||
removeTab(indexOf(p_tab));
|
||||
|
||||
// Disconnect all the signals.
|
||||
disconnect(p_tab, 0, this, 0);
|
||||
|
||||
p_tab->deleteLater();
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,9 @@ private slots:
|
||||
// Handle the statusUpdated signal of VEditTab.
|
||||
void handleTabStatusUpdated(const VEditTabInfo &p_info);
|
||||
|
||||
// @p_tab request to close itself.
|
||||
void tabRequestToClose(VEditTab *p_tab);
|
||||
|
||||
private:
|
||||
void initTabActions();
|
||||
void setupCornerWidget();
|
||||
|
@ -3,7 +3,15 @@
|
||||
#include <QDir>
|
||||
#include <QTextEdit>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include "utils/vutils.h"
|
||||
#include "vconfigmanager.h"
|
||||
|
||||
extern VConfigManager *g_config;
|
||||
|
||||
const QString VFile::c_backupFileHeadMagic = "vnote_backup_file_826537664";
|
||||
|
||||
VFile::VFile(QObject *p_parent,
|
||||
const QString &p_name,
|
||||
@ -50,6 +58,11 @@ void VFile::close()
|
||||
}
|
||||
|
||||
m_content.clear();
|
||||
if (!m_backupName.isEmpty()) {
|
||||
VUtils::deleteFile(fetchBackupFilePath());
|
||||
m_backupName.clear();
|
||||
}
|
||||
|
||||
m_opened = false;
|
||||
}
|
||||
|
||||
@ -57,6 +70,7 @@ bool VFile::save()
|
||||
{
|
||||
Q_ASSERT(m_opened);
|
||||
Q_ASSERT(m_modifiable);
|
||||
|
||||
bool ret = VUtils::writeFileToDisk(fetchPath(), m_content);
|
||||
if (ret) {
|
||||
m_lastModified = QFileInfo(fetchPath()).lastModified();
|
||||
@ -110,3 +124,87 @@ void VFile::reload()
|
||||
m_content = VUtils::readFileFromDisk(filePath);
|
||||
m_lastModified = QFileInfo(filePath).lastModified();
|
||||
}
|
||||
|
||||
QString VFile::backupFileOfPreviousSession() const
|
||||
{
|
||||
Q_ASSERT(m_modifiable && m_backupName.isEmpty());
|
||||
|
||||
QString basePath = QDir(fetchBasePath()).filePath(g_config->getBackupDirectory());
|
||||
QDir dir(basePath);
|
||||
|
||||
QStringList files = getPotentialBackupFiles(basePath);
|
||||
foreach (const QString &file, files) {
|
||||
QString filePath = dir.filePath(file);
|
||||
if (isBackupFile(filePath)) {
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString VFile::fetchBackupFilePath()
|
||||
{
|
||||
QString basePath = QDir(fetchBasePath()).filePath(g_config->getBackupDirectory());
|
||||
QDir dir(basePath);
|
||||
|
||||
if (m_backupName.isEmpty()) {
|
||||
m_backupName = VUtils::getFileNameWithSequence(basePath,
|
||||
m_name + g_config->getBackupExtension(),
|
||||
true);
|
||||
|
||||
m_lastBackupFilePath = dir.filePath(m_backupName);
|
||||
} else {
|
||||
QString filePath = dir.filePath(m_backupName);
|
||||
if (filePath != m_lastBackupFilePath) {
|
||||
// File has been moved.
|
||||
// Delete the original backup file if it still exists.
|
||||
VUtils::deleteFile(m_lastBackupFilePath);
|
||||
|
||||
m_lastBackupFilePath = filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return m_lastBackupFilePath;
|
||||
}
|
||||
|
||||
QStringList VFile::getPotentialBackupFiles(const QString &p_dir) const
|
||||
{
|
||||
QString nameFilter = QString("%1*%2").arg(m_name).arg(g_config->getBackupExtension());
|
||||
QStringList files = QDir(p_dir).entryList(QStringList(nameFilter),
|
||||
QDir::Files
|
||||
| QDir::Hidden
|
||||
| QDir::NoSymLinks
|
||||
| QDir::NoDotAndDotDot);
|
||||
return files;
|
||||
}
|
||||
|
||||
bool VFile::isBackupFile(const QString &p_file) const
|
||||
{
|
||||
QFile file(p_file);
|
||||
if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream st(&file);
|
||||
QString head = st.readLine();
|
||||
return head == fetchBackupFileHead();
|
||||
}
|
||||
|
||||
QString VFile::fetchBackupFileHead() const
|
||||
{
|
||||
return c_backupFileHeadMagic + " " + fetchPath();
|
||||
}
|
||||
|
||||
bool VFile::writeBackupFile(const QString &p_content)
|
||||
{
|
||||
return VUtils::writeFileToDisk(fetchBackupFilePath(),
|
||||
fetchBackupFileHead() + "\n" + p_content);
|
||||
}
|
||||
|
||||
QString VFile::readBackupFile(const QString &p_file)
|
||||
{
|
||||
const QString content = VUtils::readFileFromDisk(p_file);
|
||||
int idx = content.indexOf("\n");
|
||||
return content.mid(idx + 1);
|
||||
}
|
||||
|
27
src/vfile.h
27
src/vfile.h
@ -79,6 +79,14 @@ public:
|
||||
// Whether this file was changed outside VNote.
|
||||
bool isChangedOutside() const;
|
||||
|
||||
// Return backup file of previous session if there exists one.
|
||||
QString backupFileOfPreviousSession() const;
|
||||
|
||||
// Write @p_content to backup file.
|
||||
bool writeBackupFile(const QString &p_content);
|
||||
|
||||
QString readBackupFile(const QString &p_file);
|
||||
|
||||
protected:
|
||||
// Name of this file.
|
||||
QString m_name;
|
||||
@ -107,6 +115,25 @@ protected:
|
||||
// Last modified date and local time when the file is last modified
|
||||
// corresponding to m_content.
|
||||
QDateTime m_lastModified;
|
||||
|
||||
// Name of the backup file.
|
||||
QString m_backupName;
|
||||
|
||||
// Used to identify file path change.
|
||||
QString m_lastBackupFilePath;
|
||||
|
||||
private:
|
||||
// Fetch backup file path.
|
||||
QString fetchBackupFilePath();
|
||||
|
||||
QStringList getPotentialBackupFiles(const QString &p_dir) const;
|
||||
|
||||
// Read the file content to check if it is a backup file.
|
||||
bool isBackupFile(const QString &p_file) const;
|
||||
|
||||
QString fetchBackupFileHead() const;
|
||||
|
||||
static const QString c_backupFileHeadMagic;
|
||||
};
|
||||
|
||||
inline const QString &VFile::getName() const
|
||||
|
@ -59,6 +59,11 @@ VMdEditor::VMdEditor(VFile *p_file,
|
||||
connect(m_mdHighlighter, &HGMarkdownHighlighter::highlightCompleted,
|
||||
this, [this]() {
|
||||
makeBlockVisible(textCursor().block());
|
||||
|
||||
if (m_freshEdit) {
|
||||
m_freshEdit = false;
|
||||
emit m_object->ready();
|
||||
}
|
||||
});
|
||||
|
||||
m_cbHighlighter = new VCodeBlockHighlightHelper(m_mdHighlighter,
|
||||
@ -106,11 +111,6 @@ void VMdEditor::beginEdit()
|
||||
emit statusChanged();
|
||||
|
||||
updateHeaders(m_mdHighlighter->getHeaderRegions());
|
||||
|
||||
if (m_freshEdit) {
|
||||
m_freshEdit = false;
|
||||
emit m_object->ready();
|
||||
}
|
||||
}
|
||||
|
||||
void VMdEditor::endEdit()
|
||||
@ -161,14 +161,14 @@ void VMdEditor::makeBlockVisible(const QTextBlock &p_block)
|
||||
}
|
||||
|
||||
QScrollBar *vbar = verticalScrollBar();
|
||||
if (!vbar || !vbar->isVisible()) {
|
||||
if (!vbar || (vbar->minimum() == vbar->maximum())) {
|
||||
// No vertical scrollbar. No need to scroll.
|
||||
return;
|
||||
}
|
||||
|
||||
int height = rect().height();
|
||||
QScrollBar *hbar = horizontalScrollBar();
|
||||
if (hbar && hbar->isVisible()) {
|
||||
if (hbar && (hbar->minimum() != hbar->maximum())) {
|
||||
height -= hbar->height();
|
||||
}
|
||||
|
||||
@ -870,3 +870,20 @@ void VMdEditor::updateConfig()
|
||||
updateEditConfig();
|
||||
updateTextEditConfig();
|
||||
}
|
||||
|
||||
QString VMdEditor::getContent() const
|
||||
{
|
||||
return toPlainText();
|
||||
}
|
||||
|
||||
void VMdEditor::setContent(const QString &p_content, bool p_modified)
|
||||
{
|
||||
if (p_modified) {
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.select(QTextCursor::Document);
|
||||
cursor.insertText(p_content);
|
||||
setTextCursor(cursor);
|
||||
} else {
|
||||
setPlainText(p_content);
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,10 @@ public:
|
||||
|
||||
void updateConfig() Q_DECL_OVERRIDE;
|
||||
|
||||
QString getContent() const Q_DECL_OVERRIDE;
|
||||
|
||||
void setContent(const QString &p_content, bool p_modified = false) Q_DECL_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
bool jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat) Q_DECL_OVERRIDE;
|
||||
|
||||
|
141
src/vmdtab.cpp
141
src/vmdtab.cpp
@ -33,7 +33,8 @@ VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea,
|
||||
m_webViewer(NULL),
|
||||
m_document(NULL),
|
||||
m_mdConType(g_config->getMdConverterType()),
|
||||
m_enableHeadingSequence(false)
|
||||
m_enableHeadingSequence(false),
|
||||
m_backupFileChecked(false)
|
||||
{
|
||||
V_ASSERT(m_file->getDocType() == DocType::Markdown);
|
||||
|
||||
@ -49,6 +50,14 @@ VMdTab::VMdTab(VFile *p_file, VEditArea *p_editArea,
|
||||
|
||||
setupUI();
|
||||
|
||||
m_backupTimer = new QTimer(this);
|
||||
m_backupTimer->setSingleShot(true);
|
||||
m_backupTimer->setInterval(g_config->getFileTimerInterval());
|
||||
connect(m_backupTimer, &QTimer::timeout,
|
||||
this, [this]() {
|
||||
writeBackupFile();
|
||||
});
|
||||
|
||||
if (p_mode == OpenFileMode::Edit) {
|
||||
showFileEditMode();
|
||||
} else {
|
||||
@ -325,9 +334,13 @@ bool VMdTab::saveFile()
|
||||
m_editor->saveFile();
|
||||
ret = m_file->save();
|
||||
if (!ret) {
|
||||
VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note."),
|
||||
VUtils::showMessage(QMessageBox::Warning,
|
||||
tr("Warning"),
|
||||
tr("Fail to save note."),
|
||||
tr("Fail to write to disk when saving a note. Please try it again."),
|
||||
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok,
|
||||
this);
|
||||
m_editor->setModified(true);
|
||||
} else {
|
||||
m_fileDiverged = false;
|
||||
@ -376,8 +389,17 @@ void VMdTab::setupMarkdownViewer()
|
||||
this, SLOT(updateCurrentHeader(const QString &)));
|
||||
connect(m_document, &VDocument::keyPressed,
|
||||
this, &VMdTab::handleWebKeyPressed);
|
||||
connect(m_document, SIGNAL(logicsFinished(void)),
|
||||
this, SLOT(restoreFromTabInfo(void)));
|
||||
connect(m_document, &VDocument::logicsFinished,
|
||||
this, [this]() {
|
||||
if (m_ready & TabReady::ReadMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ready |= TabReady::ReadMode;
|
||||
|
||||
tabIsReady(TabReady::ReadMode);
|
||||
});
|
||||
|
||||
page->setWebChannel(channel);
|
||||
|
||||
m_webViewer->setHtml(VUtils::generateHtmlTemplate(m_mdConType, false),
|
||||
@ -417,8 +439,16 @@ void VMdTab::setupMarkdownEditor()
|
||||
this, [this]() {
|
||||
this->m_editArea->getFindReplaceDialog()->closeDialog();
|
||||
});
|
||||
connect(m_editor->object(), SIGNAL(ready(void)),
|
||||
this, SLOT(restoreFromTabInfo(void)));
|
||||
connect(m_editor->object(), &VEditorObject::ready,
|
||||
this, [this]() {
|
||||
if (m_ready & TabReady::EditMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ready |= TabReady::EditMode;
|
||||
|
||||
tabIsReady(TabReady::EditMode);
|
||||
});
|
||||
|
||||
enableHeadingSequence(m_enableHeadingSequence);
|
||||
m_editor->reloadFile();
|
||||
@ -842,3 +872,100 @@ void VMdTab::reload()
|
||||
showFileReadMode();
|
||||
}
|
||||
}
|
||||
|
||||
void VMdTab::tabIsReady(TabReady p_mode)
|
||||
{
|
||||
bool isCurrentMode = m_isEditMode && p_mode == TabReady::EditMode
|
||||
|| !m_isEditMode && p_mode == TabReady::ReadMode;
|
||||
|
||||
if (isCurrentMode) {
|
||||
restoreFromTabInfo();
|
||||
|
||||
if (m_enableBackupFile
|
||||
&& !m_backupFileChecked
|
||||
&& m_file->isModifiable()) {
|
||||
if (!checkPreviousBackupFile()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_enableBackupFile
|
||||
&& m_file->isModifiable()
|
||||
&& p_mode == TabReady::EditMode) {
|
||||
// contentsChanged will be emitted even the content is not changed.
|
||||
connect(m_editor->document(), &QTextDocument::contentsChange,
|
||||
this, [this]() {
|
||||
if (m_isEditMode) {
|
||||
m_backupTimer->stop();
|
||||
m_backupTimer->start();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void VMdTab::writeBackupFile()
|
||||
{
|
||||
Q_ASSERT(m_enableBackupFile && m_file->isModifiable());
|
||||
m_file->writeBackupFile(m_editor->getContent());
|
||||
}
|
||||
|
||||
bool VMdTab::checkPreviousBackupFile()
|
||||
{
|
||||
m_backupFileChecked = true;
|
||||
|
||||
QString preFile = m_file->backupFileOfPreviousSession();
|
||||
if (preFile.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QMessageBox box(QMessageBox::Warning,
|
||||
tr("Backup File Found"),
|
||||
tr("Found backup file <span style=\"%1\">%2</span> "
|
||||
"when opening note <span style=\"%1\">%3</span>.")
|
||||
.arg(g_config->c_dataTextStyle)
|
||||
.arg(preFile)
|
||||
.arg(m_file->fetchPath()),
|
||||
QMessageBox::NoButton,
|
||||
this);
|
||||
QString backupContent = m_file->readBackupFile(preFile);
|
||||
QString info = tr("VNote may crash while editing this note before.<br/>"
|
||||
"Please choose to recover from the backup file or delete it.<br/><br/>"
|
||||
"Note file last modified: <span style=\"%1\">%2</span><br/>"
|
||||
"Backup file last modified: <span style=\"%1\">%3</span><br/>"
|
||||
"Content comparison: <span style=\"%1\">%4</span>")
|
||||
.arg(g_config->c_dataTextStyle)
|
||||
.arg(VUtils::displayDateTime(QFileInfo(m_file->fetchPath()).lastModified()))
|
||||
.arg(VUtils::displayDateTime(QFileInfo(preFile).lastModified()))
|
||||
.arg(m_file->getContent() == backupContent ? tr("Identical")
|
||||
: tr("Different"));
|
||||
box.setInformativeText(info);
|
||||
QPushButton *recoverBtn = box.addButton(tr("Recover From Backup File"), QMessageBox::YesRole);
|
||||
box.addButton(tr("Discard Backup File"), QMessageBox::NoRole);
|
||||
QPushButton *cancelBtn = box.addButton(tr("Cancel"), QMessageBox::RejectRole);
|
||||
|
||||
box.setDefaultButton(cancelBtn);
|
||||
box.setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
box.exec();
|
||||
QAbstractButton *btn = box.clickedButton();
|
||||
if (btn == cancelBtn || !btn) {
|
||||
// Close current tab.
|
||||
emit closeRequested(this);
|
||||
return false;
|
||||
} else if (btn == recoverBtn) {
|
||||
// Load content from the backup file.
|
||||
if (!m_isEditMode) {
|
||||
showFileEditMode();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_editor);
|
||||
m_editor->setContent(backupContent, true);
|
||||
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
VUtils::deleteFile(preFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
18
src/vmdtab.h
18
src/vmdtab.h
@ -13,6 +13,7 @@ class QStackedLayout;
|
||||
class VDocument;
|
||||
class VMdEditor;
|
||||
class VInsertSelector;
|
||||
class QTimer;
|
||||
|
||||
class VMdTab : public VEditTab
|
||||
{
|
||||
@ -88,6 +89,9 @@ public slots:
|
||||
// Enter edit mode.
|
||||
void editFile() Q_DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void writeBackupFile() Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
// Update m_outline according to @p_tocHtml for read mode.
|
||||
void updateOutlineFromHtml(const QString &p_tocHtml);
|
||||
@ -115,6 +119,8 @@ private slots:
|
||||
void restoreFromTabInfo();
|
||||
|
||||
private:
|
||||
enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 };
|
||||
|
||||
// Setup UI.
|
||||
void setupUI();
|
||||
|
||||
@ -166,6 +172,13 @@ private:
|
||||
// Prepare insert selector with snippets.
|
||||
VInsertSelector *prepareSnippetSelector(QWidget *p_parent = nullptr);
|
||||
|
||||
// Called once read or edit mode is ready.
|
||||
void tabIsReady(TabReady p_mode);
|
||||
|
||||
// Check if there exists backup file from previous session.
|
||||
// Return true if we could continue.
|
||||
bool checkPreviousBackupFile();
|
||||
|
||||
VMdEditor *m_editor;
|
||||
VWebView *m_webViewer;
|
||||
VDocument *m_document;
|
||||
@ -175,6 +188,11 @@ private:
|
||||
bool m_enableHeadingSequence;
|
||||
|
||||
QStackedLayout *m_stacks;
|
||||
|
||||
// Timer to write backup file when content has been changed.
|
||||
QTimer *m_backupTimer;
|
||||
|
||||
bool m_backupFileChecked;
|
||||
};
|
||||
|
||||
inline VMdEditor *VMdTab::getEditor()
|
||||
|
Loading…
x
Reference in New Issue
Block a user