mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
refactor: add VFile and VDirectory
Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
parent
8e8d69c85f
commit
e7c42ba5be
@ -20,7 +20,7 @@ void VDirInfoDialog::setupUI()
|
|||||||
if (!info.isEmpty()) {
|
if (!info.isEmpty()) {
|
||||||
infoLabel = new QLabel(info);
|
infoLabel = new QLabel(info);
|
||||||
}
|
}
|
||||||
nameLabel = new QLabel(tr("&Name"));
|
nameLabel = new QLabel(tr("&Name:"));
|
||||||
nameEdit = new QLineEdit(defaultName);
|
nameEdit = new QLineEdit(defaultName);
|
||||||
nameEdit->selectAll();
|
nameEdit->selectAll();
|
||||||
nameLabel->setBuddy(nameEdit);
|
nameLabel->setBuddy(nameEdit);
|
||||||
@ -29,10 +29,7 @@ void VDirInfoDialog::setupUI()
|
|||||||
okBtn->setDefault(true);
|
okBtn->setDefault(true);
|
||||||
cancelBtn = new QPushButton(tr("&Cancel"));
|
cancelBtn = new QPushButton(tr("&Cancel"));
|
||||||
|
|
||||||
QVBoxLayout *topLayout = new QVBoxLayout();
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
||||||
if (infoLabel) {
|
|
||||||
topLayout->addWidget(infoLabel);
|
|
||||||
}
|
|
||||||
topLayout->addWidget(nameLabel);
|
topLayout->addWidget(nameLabel);
|
||||||
topLayout->addWidget(nameEdit);
|
topLayout->addWidget(nameEdit);
|
||||||
|
|
||||||
@ -42,6 +39,9 @@ void VDirInfoDialog::setupUI()
|
|||||||
btmLayout->addWidget(cancelBtn);
|
btmLayout->addWidget(cancelBtn);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
if (infoLabel) {
|
||||||
|
mainLayout->addWidget(infoLabel);
|
||||||
|
}
|
||||||
mainLayout->addLayout(topLayout);
|
mainLayout->addLayout(topLayout);
|
||||||
mainLayout->addLayout(btmLayout);
|
mainLayout->addLayout(btmLayout);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
@ -29,10 +29,7 @@ void VFileInfoDialog::setupUI()
|
|||||||
okBtn->setDefault(true);
|
okBtn->setDefault(true);
|
||||||
cancelBtn = new QPushButton(tr("&Cancel"));
|
cancelBtn = new QPushButton(tr("&Cancel"));
|
||||||
|
|
||||||
QVBoxLayout *topLayout = new QVBoxLayout();
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
||||||
if (infoLabel) {
|
|
||||||
topLayout->addWidget(infoLabel);
|
|
||||||
}
|
|
||||||
topLayout->addWidget(nameLabel);
|
topLayout->addWidget(nameLabel);
|
||||||
topLayout->addWidget(nameEdit);
|
topLayout->addWidget(nameEdit);
|
||||||
|
|
||||||
@ -42,6 +39,9 @@ void VFileInfoDialog::setupUI()
|
|||||||
btmLayout->addWidget(cancelBtn);
|
btmLayout->addWidget(cancelBtn);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
if (infoLabel) {
|
||||||
|
mainLayout->addWidget(infoLabel);
|
||||||
|
}
|
||||||
mainLayout->addLayout(topLayout);
|
mainLayout->addLayout(topLayout);
|
||||||
mainLayout->addLayout(btmLayout);
|
mainLayout->addLayout(btmLayout);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#include "vnewdirdialog.h"
|
#include "vnewdirdialog.h"
|
||||||
|
|
||||||
VNewDirDialog::VNewDirDialog(const QString &title, const QString &name, const QString &defaultName,
|
VNewDirDialog::VNewDirDialog(const QString &title, const QString &info, const QString &name, const QString &defaultName,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QDialog(parent), title(title), name(name), defaultName(defaultName)
|
: QDialog(parent), title(title), info(info), name(name), defaultName(defaultName)
|
||||||
{
|
{
|
||||||
setupUI();
|
setupUI();
|
||||||
|
|
||||||
@ -14,6 +14,11 @@ VNewDirDialog::VNewDirDialog(const QString &title, const QString &name, const QS
|
|||||||
|
|
||||||
void VNewDirDialog::setupUI()
|
void VNewDirDialog::setupUI()
|
||||||
{
|
{
|
||||||
|
QLabel *infoLabel = NULL;
|
||||||
|
if (!info.isEmpty()) {
|
||||||
|
infoLabel = new QLabel(info);
|
||||||
|
}
|
||||||
|
|
||||||
nameLabel = new QLabel(name);
|
nameLabel = new QLabel(name);
|
||||||
nameEdit = new QLineEdit(defaultName);
|
nameEdit = new QLineEdit(defaultName);
|
||||||
nameEdit->selectAll();
|
nameEdit->selectAll();
|
||||||
@ -23,7 +28,7 @@ void VNewDirDialog::setupUI()
|
|||||||
okBtn->setDefault(true);
|
okBtn->setDefault(true);
|
||||||
cancelBtn = new QPushButton(tr("&Cancel"));
|
cancelBtn = new QPushButton(tr("&Cancel"));
|
||||||
|
|
||||||
QVBoxLayout *topLayout = new QVBoxLayout();
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
||||||
topLayout->addWidget(nameLabel);
|
topLayout->addWidget(nameLabel);
|
||||||
topLayout->addWidget(nameEdit);
|
topLayout->addWidget(nameEdit);
|
||||||
|
|
||||||
@ -33,6 +38,9 @@ void VNewDirDialog::setupUI()
|
|||||||
btmLayout->addWidget(cancelBtn);
|
btmLayout->addWidget(cancelBtn);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
if (infoLabel) {
|
||||||
|
mainLayout->addWidget(infoLabel);
|
||||||
|
}
|
||||||
mainLayout->addLayout(topLayout);
|
mainLayout->addLayout(topLayout);
|
||||||
mainLayout->addLayout(btmLayout);
|
mainLayout->addLayout(btmLayout);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
@ -12,7 +12,7 @@ class VNewDirDialog : public QDialog
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VNewDirDialog(const QString &title, const QString &name,
|
VNewDirDialog(const QString &title, const QString &info, const QString &name,
|
||||||
const QString &defaultName, QWidget *parent = 0);
|
const QString &defaultName, QWidget *parent = 0);
|
||||||
QString getNameInput() const;
|
QString getNameInput() const;
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ private:
|
|||||||
QPushButton *cancelBtn;
|
QPushButton *cancelBtn;
|
||||||
|
|
||||||
QString title;
|
QString title;
|
||||||
|
QString info;
|
||||||
QString name;
|
QString name;
|
||||||
QString defaultName;
|
QString defaultName;
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#include "vnewfiledialog.h"
|
#include "vnewfiledialog.h"
|
||||||
|
|
||||||
VNewFileDialog::VNewFileDialog(const QString &title, const QString &name, const QString &defaultName,
|
VNewFileDialog::VNewFileDialog(const QString &title, const QString &info, const QString &name,
|
||||||
QWidget *parent)
|
const QString &defaultName, QWidget *parent)
|
||||||
: QDialog(parent), title(title), name(name), defaultName(defaultName)
|
: QDialog(parent), title(title), info(info), name(name), defaultName(defaultName)
|
||||||
{
|
{
|
||||||
setupUI();
|
setupUI();
|
||||||
|
|
||||||
@ -14,6 +14,11 @@ VNewFileDialog::VNewFileDialog(const QString &title, const QString &name, const
|
|||||||
|
|
||||||
void VNewFileDialog::setupUI()
|
void VNewFileDialog::setupUI()
|
||||||
{
|
{
|
||||||
|
QLabel *infoLabel = NULL;
|
||||||
|
if (!info.isEmpty()) {
|
||||||
|
infoLabel = new QLabel(info);
|
||||||
|
}
|
||||||
|
|
||||||
nameLabel = new QLabel(name);
|
nameLabel = new QLabel(name);
|
||||||
nameEdit = new QLineEdit(defaultName);
|
nameEdit = new QLineEdit(defaultName);
|
||||||
nameEdit->selectAll();
|
nameEdit->selectAll();
|
||||||
@ -23,7 +28,7 @@ void VNewFileDialog::setupUI()
|
|||||||
okBtn->setDefault(true);
|
okBtn->setDefault(true);
|
||||||
cancelBtn = new QPushButton(tr("&Cancel"));
|
cancelBtn = new QPushButton(tr("&Cancel"));
|
||||||
|
|
||||||
QVBoxLayout *topLayout = new QVBoxLayout();
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
||||||
topLayout->addWidget(nameLabel);
|
topLayout->addWidget(nameLabel);
|
||||||
topLayout->addWidget(nameEdit);
|
topLayout->addWidget(nameEdit);
|
||||||
|
|
||||||
@ -33,6 +38,9 @@ void VNewFileDialog::setupUI()
|
|||||||
btmLayout->addWidget(cancelBtn);
|
btmLayout->addWidget(cancelBtn);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
if (infoLabel) {
|
||||||
|
mainLayout->addWidget(infoLabel);
|
||||||
|
}
|
||||||
mainLayout->addLayout(topLayout);
|
mainLayout->addLayout(topLayout);
|
||||||
mainLayout->addLayout(btmLayout);
|
mainLayout->addLayout(btmLayout);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
@ -12,8 +12,8 @@ class VNewFileDialog : public QDialog
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VNewFileDialog(const QString &title, const QString &name, const QString &defaultName,
|
VNewFileDialog(const QString &title, const QString &info, const QString &name,
|
||||||
QWidget *parent = 0);
|
const QString &defaultName, QWidget *parent = 0);
|
||||||
QString getNameInput() const;
|
QString getNameInput() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@ -28,6 +28,7 @@ private:
|
|||||||
QPushButton *cancelBtn;
|
QPushButton *cancelBtn;
|
||||||
|
|
||||||
QString title;
|
QString title;
|
||||||
|
QString info;
|
||||||
QString name;
|
QString name;
|
||||||
QString defaultName;
|
QString defaultName;
|
||||||
};
|
};
|
||||||
|
12
src/src.pro
12
src/src.pro
@ -23,7 +23,6 @@ SOURCES += main.cpp\
|
|||||||
vfilelist.cpp \
|
vfilelist.cpp \
|
||||||
dialog/vnewfiledialog.cpp \
|
dialog/vnewfiledialog.cpp \
|
||||||
vedit.cpp \
|
vedit.cpp \
|
||||||
vnotefile.cpp \
|
|
||||||
vdocument.cpp \
|
vdocument.cpp \
|
||||||
utils/vutils.cpp \
|
utils/vutils.cpp \
|
||||||
vpreviewpage.cpp \
|
vpreviewpage.cpp \
|
||||||
@ -43,8 +42,9 @@ SOURCES += main.cpp\
|
|||||||
vedittab.cpp \
|
vedittab.cpp \
|
||||||
voutline.cpp \
|
voutline.cpp \
|
||||||
vtoc.cpp \
|
vtoc.cpp \
|
||||||
vfilelocation.cpp \
|
vsingleinstanceguard.cpp \
|
||||||
vsingleinstanceguard.cpp
|
vdirectory.cpp \
|
||||||
|
vfile.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -56,7 +56,6 @@ HEADERS += vmainwindow.h \
|
|||||||
dialog/vnewfiledialog.h \
|
dialog/vnewfiledialog.h \
|
||||||
vedit.h \
|
vedit.h \
|
||||||
vconstants.h \
|
vconstants.h \
|
||||||
vnotefile.h \
|
|
||||||
vdocument.h \
|
vdocument.h \
|
||||||
utils/vutils.h \
|
utils/vutils.h \
|
||||||
vpreviewpage.h \
|
vpreviewpage.h \
|
||||||
@ -76,8 +75,9 @@ HEADERS += vmainwindow.h \
|
|||||||
vedittab.h \
|
vedittab.h \
|
||||||
voutline.h \
|
voutline.h \
|
||||||
vtoc.h \
|
vtoc.h \
|
||||||
vfilelocation.h \
|
vsingleinstanceguard.h \
|
||||||
vsingleinstanceguard.h
|
vdirectory.h \
|
||||||
|
vfile.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc
|
vnote.qrc
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
VUtils::VUtils()
|
VUtils::VUtils()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -202,3 +201,38 @@ bool VUtils::copyFile(const QString &p_srcFilePath, const QString &p_destFilePat
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VUtils::showMessage(QMessageBox::Icon p_icon, const QString &p_title, const QString &p_text, const QString &p_infoText,
|
||||||
|
QMessageBox::StandardButtons p_buttons, QMessageBox::StandardButton p_defaultBtn, QWidget *p_parent)
|
||||||
|
{
|
||||||
|
QMessageBox msgBox(p_icon, p_title, p_text, p_buttons, p_parent);
|
||||||
|
msgBox.setInformativeText(p_infoText);
|
||||||
|
msgBox.setDefaultButton(p_defaultBtn);
|
||||||
|
return msgBox.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VUtils::generateCopiedFileName(const QString &p_dirPath, const QString &p_fileName)
|
||||||
|
{
|
||||||
|
QString suffix;
|
||||||
|
QString base = p_fileName;
|
||||||
|
int dotIdx = p_fileName.lastIndexOf('.');
|
||||||
|
if (dotIdx != -1) {
|
||||||
|
// .md
|
||||||
|
suffix = p_fileName.right(p_fileName.size() - dotIdx);
|
||||||
|
base = p_fileName.left(dotIdx);
|
||||||
|
}
|
||||||
|
QDir dir(p_dirPath);
|
||||||
|
QString name = p_fileName;
|
||||||
|
QString filePath = dir.filePath(name);
|
||||||
|
int index = 0;
|
||||||
|
while (QFile(filePath).exists()) {
|
||||||
|
QString seq;
|
||||||
|
if (index > 0) {
|
||||||
|
seq = QString::number(index);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
name = QString("%1_copy%2%3").arg(base).arg(seq).arg(suffix);
|
||||||
|
filePath = dir.filePath(name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QMessageBox>
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ public:
|
|||||||
static QRgb QRgbFromString(const QString &str);
|
static QRgb QRgbFromString(const QString &str);
|
||||||
static QString generateImageFileName(const QString &path, const QString &title,
|
static QString generateImageFileName(const QString &path, const QString &title,
|
||||||
const QString &format = "png");
|
const QString &format = "png");
|
||||||
|
static QString generateCopiedFileName(const QString &p_dirPath, const QString &p_fileName);
|
||||||
static void processStyle(QString &style, const QVector<QPair<QString, QString> > &varMap);
|
static void processStyle(QString &style, const QVector<QPair<QString, QString> > &varMap);
|
||||||
static bool isMarkdown(const QString &fileName);
|
static bool isMarkdown(const QString &fileName);
|
||||||
static inline QString directoryNameFromPath(const QString& path);
|
static inline QString directoryNameFromPath(const QString& path);
|
||||||
@ -28,6 +30,9 @@ public:
|
|||||||
static void makeDirectory(const QString &path);
|
static void makeDirectory(const QString &path);
|
||||||
static ClipboardOpType opTypeInClipboard();
|
static ClipboardOpType opTypeInClipboard();
|
||||||
static bool copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut);
|
static bool copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut);
|
||||||
|
static int showMessage(QMessageBox::Icon p_icon, const QString &p_title, const QString &p_text,
|
||||||
|
const QString &p_infoText, QMessageBox::StandardButtons p_buttons,
|
||||||
|
QMessageBox::StandardButton p_defaultBtn, QWidget *p_parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString VUtils::directoryNameFromPath(const QString &path)
|
inline QString VUtils::directoryNameFromPath(const QString &path)
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
|
|
||||||
enum class DocType { Html, Markdown };
|
enum class DocType { Html, Markdown };
|
||||||
enum class ClipboardOpType { Invalid, CopyFile, CopyDir };
|
enum class ClipboardOpType { Invalid, CopyFile, CopyDir };
|
||||||
|
enum class OpenFileMode {Read = 0, Edit};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
468
src/vdirectory.cpp
Normal file
468
src/vdirectory.cpp
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
#include "vdirectory.h"
|
||||||
|
#include <QDir>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
|
VDirectory::VDirectory(VNotebook *p_notebook,
|
||||||
|
const QString &p_name, QObject *p_parent)
|
||||||
|
: QObject(p_parent), m_notebook(p_notebook), m_name(p_name), m_opened(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VDirectory::open()
|
||||||
|
{
|
||||||
|
if (m_opened) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Q_ASSERT(m_subDirs.isEmpty() && m_files.isEmpty());
|
||||||
|
QString path = retrivePath();
|
||||||
|
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
||||||
|
if (configJson.isEmpty()) {
|
||||||
|
qWarning() << "invalid directory configuration in path" << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [sub_directories] section
|
||||||
|
QJsonArray dirJson = configJson["sub_directories"].toArray();
|
||||||
|
for (int i = 0; i < dirJson.size(); ++i) {
|
||||||
|
QJsonObject dirItem = dirJson[i].toObject();
|
||||||
|
VDirectory *dir = new VDirectory(m_notebook, dirItem["name"].toString(), this);
|
||||||
|
m_subDirs.append(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [files] section
|
||||||
|
QJsonArray fileJson = configJson["files"].toArray();
|
||||||
|
for (int i = 0; i < fileJson.size(); ++i) {
|
||||||
|
QJsonObject fileItem = fileJson[i].toObject();
|
||||||
|
VFile *file = new VFile(fileItem["name"].toString(), this);
|
||||||
|
m_files.append(file);
|
||||||
|
}
|
||||||
|
m_opened = true;
|
||||||
|
qDebug() << "dir" << m_name << "open" << m_subDirs.size() << "sub directories" << m_files.size() << "files";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VDirectory::close()
|
||||||
|
{
|
||||||
|
if (!m_opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_subDirs.size(); ++i) {
|
||||||
|
VDirectory *dir = m_subDirs[i];
|
||||||
|
dir->close();
|
||||||
|
delete dir;
|
||||||
|
}
|
||||||
|
m_subDirs.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < m_files.size(); ++i) {
|
||||||
|
VFile *file = m_files[i];
|
||||||
|
file->close();
|
||||||
|
delete file;
|
||||||
|
}
|
||||||
|
m_files.clear();
|
||||||
|
|
||||||
|
m_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VDirectory::retrivePath(const VDirectory *p_dir) const
|
||||||
|
{
|
||||||
|
if (!p_dir) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
VDirectory *parentDir = (VDirectory *)p_dir->parent();
|
||||||
|
if (parentDir) {
|
||||||
|
// Not the root directory
|
||||||
|
return QDir(retrivePath(parentDir)).filePath(p_dir->getName());
|
||||||
|
} else {
|
||||||
|
return m_notebook->getPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VDirectory::retriveRelativePath(const VDirectory *p_dir) const
|
||||||
|
{
|
||||||
|
if (!p_dir) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
VDirectory *parentDir = (VDirectory *)p_dir->parent();
|
||||||
|
if (parentDir) {
|
||||||
|
// Not the root directory
|
||||||
|
return QDir(retriveRelativePath(parentDir)).filePath(p_dir->getName());
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject VDirectory::createDirectoryJson() const
|
||||||
|
{
|
||||||
|
QJsonObject dirJson;
|
||||||
|
dirJson["version"] = "1";
|
||||||
|
dirJson["sub_directories"] = QJsonArray();
|
||||||
|
dirJson["files"] = QJsonArray();
|
||||||
|
return dirJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDirectory *VDirectory::createSubDirectory(const QString &p_name)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!p_name.isEmpty());
|
||||||
|
// First open current directory
|
||||||
|
if (!open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
QString path = retrivePath();
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.mkdir(p_name)) {
|
||||||
|
qWarning() << "failed to create directory" << p_name << "under" << path;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject subJson = createDirectoryJson();
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(QDir::cleanPath(QDir(path).filePath(p_name)), subJson)) {
|
||||||
|
dir.rmdir(p_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update parent's config file to include this new directory
|
||||||
|
QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
|
||||||
|
Q_ASSERT(!dirJson.isEmpty());
|
||||||
|
QJsonObject itemJson;
|
||||||
|
itemJson["name"] = p_name;
|
||||||
|
QJsonArray subDirArray = dirJson["sub_directories"].toArray();
|
||||||
|
subDirArray.append(itemJson);
|
||||||
|
dirJson["sub_directories"] = subDirArray;
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
|
||||||
|
VConfigManager::deleteDirectoryConfig(QDir(path).filePath(p_name));
|
||||||
|
dir.rmdir(p_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDirectory *ret = new VDirectory(m_notebook, p_name, this);
|
||||||
|
m_subDirs.append(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDirectory *VDirectory::findSubDirectory(const QString &p_name)
|
||||||
|
{
|
||||||
|
if (!m_opened && !open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < m_subDirs.size(); ++i) {
|
||||||
|
if (p_name == m_subDirs[i]->getName()) {
|
||||||
|
return m_subDirs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *VDirectory::findFile(const QString &p_name)
|
||||||
|
{
|
||||||
|
if (!m_opened && !open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < m_files.size(); ++i) {
|
||||||
|
if (p_name == m_files[i]->getName()) {
|
||||||
|
return m_files[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *VDirectory::createFile(const QString &p_name)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!p_name.isEmpty());
|
||||||
|
if (!open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
QString path = retrivePath();
|
||||||
|
QString filePath = QDir(path).filePath(p_name);
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
qWarning() << "failed to create file" << p_name;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
qDebug() << "file created" << p_name;
|
||||||
|
|
||||||
|
if (!createFileInConfig(p_name)) {
|
||||||
|
file.remove();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *ret = new VFile(p_name, this);
|
||||||
|
m_files.append(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VDirectory::createFileInConfig(const QString &p_name, int p_index)
|
||||||
|
{
|
||||||
|
QString path = retrivePath();
|
||||||
|
QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
|
||||||
|
Q_ASSERT(!dirJson.isEmpty());
|
||||||
|
QJsonObject itemJson;
|
||||||
|
itemJson["name"] = p_name;
|
||||||
|
QJsonArray fileArray = dirJson["files"].toArray();
|
||||||
|
if (p_index == -1) {
|
||||||
|
fileArray.append(itemJson);
|
||||||
|
} else {
|
||||||
|
fileArray.insert(p_index, itemJson);
|
||||||
|
}
|
||||||
|
dirJson["files"] = fileArray;
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *VDirectory::addFile(VFile *p_file, int p_index)
|
||||||
|
{
|
||||||
|
if (!open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!createFileInConfig(p_file->getName(), p_index)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (p_index == -1) {
|
||||||
|
m_files.append(p_file);
|
||||||
|
} else {
|
||||||
|
m_files.insert(p_index, p_file);
|
||||||
|
}
|
||||||
|
p_file->setParent(this);
|
||||||
|
return p_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *VDirectory::addFile(const QString &p_name, int p_index)
|
||||||
|
{
|
||||||
|
if (!open()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!createFileInConfig(p_name, p_index)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
VFile *file = new VFile(p_name, this);
|
||||||
|
if (!file) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (p_index == -1) {
|
||||||
|
m_files.append(file);
|
||||||
|
} else {
|
||||||
|
m_files.insert(p_index, file);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VDirectory::deleteSubDirectory(VDirectory *p_subDir)
|
||||||
|
{
|
||||||
|
if (!open()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString path = retrivePath();
|
||||||
|
|
||||||
|
int index;
|
||||||
|
for (index = 0; index < m_subDirs.size(); ++index) {
|
||||||
|
if (m_subDirs[index] == p_subDir) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == m_subDirs.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_subDirs.remove(index);
|
||||||
|
QString name = p_subDir->getName();
|
||||||
|
// Update config to exclude this directory
|
||||||
|
QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
|
||||||
|
QJsonArray subDirArray = dirJson["sub_directories"].toArray();
|
||||||
|
bool deleted = false;
|
||||||
|
for (int i = 0; i < subDirArray.size(); ++i) {
|
||||||
|
QJsonObject ele = subDirArray[i].toObject();
|
||||||
|
if (ele["name"].toString() == name) {
|
||||||
|
subDirArray.removeAt(i);
|
||||||
|
deleted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(deleted);
|
||||||
|
dirJson["sub_directories"] = subDirArray;
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
|
||||||
|
qWarning() << "failed to update configuration in" << path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the entire directory
|
||||||
|
p_subDir->close();
|
||||||
|
delete p_subDir;
|
||||||
|
QString dirName = QDir(path).filePath(name);
|
||||||
|
QDir dir(dirName);
|
||||||
|
if (!dir.removeRecursively()) {
|
||||||
|
qWarning() << "failed to delete" << dirName << "recursively";
|
||||||
|
} else {
|
||||||
|
qDebug() << "deleted" << dirName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After calling this, p_file->parent() remain the same.
|
||||||
|
int VDirectory::removeFile(VFile *p_file)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_opened);
|
||||||
|
Q_ASSERT(p_file);
|
||||||
|
|
||||||
|
QString path = retrivePath();
|
||||||
|
|
||||||
|
int index;
|
||||||
|
for (index = 0; index < m_files.size(); ++index) {
|
||||||
|
if (m_files[index] == p_file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(index != m_files.size());
|
||||||
|
m_files.remove(index);
|
||||||
|
QString name = p_file->getName();
|
||||||
|
|
||||||
|
// Update config to exclude this file
|
||||||
|
QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
|
||||||
|
QJsonArray subFileArray = dirJson["files"].toArray();
|
||||||
|
bool deleted = false;
|
||||||
|
for (int i = 0; i < subFileArray.size(); ++i) {
|
||||||
|
QJsonObject ele = subFileArray[i].toObject();
|
||||||
|
if (ele["name"].toString() == name) {
|
||||||
|
subFileArray.removeAt(i);
|
||||||
|
deleted = true;
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(deleted);
|
||||||
|
dirJson["files"] = subFileArray;
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
|
||||||
|
qWarning() << "failed to update configuration in" << path;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VDirectory::deleteFile(VFile *p_file)
|
||||||
|
{
|
||||||
|
removeFile(p_file);
|
||||||
|
|
||||||
|
// Delete the file
|
||||||
|
Q_ASSERT(!p_file->isOpened());
|
||||||
|
p_file->deleteDiskFile();
|
||||||
|
delete p_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VDirectory::rename(const QString &p_name)
|
||||||
|
{
|
||||||
|
if (m_name == p_name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
VDirectory *parentDir = getParentDirectory();
|
||||||
|
Q_ASSERT(parentDir);
|
||||||
|
QString parentPath = parentDir->retrivePath();
|
||||||
|
QDir dir(parentPath);
|
||||||
|
QString name = m_name;
|
||||||
|
if (!dir.rename(m_name, p_name)) {
|
||||||
|
qWarning() << "failed to rename directory" << m_name << "to" << p_name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_name = p_name;
|
||||||
|
|
||||||
|
// Update parent's config file
|
||||||
|
QJsonObject dirJson = VConfigManager::readDirectoryConfig(parentPath);
|
||||||
|
QJsonArray subDirArray = dirJson["sub_directories"].toArray();
|
||||||
|
int index = 0;
|
||||||
|
for (index = 0; index < subDirArray.size(); ++index) {
|
||||||
|
QJsonObject ele = subDirArray[index].toObject();
|
||||||
|
if (ele["name"].toString() == name) {
|
||||||
|
ele["name"] = p_name;
|
||||||
|
subDirArray[index] = ele;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_ASSERT(index != subDirArray.size());
|
||||||
|
dirJson["sub_directories"] = subDirArray;
|
||||||
|
if (!VConfigManager::writeDirectoryConfig(parentPath, dirJson)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName,
|
||||||
|
VFile *p_srcFile, bool p_cut)
|
||||||
|
{
|
||||||
|
QString srcPath = QDir::cleanPath(p_srcFile->retrivePath());
|
||||||
|
QString destPath = QDir::cleanPath(QDir(p_destDir->retrivePath()).filePath(p_destName));
|
||||||
|
if (srcPath == destPath) {
|
||||||
|
return p_srcFile;
|
||||||
|
}
|
||||||
|
VDirectory *srcDir = p_srcFile->getDirectory();
|
||||||
|
DocType docType = p_srcFile->getDocType();
|
||||||
|
DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html;
|
||||||
|
|
||||||
|
QVector<QString> images;
|
||||||
|
if (docType == DocType::Markdown) {
|
||||||
|
images = VUtils::imagesFromMarkdownFile(srcPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the file
|
||||||
|
if (!VUtils::copyFile(srcPath, destPath, p_cut)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle VDirectory and VFile
|
||||||
|
int index = -1;
|
||||||
|
VFile *destFile = NULL;
|
||||||
|
if (p_cut) {
|
||||||
|
// Remove the file from config
|
||||||
|
index = srcDir->removeFile(p_srcFile);
|
||||||
|
p_srcFile->setName(p_destName);
|
||||||
|
if (srcDir != p_destDir) {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
// Add the file to new dir's config
|
||||||
|
destFile = p_destDir->addFile(p_srcFile, index);
|
||||||
|
} else {
|
||||||
|
destFile = p_destDir->addFile(p_destName, -1);
|
||||||
|
}
|
||||||
|
if (!destFile) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (docType != newDocType) {
|
||||||
|
destFile->convert(docType, newDocType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to copy images when it is still markdown
|
||||||
|
if (!images.isEmpty()) {
|
||||||
|
if (newDocType == DocType::Markdown) {
|
||||||
|
QString dirPath = destFile->retriveImagePath();
|
||||||
|
VUtils::makeDirectory(dirPath);
|
||||||
|
int nrPasted = 0;
|
||||||
|
for (int i = 0; i < images.size(); ++i) {
|
||||||
|
if (!QFile(images[i]).exists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString destImagePath = QDir(dirPath).filePath(VUtils::fileNameFromPath(images[i]));
|
||||||
|
// Copy or Cut the images accordingly.
|
||||||
|
if (VUtils::copyFile(images[i], destImagePath, p_cut)) {
|
||||||
|
nrPasted++;
|
||||||
|
} else {
|
||||||
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Failed to copy image %1.").arg(images[i]),
|
||||||
|
tr("Please check if there already exists a file with the same name and manually copy it"),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "pasted" << nrPasted << "images sucessfully";
|
||||||
|
} else {
|
||||||
|
// Delete the images
|
||||||
|
for (int i = 0; i < images.size(); ++i) {
|
||||||
|
QFile file(images[i]);
|
||||||
|
file.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return destFile;
|
||||||
|
}
|
109
src/vdirectory.h
Normal file
109
src/vdirectory.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#ifndef VDIRECTORY_H
|
||||||
|
#define VDIRECTORY_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include "vnotebook.h"
|
||||||
|
|
||||||
|
class VFile;
|
||||||
|
|
||||||
|
class VDirectory : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VDirectory(VNotebook *p_notebook,
|
||||||
|
const QString &p_name, QObject *p_parent = 0);
|
||||||
|
bool open();
|
||||||
|
void close();
|
||||||
|
VDirectory *createSubDirectory(const QString &p_name);
|
||||||
|
VDirectory *findSubDirectory(const QString &p_name);
|
||||||
|
VFile *findFile(const QString &p_name);
|
||||||
|
VFile *createFile(const QString &p_name);
|
||||||
|
void deleteSubDirectory(VDirectory *p_subDir);
|
||||||
|
// Remove the file in the config and m_files without deleting it in the disk.
|
||||||
|
int removeFile(VFile *p_file);
|
||||||
|
// Add the file in the config and m_files. If @p_index is -1, add it at the end.
|
||||||
|
// Return the VFile if succeed.
|
||||||
|
VFile *addFile(VFile *p_file, int p_index);
|
||||||
|
VFile *addFile(const QString &p_name, int p_index);
|
||||||
|
void deleteFile(VFile *p_file);
|
||||||
|
bool rename(const QString &p_name);
|
||||||
|
|
||||||
|
inline const QVector<VDirectory *> &getSubDirs() const;
|
||||||
|
inline const QString &getName() const;
|
||||||
|
inline bool isOpened() const;
|
||||||
|
inline VDirectory *getParentDirectory();
|
||||||
|
inline const QVector<VFile *> &getFiles() const;
|
||||||
|
inline QString retrivePath() const;
|
||||||
|
inline QString retriveRelativePath() const;
|
||||||
|
inline QString retriveNotebook() const;
|
||||||
|
|
||||||
|
// Copy @p_srcFile to @p_destDir, setting new name to @p_destName.
|
||||||
|
// @p_cut: copy or cut. Returns the dest VFile.
|
||||||
|
static VFile *copyFile(VDirectory *p_destDir, const QString &p_destName,
|
||||||
|
VFile *p_srcFile, bool p_cut);
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Get the path of @p_dir recursively
|
||||||
|
QString retrivePath(const VDirectory *p_dir) const;
|
||||||
|
// Get teh relative path of @p_dir recursively related to the notebook path
|
||||||
|
QString retriveRelativePath(const VDirectory *p_dir) const;
|
||||||
|
QJsonObject createDirectoryJson() const;
|
||||||
|
bool createFileInConfig(const QString &p_name, int p_index = -1);
|
||||||
|
|
||||||
|
QPointer<VNotebook> m_notebook;
|
||||||
|
QString m_name;
|
||||||
|
// Owner of the sub-directories
|
||||||
|
QVector<VDirectory *> m_subDirs;
|
||||||
|
// Owner of the files
|
||||||
|
QVector<VFile *> m_files;
|
||||||
|
bool m_opened;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QVector<VDirectory *> &VDirectory::getSubDirs() const
|
||||||
|
{
|
||||||
|
return m_subDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QString &VDirectory::getName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VDirectory::isOpened() const
|
||||||
|
{
|
||||||
|
return m_opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VDirectory *VDirectory::getParentDirectory()
|
||||||
|
{
|
||||||
|
return (VDirectory *)this->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QVector<VFile *> &VDirectory::getFiles() const
|
||||||
|
{
|
||||||
|
return m_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VDirectory::retriveNotebook() const
|
||||||
|
{
|
||||||
|
return m_notebook->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VDirectory::retrivePath() const
|
||||||
|
{
|
||||||
|
return retrivePath(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VDirectory::retriveRelativePath() const
|
||||||
|
{
|
||||||
|
return retriveRelativePath(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VDIRECTORY_H
|
@ -4,6 +4,8 @@
|
|||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "dialog/vdirinfodialog.h"
|
#include "dialog/vdirinfodialog.h"
|
||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
|
VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
|
||||||
: QTreeWidget(parent), vnote(vnote)
|
: QTreeWidget(parent), vnote(vnote)
|
||||||
@ -14,7 +16,7 @@ VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
|
|||||||
initActions();
|
initActions();
|
||||||
|
|
||||||
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
||||||
this, SLOT(updateItemSubtree(QTreeWidgetItem*)));
|
this, SLOT(updateChildren(QTreeWidgetItem*)));
|
||||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)),
|
connect(this, SIGNAL(customContextMenuRequested(QPoint)),
|
||||||
this, SLOT(contextMenuRequested(QPoint)));
|
this, SLOT(contextMenuRequested(QPoint)));
|
||||||
connect(this, &VDirectoryTree::currentItemChanged,
|
connect(this, &VDirectoryTree::currentItemChanged,
|
||||||
@ -29,11 +31,6 @@ void VDirectoryTree::initActions()
|
|||||||
connect(newRootDirAct, &QAction::triggered,
|
connect(newRootDirAct, &QAction::triggered,
|
||||||
this, &VDirectoryTree::newRootDirectory);
|
this, &VDirectoryTree::newRootDirectory);
|
||||||
|
|
||||||
newSiblingDirAct = new QAction(tr("New &sibling directory"), this);
|
|
||||||
newSiblingDirAct->setStatusTip(tr("Create a new sibling directory at current level"));
|
|
||||||
connect(newSiblingDirAct, &QAction::triggered,
|
|
||||||
this, &VDirectoryTree::newSiblingDirectory);
|
|
||||||
|
|
||||||
newSubDirAct = new QAction(tr("&New sub-directory"), this);
|
newSubDirAct = new QAction(tr("&New sub-directory"), this);
|
||||||
newSubDirAct->setStatusTip(tr("Create a new sub-directory"));
|
newSubDirAct->setStatusTip(tr("Create a new sub-directory"));
|
||||||
connect(newSubDirAct, &QAction::triggered,
|
connect(newSubDirAct, &QAction::triggered,
|
||||||
@ -52,208 +49,159 @@ void VDirectoryTree::initActions()
|
|||||||
this, &VDirectoryTree::editDirectoryInfo);
|
this, &VDirectoryTree::editDirectoryInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::setNotebook(const QString& notebookName)
|
void VDirectoryTree::setNotebook(VNotebook *p_notebook)
|
||||||
{
|
{
|
||||||
if (notebook == notebookName) {
|
if (m_notebook == p_notebook) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
notebook = notebookName;
|
if (m_notebook) {
|
||||||
treePath = "";
|
// Disconnect
|
||||||
if (notebook.isEmpty()) {
|
disconnect((VNotebook *)m_notebook, &VNotebook::contentChanged,
|
||||||
|
this, &VDirectoryTree::updateDirectoryTree);
|
||||||
|
}
|
||||||
|
m_notebook = p_notebook;
|
||||||
|
if (m_notebook) {
|
||||||
|
connect((VNotebook *)m_notebook, &VNotebook::contentChanged,
|
||||||
|
this, &VDirectoryTree::updateDirectoryTree);
|
||||||
|
} else {
|
||||||
clear();
|
clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QVector<VNotebook *> ¬ebooks = vnote->getNotebooks();
|
if (!m_notebook->open()) {
|
||||||
for (int i = 0; i < notebooks.size(); ++i) {
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
if (notebooks[i]->getName() == notebook) {
|
QString("Failed to open notebook %1").arg(m_notebook->getName()), "",
|
||||||
treePath = notebooks[i]->getPath();
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
break;
|
clear();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Q_ASSERT(!treePath.isEmpty());
|
|
||||||
|
|
||||||
updateDirectoryTree();
|
updateDirectoryTree();
|
||||||
if (topLevelItemCount() > 0) {
|
|
||||||
setCurrentItem(topLevelItem(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VDirectoryTree::validatePath(const QString &path)
|
void VDirectoryTree::fillTreeItem(QTreeWidgetItem &p_item, const QString &p_name,
|
||||||
|
VDirectory *p_directory, const QIcon &p_icon)
|
||||||
{
|
{
|
||||||
return QDir(path).exists();
|
p_item.setText(0, p_name);
|
||||||
|
p_item.setData(0, Qt::UserRole, QVariant::fromValue(p_directory));
|
||||||
|
p_item.setIcon(0, p_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::updateDirectoryTree()
|
void VDirectoryTree::updateDirectoryTree()
|
||||||
{
|
{
|
||||||
updateDirectoryTreeTopLevel();
|
|
||||||
|
|
||||||
int nrTopLevelItems = topLevelItemCount();
|
|
||||||
for (int i = 0; i < nrTopLevelItems; ++i) {
|
|
||||||
QTreeWidgetItem *item = topLevelItem(i);
|
|
||||||
Q_ASSERT(item);
|
|
||||||
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
updateDirectoryTreeOne(*item, itemJson["name"].toString(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson)
|
|
||||||
{
|
|
||||||
item.setText(0, itemJson["name"].toString());
|
|
||||||
item.setData(0, Qt::UserRole, itemJson);
|
|
||||||
item.setIcon(0, QIcon(":/resources/icons/dir_item.svg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* VDirectoryTree::insertDirectoryTreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding,
|
|
||||||
const QJsonObject &newItem)
|
|
||||||
{
|
|
||||||
QTreeWidgetItem *item;
|
|
||||||
if (parent) {
|
|
||||||
if (preceding) {
|
|
||||||
item = new QTreeWidgetItem(parent, preceding);
|
|
||||||
} else {
|
|
||||||
item = new QTreeWidgetItem(parent);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (preceding) {
|
|
||||||
item = new QTreeWidgetItem(this, preceding);
|
|
||||||
} else {
|
|
||||||
item = new QTreeWidgetItem(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fillDirectoryTreeItem(*item, newItem);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::removeDirectoryTreeItem(QTreeWidgetItem *item)
|
|
||||||
{
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::updateDirectoryTreeTopLevel()
|
|
||||||
{
|
|
||||||
const QString &path = treePath;
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
VDirectory *rootDir = m_notebook->getRootDir();
|
||||||
|
const QVector<VDirectory *> &subDirs = rootDir->getSubDirs();
|
||||||
|
for (int i = 0; i < subDirs.size(); ++i) {
|
||||||
|
VDirectory *dir = subDirs[i];
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(this);
|
||||||
|
|
||||||
if (!validatePath(path)) {
|
fillTreeItem(*item, dir->getName(), dir,
|
||||||
qDebug() << "invalid notebook path:" << path;
|
QIcon(":/resources/icons/dir_item.svg"));
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook path."),
|
|
||||||
QMessageBox::Ok, this);
|
updateDirectoryTreeOne(item, 1);
|
||||||
msgBox.setInformativeText(QString("Notebook path \"%1\" either does not exist or is not valid.")
|
}
|
||||||
.arg(path));
|
setCurrentItem(topLevelItem(0));
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int depth)
|
||||||
if (configJson.isEmpty()) {
|
|
||||||
qDebug() << "invalid notebook configuration for path:" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook configuration."),
|
|
||||||
QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Notebook path \"%1\" does not contain a valid configuration file.")
|
|
||||||
.arg(path));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle sub_directories section
|
|
||||||
QJsonArray dirJson = configJson["sub_directories"].toArray();
|
|
||||||
QTreeWidgetItem *preItem = NULL;
|
|
||||||
for (int i = 0; i < dirJson.size(); ++i) {
|
|
||||||
QJsonObject dirItem = dirJson[i].toObject();
|
|
||||||
QTreeWidgetItem *treeItem = insertDirectoryTreeItem(NULL, preItem, dirItem);
|
|
||||||
preItem = treeItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "updated" << dirJson.size() << "top-level items";
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem &parent, const QString &relativePath,
|
|
||||||
int depth)
|
|
||||||
{
|
{
|
||||||
Q_ASSERT(parent.childCount() == 0);
|
Q_ASSERT(p_parent->childCount() == 0);
|
||||||
// Going deep enough
|
|
||||||
if (depth <= 0) {
|
if (depth <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
VDirectory *dir = getVDirectory(p_parent);
|
||||||
qDebug() << "update directory" << relativePath;
|
if (!dir->open()) {
|
||||||
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
QString path(QDir::cleanPath(treePath + QDir::separator() + relativePath));
|
QString("Failed to open directory %1").arg(dir->getName()), "",
|
||||||
if (!validatePath(path)) {
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
qDebug() << "invalide notebook directory:" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook directory."),
|
|
||||||
QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Notebook directory \"%1\" either does not exist or is not a valid notebook directory.")
|
|
||||||
.arg(path));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const QVector<VDirectory *> &subDirs = dir->getSubDirs();
|
||||||
|
for (int i = 0; i < subDirs.size(); ++i) {
|
||||||
|
VDirectory *subDir = subDirs[i];
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(p_parent);
|
||||||
|
|
||||||
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
fillTreeItem(*item, subDir->getName(), subDir,
|
||||||
if (configJson.isEmpty()) {
|
QIcon(":/resources/icons/dir_item.svg"));
|
||||||
qDebug() << "invalid notebook configuration for directory:" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook directory configuration."),
|
|
||||||
QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Notebook directory \"%1\" does not contain a valid configuration file.")
|
|
||||||
.arg(path));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle sub_directories section
|
updateDirectoryTreeOne(item, depth - 1);
|
||||||
QJsonArray dirJson = configJson["sub_directories"].toArray();
|
|
||||||
QTreeWidgetItem *preItem = NULL;
|
|
||||||
for (int i = 0; i < dirJson.size(); ++i) {
|
|
||||||
QJsonObject dirItem = dirJson[i].toObject();
|
|
||||||
QTreeWidgetItem *treeItem = insertDirectoryTreeItem(&parent, preItem, dirItem);
|
|
||||||
preItem = treeItem;
|
|
||||||
|
|
||||||
// Update its sub-directory recursively
|
|
||||||
updateDirectoryTreeOne(*treeItem, QDir::cleanPath(QDir(relativePath).filePath(dirItem["name"].toString())), depth - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VDirectoryTree::calculateItemRelativePath(QTreeWidgetItem *item)
|
// Update @p_item's children items
|
||||||
|
void VDirectoryTree::updateChildren(QTreeWidgetItem *p_item)
|
||||||
{
|
{
|
||||||
if (!item) {
|
Q_ASSERT(p_item);
|
||||||
return ".";
|
int nrChild = p_item->childCount();
|
||||||
}
|
|
||||||
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
QString name = itemJson["name"].toString();
|
|
||||||
Q_ASSERT(!name.isEmpty());
|
|
||||||
return QDir::cleanPath(calculateItemRelativePath(item->parent()) +
|
|
||||||
QDir::separator() + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::updateItemSubtree(QTreeWidgetItem *item)
|
|
||||||
{
|
|
||||||
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
QString relativePath = calculateItemRelativePath(item);
|
|
||||||
int nrChild = item->childCount();
|
|
||||||
if (nrChild == 0) {
|
if (nrChild == 0) {
|
||||||
updateDirectoryTreeOne(*item, relativePath, 2);
|
return;
|
||||||
} else {
|
}
|
||||||
for (int i = 0; i < nrChild; ++i) {
|
for (int i = 0; i < nrChild; ++i) {
|
||||||
QTreeWidgetItem *childItem = item->child(i);
|
QTreeWidgetItem *childItem = p_item->child(i);
|
||||||
if (childItem->childCount() > 0) {
|
if (childItem->childCount() > 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QJsonObject childJson = childItem->data(0, Qt::UserRole).toJsonObject();
|
updateDirectoryTreeOne(childItem, 1);
|
||||||
Q_ASSERT(!childJson.isEmpty());
|
|
||||||
updateDirectoryTreeOne(*childItem,
|
|
||||||
QDir::cleanPath(QDir(relativePath).filePath(childJson["name"].toString())), 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<QTreeWidgetItem *> VDirectoryTree::updateItemChildrenAdded(QTreeWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
QVector<QTreeWidgetItem *> ret;
|
||||||
|
QPointer<VDirectory> parentDir;
|
||||||
|
if (p_item) {
|
||||||
|
parentDir = getVDirectory(p_item);
|
||||||
|
} else {
|
||||||
|
parentDir = m_notebook->getRootDir();
|
||||||
|
}
|
||||||
|
const QVector<VDirectory *> &subDirs = parentDir->getSubDirs();
|
||||||
|
for (int i = 0; i < subDirs.size(); ++i) {
|
||||||
|
int nrChild;
|
||||||
|
if (p_item) {
|
||||||
|
nrChild = p_item->childCount();
|
||||||
|
} else {
|
||||||
|
nrChild = this->topLevelItemCount();
|
||||||
|
}
|
||||||
|
VDirectory *dir = subDirs[i];
|
||||||
|
QTreeWidgetItem *item;
|
||||||
|
if (i >= nrChild) {
|
||||||
|
if (p_item) {
|
||||||
|
item = new QTreeWidgetItem(p_item);
|
||||||
|
} else {
|
||||||
|
item = new QTreeWidgetItem(this);
|
||||||
|
}
|
||||||
|
fillTreeItem(*item, dir->getName(), dir, QIcon(":/resources/icons/dir_item.svg"));
|
||||||
|
updateDirectoryTreeOne(item, 1);
|
||||||
|
ret.append(item);
|
||||||
|
} else {
|
||||||
|
VDirectory *itemDir;
|
||||||
|
if (p_item) {
|
||||||
|
itemDir = getVDirectory(p_item->child(i));
|
||||||
|
} else {
|
||||||
|
itemDir = getVDirectory(topLevelItem(i));
|
||||||
|
}
|
||||||
|
if (itemDir != dir) {
|
||||||
|
item = new QTreeWidgetItem();
|
||||||
|
if (p_item) {
|
||||||
|
p_item->insertChild(i, item);
|
||||||
|
} else {
|
||||||
|
this->insertTopLevelItem(i, item);
|
||||||
|
}
|
||||||
|
fillTreeItem(*item, dir->getName(), dir, QIcon(":/resources/icons/dir_item.svg"));
|
||||||
|
updateDirectoryTreeOne(item, 1);
|
||||||
|
ret.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << ret.size() << "items added";
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::contextMenuRequested(QPoint pos)
|
void VDirectoryTree::contextMenuRequested(QPoint pos)
|
||||||
{
|
{
|
||||||
|
if (!m_notebook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QTreeWidgetItem *item = itemAt(pos);
|
QTreeWidgetItem *item = itemAt(pos);
|
||||||
QMenu menu(this);
|
QMenu menu(this);
|
||||||
|
|
||||||
@ -265,7 +213,6 @@ void VDirectoryTree::contextMenuRequested(QPoint pos)
|
|||||||
if (item->parent()) {
|
if (item->parent()) {
|
||||||
// Low-level item
|
// Low-level item
|
||||||
menu.addAction(newSubDirAct);
|
menu.addAction(newSubDirAct);
|
||||||
menu.addAction(newSiblingDirAct);
|
|
||||||
} else {
|
} else {
|
||||||
// Top-level item
|
// Top-level item
|
||||||
menu.addAction(newRootDirAct);
|
menu.addAction(newRootDirAct);
|
||||||
@ -277,60 +224,40 @@ void VDirectoryTree::contextMenuRequested(QPoint pos)
|
|||||||
menu.exec(mapToGlobal(pos));
|
menu.exec(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::newSiblingDirectory()
|
|
||||||
{
|
|
||||||
QTreeWidgetItem *parentItem = currentItem()->parent();
|
|
||||||
Q_ASSERT(parentItem);
|
|
||||||
QJsonObject parentItemJson = parentItem->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
QString parentItemName = parentItemJson["name"].toString();
|
|
||||||
|
|
||||||
QString text("&Directory name:");
|
|
||||||
QString defaultText("new_directory");
|
|
||||||
do {
|
|
||||||
VNewDirDialog dialog(QString("Create a new directory under %1").arg(parentItemName), text,
|
|
||||||
defaultText, this);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
|
||||||
QString name = dialog.getNameInput();
|
|
||||||
if (isConflictNameWithChildren(parentItem, name)) {
|
|
||||||
text = "Name already exists.\nPlease choose another name:";
|
|
||||||
defaultText = name;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(parentItem, name);
|
|
||||||
if (newItem) {
|
|
||||||
this->setCurrentItem(newItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::newSubDirectory()
|
void VDirectoryTree::newSubDirectory()
|
||||||
{
|
{
|
||||||
|
if (!m_notebook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QTreeWidgetItem *curItem = currentItem();
|
QTreeWidgetItem *curItem = currentItem();
|
||||||
if (!curItem) {
|
if (!curItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonObject curItemJson = curItem->data(0, Qt::UserRole).toJsonObject();
|
VDirectory *curDir = getVDirectory(curItem);
|
||||||
QString curItemName = curItemJson["name"].toString();
|
|
||||||
|
|
||||||
|
QString info = QString("Create sub-directory under %1.").arg(curDir->getName());
|
||||||
QString text("&Directory name:");
|
QString text("&Directory name:");
|
||||||
QString defaultText("new_directory");
|
QString defaultText("new_directory");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
VNewDirDialog dialog(QString("Create a new directory under %1").arg(curItemName), text,
|
VNewDirDialog dialog(tr("Create directory"), info, text, defaultText, this);
|
||||||
defaultText, this);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
QString name = dialog.getNameInput();
|
QString name = dialog.getNameInput();
|
||||||
if (isConflictNameWithChildren(curItem, name)) {
|
if (curDir->findSubDirectory(name)) {
|
||||||
text = "Name already exists.\nPlease choose another name:";
|
info = QString("Name already exists under %1.\nPlease choose another name.").arg(curDir->getName());
|
||||||
defaultText = name;
|
defaultText = name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(curItem, name);
|
VDirectory *subDir = curDir->createSubDirectory(name);
|
||||||
if (newItem) {
|
if (!subDir) {
|
||||||
this->setCurrentItem(newItem);
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Failed to create directory %1.").arg(name), "",
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
QVector<QTreeWidgetItem *> items = updateItemChildrenAdded(curItem);
|
||||||
|
Q_ASSERT(items.size() == 1);
|
||||||
|
setCurrentItem(items[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
@ -338,23 +265,32 @@ void VDirectoryTree::newSubDirectory()
|
|||||||
|
|
||||||
void VDirectoryTree::newRootDirectory()
|
void VDirectoryTree::newRootDirectory()
|
||||||
{
|
{
|
||||||
|
if (!m_notebook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString info = QString("Create root directory in notebook %1.").arg(m_notebook->getName());
|
||||||
QString text("&Directory name:");
|
QString text("&Directory name:");
|
||||||
QString defaultText("new_directory");
|
QString defaultText("new_directory");
|
||||||
|
VDirectory *rootDir = m_notebook->getRootDir();
|
||||||
do {
|
do {
|
||||||
VNewDirDialog dialog(tr("Create a new root directory"), text,
|
VNewDirDialog dialog(tr("Create root directory"), info, text, defaultText, this);
|
||||||
defaultText, this);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
QString name = dialog.getNameInput();
|
QString name = dialog.getNameInput();
|
||||||
if (isConflictNameWithChildren(NULL, name)) {
|
if (rootDir->findSubDirectory(name)) {
|
||||||
text = "Name already exists.\nPlease choose another name:";
|
info = QString("Name already exists in notebook %1.\nPlease choose another name.").arg(m_notebook->getName());
|
||||||
defaultText = name;
|
defaultText = name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(NULL, name);
|
VDirectory *subDir = rootDir->createSubDirectory(name);
|
||||||
if (newItem) {
|
if (!subDir) {
|
||||||
this->setCurrentItem(newItem);
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Failed to create directory %1.").arg(name), "",
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
QVector<QTreeWidgetItem *> items = updateItemChildrenAdded(NULL);
|
||||||
|
Q_ASSERT(items.size() == 1);
|
||||||
|
setCurrentItem(items[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
@ -366,140 +302,26 @@ void VDirectoryTree::deleteDirectory()
|
|||||||
if (!curItem) {
|
if (!curItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonObject curItemJson = curItem->data(0, Qt::UserRole).toJsonObject();
|
VDirectory *curDir = getVDirectory(curItem);
|
||||||
QString curItemName = curItemJson["name"].toString();
|
int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Are you sure to delete directory %1?").arg(curDir->getName()),
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Are you sure you want to delete directory \"%1\"?")
|
tr("This will delete any files under this directory."), QMessageBox::Ok | QMessageBox::Cancel,
|
||||||
.arg(curItemName), QMessageBox::Ok | QMessageBox::Cancel, this);
|
QMessageBox::Ok, this);
|
||||||
msgBox.setInformativeText(tr("This will delete any files under this directory."));
|
if (ret == QMessageBox::Ok) {
|
||||||
msgBox.setDefaultButton(QMessageBox::Cancel);
|
VDirectory *parentDir = curDir->getParentDirectory();
|
||||||
if (msgBox.exec() == QMessageBox::Ok) {
|
Q_ASSERT(parentDir);
|
||||||
deleteDirectoryAndUpdateTree(curItem);
|
parentDir->deleteSubDirectory(curDir);
|
||||||
|
delete curItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *parent,
|
|
||||||
const QString &name)
|
|
||||||
{
|
|
||||||
QString relativePath = calculateItemRelativePath(parent);
|
|
||||||
QString path = QDir::cleanPath(QDir(treePath).filePath(relativePath));
|
|
||||||
QDir dir(path);
|
|
||||||
if (!dir.mkdir(name)) {
|
|
||||||
qWarning() << "error: fail to create directory" << name << "under" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Could not create directory \"%1\" under \"%2\".")
|
|
||||||
.arg(name).arg(path), QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Please check if there already exists a directory named \"%1\".").arg(name));
|
|
||||||
msgBox.exec();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject configJson;
|
|
||||||
configJson["version"] = "1";
|
|
||||||
configJson["sub_directories"] = QJsonArray();
|
|
||||||
configJson["files"] = QJsonArray();
|
|
||||||
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(QDir::cleanPath(QDir(path).filePath(name)), configJson)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update parent's config file to include this new directory
|
|
||||||
configJson = VConfigManager::readDirectoryConfig(path);
|
|
||||||
Q_ASSERT(!configJson.isEmpty());
|
|
||||||
QJsonObject itemJson;
|
|
||||||
itemJson["name"] = name;
|
|
||||||
QJsonArray subDirArray = configJson["sub_directories"].toArray();
|
|
||||||
subDirArray.append(itemJson);
|
|
||||||
configJson["sub_directories"] = subDirArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(path, configJson)) {
|
|
||||||
VConfigManager::deleteDirectoryConfig(QDir::cleanPath(QDir(path).filePath(name)));
|
|
||||||
dir.rmdir(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return insertDirectoryTreeItem(parent, NULL, itemJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::deleteDirectoryAndUpdateTree(QTreeWidgetItem *item)
|
|
||||||
{
|
|
||||||
if (!item) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
QString itemName = itemJson["name"].toString();
|
|
||||||
QString parentRelativePath = calculateItemRelativePath(item->parent());
|
|
||||||
|
|
||||||
// Update parent's config file to exclude this directory
|
|
||||||
QString path = QDir::cleanPath(QDir(treePath).filePath(parentRelativePath));
|
|
||||||
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
|
||||||
Q_ASSERT(!configJson.isEmpty());
|
|
||||||
QJsonArray subDirArray = configJson["sub_directories"].toArray();
|
|
||||||
bool deleted = false;
|
|
||||||
for (int i = 0; i < subDirArray.size(); ++i) {
|
|
||||||
QJsonObject ele = subDirArray[i].toObject();
|
|
||||||
if (ele["name"].toString() == itemName) {
|
|
||||||
subDirArray.removeAt(i);
|
|
||||||
deleted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!deleted) {
|
|
||||||
qWarning() << "error: fail to find" << itemName << "to delete in its parent's configuration file";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
configJson["sub_directories"] = subDirArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(path, configJson)) {
|
|
||||||
qWarning() << "error: fail to update parent's configuration file to delete" << itemName;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the entire directory
|
|
||||||
QString dirName = QDir::cleanPath(QDir(path).filePath(itemName));
|
|
||||||
QDir dir(dirName);
|
|
||||||
if (!dir.removeRecursively()) {
|
|
||||||
qWarning() << "error: fail to delete" << dirName << "recursively";
|
|
||||||
} else {
|
|
||||||
qDebug() << "delete" << dirName << "recursively";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the tree
|
|
||||||
removeDirectoryTreeItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VDirectoryTree::isConflictNameWithChildren(const QTreeWidgetItem *parent, const QString &name)
|
|
||||||
{
|
|
||||||
if (parent) {
|
|
||||||
int nrChild = parent->childCount();
|
|
||||||
for (int i = 0; i < nrChild; ++i) {
|
|
||||||
QJsonObject childItemJson = parent->child(i)->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!childItemJson.isEmpty());
|
|
||||||
if (childItemJson["name"].toString() == name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int nrTopLevelItems = topLevelItemCount();
|
|
||||||
for (int i = 0; i < nrTopLevelItems; ++i) {
|
|
||||||
QJsonObject itemJson = topLevelItem(i)->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
if (itemJson["name"].toString() == name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VDirectoryTree::currentDirectoryItemChanged(QTreeWidgetItem *currentItem)
|
void VDirectoryTree::currentDirectoryItemChanged(QTreeWidgetItem *currentItem)
|
||||||
{
|
{
|
||||||
if (!currentItem) {
|
if (!currentItem) {
|
||||||
emit currentDirectoryChanged(QJsonObject());
|
emit currentDirectoryChanged(NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonObject itemJson = currentItem->data(0, Qt::UserRole).toJsonObject();
|
emit currentDirectoryChanged(getVDirectory(currentItem));
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
itemJson["notebook"] = notebook;
|
|
||||||
itemJson["relative_path"] = calculateItemRelativePath(currentItem);
|
|
||||||
emit currentDirectoryChanged(itemJson);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::editDirectoryInfo()
|
void VDirectoryTree::editDirectoryInfo()
|
||||||
@ -508,80 +330,33 @@ void VDirectoryTree::editDirectoryInfo()
|
|||||||
if (!curItem) {
|
if (!curItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonObject curItemJson = curItem->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
QString curItemName = curItemJson["name"].toString();
|
|
||||||
|
|
||||||
|
VDirectory *curDir = getVDirectory(curItem);
|
||||||
|
VDirectory *parentDir = curDir->getParentDirectory();
|
||||||
|
QString curName = curDir->getName();
|
||||||
QString info;
|
QString info;
|
||||||
QString defaultName = curItemName;
|
QString defaultName = curName;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
VDirInfoDialog dialog(tr("Directory Information"), info, defaultName, this);
|
VDirInfoDialog dialog(tr("Directory Information"), info, defaultName, this);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
QString name = dialog.getNameInput();
|
QString name = dialog.getNameInput();
|
||||||
if (name == curItemName) {
|
if (name == curName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isConflictNameWithChildren(curItem->parent(), name)) {
|
if (parentDir->findSubDirectory(name)) {
|
||||||
info = "Name already exists.\nPlease choose another name:";
|
info = "Name already exists.\nPlease choose another name.";
|
||||||
defaultName = name;
|
defaultName = name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
renameDirectory(curItem, name);
|
if (!curDir->rename(name)) {
|
||||||
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Failed to rename directory %1.").arg(curName), "",
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
curItem->setText(0, name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::renameDirectory(QTreeWidgetItem *item, const QString &newName)
|
|
||||||
{
|
|
||||||
if (!item) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
|
|
||||||
QString name = itemJson["name"].toString();
|
|
||||||
|
|
||||||
QTreeWidgetItem *parent = item->parent();
|
|
||||||
QString parentRelativePath = calculateItemRelativePath(parent);
|
|
||||||
|
|
||||||
QString path = QDir::cleanPath(QDir(treePath).filePath(parentRelativePath));
|
|
||||||
QDir dir(path);
|
|
||||||
|
|
||||||
if (!dir.rename(name, newName)) {
|
|
||||||
qWarning() << "error: fail to rename directory" << name << "under" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Could not rename directory \"%1\" under \"%2\".")
|
|
||||||
.arg(name).arg(path), QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Please check if there already exists a directory named \"%1\".").arg(name));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update parent's config file
|
|
||||||
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
|
||||||
Q_ASSERT(!configJson.isEmpty());
|
|
||||||
QJsonArray subDirArray = configJson["sub_directories"].toArray();
|
|
||||||
int index = 0;
|
|
||||||
for (index = 0; index < subDirArray.size(); ++index) {
|
|
||||||
QJsonObject tmp = subDirArray[index].toObject();
|
|
||||||
if (tmp["name"].toString() == name) {
|
|
||||||
tmp["name"] = newName;
|
|
||||||
subDirArray[index] = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Q_ASSERT(index != subDirArray.size());
|
|
||||||
configJson["sub_directories"] = subDirArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(path, configJson)) {
|
|
||||||
dir.rename(newName, name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update item
|
|
||||||
itemJson["name"] = newName;
|
|
||||||
item->setData(0, Qt::UserRole, itemJson);
|
|
||||||
item->setText(0, newName);
|
|
||||||
|
|
||||||
QString oldPath = QDir::cleanPath(QDir(parentRelativePath).filePath(name));
|
|
||||||
QString newPath = QDir::cleanPath(QDir(parentRelativePath).filePath(newName));
|
|
||||||
qDebug() << "directory renamed" << oldPath << "to" << newPath;
|
|
||||||
emit directoryRenamed(notebook, oldPath, newPath);
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QVector>
|
||||||
|
#include "vdirectory.h"
|
||||||
#include "vnotebook.h"
|
#include "vnotebook.h"
|
||||||
|
|
||||||
class VNote;
|
class VNote;
|
||||||
@ -14,56 +17,35 @@ public:
|
|||||||
explicit VDirectoryTree(VNote *vnote, QWidget *parent = 0);
|
explicit VDirectoryTree(VNote *vnote, QWidget *parent = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentDirectoryChanged(QJsonObject itemJson);
|
void currentDirectoryChanged(VDirectory *p_directory);
|
||||||
void directoryRenamed(const QString ¬ebook, const QString &oldRelativePath,
|
void directoryRenamed(const QString ¬ebook, const QString &oldRelativePath,
|
||||||
const QString &newRelativePath);
|
const QString &newRelativePath);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setNotebook(const QString ¬ebookName);
|
void setNotebook(VNotebook *p_notebook);
|
||||||
void newRootDirectory();
|
void newRootDirectory();
|
||||||
void deleteDirectory();
|
void deleteDirectory();
|
||||||
void editDirectoryInfo();
|
void editDirectoryInfo();
|
||||||
|
void updateDirectoryTree();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Read config file and pdate the subtree of @item in the directory tree.
|
void updateChildren(QTreeWidgetItem *p_item);
|
||||||
// If @item has no child, we will call updateDirectoryTreeOne() to update it.
|
|
||||||
// Otherwise, we will loop all its direct-children and try to populate it if
|
|
||||||
// it has not been populated yet.
|
|
||||||
void updateItemSubtree(QTreeWidgetItem *item);
|
|
||||||
void contextMenuRequested(QPoint pos);
|
void contextMenuRequested(QPoint pos);
|
||||||
void newSiblingDirectory();
|
|
||||||
void newSubDirectory();
|
void newSubDirectory();
|
||||||
void currentDirectoryItemChanged(QTreeWidgetItem *currentItem);
|
void currentDirectoryItemChanged(QTreeWidgetItem *currentItem);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString calculateItemRelativePath(QTreeWidgetItem *item);
|
void updateDirectoryTreeOne(QTreeWidgetItem *p_parent, int depth);
|
||||||
// Clean and pdate the TreeWidget according to treePath
|
void fillTreeItem(QTreeWidgetItem &p_item, const QString &p_name,
|
||||||
void updateDirectoryTree();
|
VDirectory *p_directory, const QIcon &p_icon);
|
||||||
// Update the top-level items of the directory tree. Will not clean the tree at first.
|
|
||||||
void updateDirectoryTreeTopLevel();
|
|
||||||
|
|
||||||
// @relativePath is the relative path of the direcotry we are updating
|
|
||||||
void updateDirectoryTreeOne(QTreeWidgetItem &parent, const QString &relativePath, int depth);
|
|
||||||
// Validate if a directory is valid
|
|
||||||
bool validatePath(const QString &path);
|
|
||||||
|
|
||||||
void fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson);
|
|
||||||
void initActions();
|
void initActions();
|
||||||
QTreeWidgetItem* createDirectoryAndUpdateTree(QTreeWidgetItem *parent, const QString &name);
|
// New directories added to @p_item. Update @p_item's children items.
|
||||||
void deleteDirectoryAndUpdateTree(QTreeWidgetItem *item);
|
// If @p_item is NULL, then top level items added.
|
||||||
// If @name conflict with the children's names of @parent.
|
QVector<QTreeWidgetItem *> updateItemChildrenAdded(QTreeWidgetItem *p_item);
|
||||||
bool isConflictNameWithChildren(const QTreeWidgetItem *parent, const QString &name);
|
inline QPointer<VDirectory> getVDirectory(QTreeWidgetItem *p_item);
|
||||||
|
|
||||||
QTreeWidgetItem* insertDirectoryTreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding,
|
|
||||||
const QJsonObject &newItem);
|
|
||||||
void removeDirectoryTreeItem(QTreeWidgetItem *item);
|
|
||||||
void renameDirectory(QTreeWidgetItem *item, const QString &newName);
|
|
||||||
|
|
||||||
VNote *vnote;
|
VNote *vnote;
|
||||||
|
QPointer<VNotebook> m_notebook;
|
||||||
QString notebook;
|
|
||||||
// Used for cache
|
|
||||||
QString treePath;
|
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
QAction *newRootDirAct;
|
QAction *newRootDirAct;
|
||||||
@ -73,4 +55,10 @@ private:
|
|||||||
QAction *dirInfoAct;
|
QAction *dirInfoAct;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline QPointer<VDirectory> VDirectoryTree::getVDirectory(QTreeWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_item);
|
||||||
|
return p_item->data(0, Qt::UserRole).value<VDirectory *>();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VDIRECTORYTREE_H
|
#endif // VDIRECTORYTREE_H
|
||||||
|
@ -10,18 +10,20 @@
|
|||||||
|
|
||||||
extern VConfigManager vconfig;
|
extern VConfigManager vconfig;
|
||||||
|
|
||||||
VEdit::VEdit(VNoteFile *noteFile, QWidget *parent)
|
VEdit::VEdit(VFile *p_file, QWidget *p_parent)
|
||||||
: QTextEdit(parent), noteFile(noteFile), mdHighlighter(NULL)
|
: QTextEdit(p_parent), m_file(p_file), mdHighlighter(NULL)
|
||||||
{
|
{
|
||||||
if (noteFile->docType == DocType::Markdown) {
|
connect(document(), &QTextDocument::modificationChanged,
|
||||||
|
(VFile *)m_file, &VFile::setModified);
|
||||||
|
|
||||||
|
if (m_file->getDocType() == DocType::Markdown) {
|
||||||
setAcceptRichText(false);
|
setAcceptRichText(false);
|
||||||
mdHighlighter = new HGMarkdownHighlighter(vconfig.getMdHighlightingStyles(),
|
mdHighlighter = new HGMarkdownHighlighter(vconfig.getMdHighlightingStyles(),
|
||||||
500, document());
|
500, document());
|
||||||
connect(mdHighlighter, &HGMarkdownHighlighter::highlightCompleted,
|
connect(mdHighlighter, &HGMarkdownHighlighter::highlightCompleted,
|
||||||
this, &VEdit::generateEditOutline);
|
this, &VEdit::generateEditOutline);
|
||||||
editOps = new VMdEditOperations(this, noteFile);
|
editOps = new VMdEditOperations(this, m_file);
|
||||||
} else {
|
} else {
|
||||||
setAutoFormatting(QTextEdit::AutoBulletList);
|
|
||||||
editOps = NULL;
|
editOps = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +35,10 @@ VEdit::VEdit(VNoteFile *noteFile, QWidget *parent)
|
|||||||
|
|
||||||
VEdit::~VEdit()
|
VEdit::~VEdit()
|
||||||
{
|
{
|
||||||
|
if (m_file) {
|
||||||
|
disconnect(document(), &QTextDocument::modificationChanged,
|
||||||
|
(VFile *)m_file, &VFile::setModified);
|
||||||
|
}
|
||||||
if (editOps) {
|
if (editOps) {
|
||||||
delete editOps;
|
delete editOps;
|
||||||
editOps = NULL;
|
editOps = NULL;
|
||||||
@ -41,7 +47,7 @@ VEdit::~VEdit()
|
|||||||
|
|
||||||
void VEdit::updateFontAndPalette()
|
void VEdit::updateFontAndPalette()
|
||||||
{
|
{
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
setFont(vconfig.getMdEditFont());
|
setFont(vconfig.getMdEditFont());
|
||||||
setPalette(vconfig.getMdEditPalette());
|
setPalette(vconfig.getMdEditPalette());
|
||||||
@ -51,14 +57,14 @@ void VEdit::updateFontAndPalette()
|
|||||||
setPalette(vconfig.getBaseEditPalette());
|
setPalette(vconfig.getBaseEditPalette());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEdit::updateTabSettings()
|
void VEdit::updateTabSettings()
|
||||||
{
|
{
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
if (vconfig.getTabStopWidth() > 0) {
|
if (vconfig.getTabStopWidth() > 0) {
|
||||||
QFontMetrics metrics(vconfig.getMdEditFont());
|
QFontMetrics metrics(vconfig.getMdEditFont());
|
||||||
@ -72,7 +78,7 @@ void VEdit::updateTabSettings()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,27 +90,28 @@ void VEdit::updateTabSettings()
|
|||||||
|
|
||||||
void VEdit::beginEdit()
|
void VEdit::beginEdit()
|
||||||
{
|
{
|
||||||
setReadOnly(false);
|
|
||||||
updateTabSettings();
|
updateTabSettings();
|
||||||
updateFontAndPalette();
|
updateFontAndPalette();
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Html:
|
case DocType::Html:
|
||||||
setHtml(noteFile->content);
|
setHtml(m_file->getContent());
|
||||||
break;
|
break;
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
setFont(vconfig.getMdEditFont());
|
setFont(vconfig.getMdEditFont());
|
||||||
setPlainText(noteFile->content);
|
setPlainText(m_file->getContent());
|
||||||
initInitImages();
|
initInitImages();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
}
|
}
|
||||||
|
setReadOnly(false);
|
||||||
|
setModified(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEdit::endEdit()
|
void VEdit::endEdit()
|
||||||
{
|
{
|
||||||
setReadOnly(true);
|
setReadOnly(true);
|
||||||
if (noteFile->docType == DocType::Markdown) {
|
if (m_file->getDocType() == DocType::Markdown) {
|
||||||
clearUnusedImages();
|
clearUnusedImages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,31 +122,32 @@ void VEdit::saveFile()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Html:
|
case DocType::Html:
|
||||||
noteFile->content = toHtml();
|
m_file->setContent(toHtml());
|
||||||
break;
|
break;
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
noteFile->content = toPlainText();
|
m_file->setContent(toPlainText());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
}
|
}
|
||||||
document()->setModified(false);
|
document()->setModified(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEdit::reloadFile()
|
void VEdit::reloadFile()
|
||||||
{
|
{
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Html:
|
case DocType::Html:
|
||||||
setHtml(noteFile->content);
|
setHtml(m_file->getContent());
|
||||||
break;
|
break;
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
setPlainText(noteFile->content);
|
setPlainText(m_file->getContent());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
}
|
}
|
||||||
|
setModified(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEdit::keyPressEvent(QKeyEvent *event)
|
void VEdit::keyPressEvent(QKeyEvent *event)
|
||||||
@ -236,12 +244,12 @@ void VEdit::insertImage(const QString &name)
|
|||||||
|
|
||||||
void VEdit::initInitImages()
|
void VEdit::initInitImages()
|
||||||
{
|
{
|
||||||
m_initImages = VUtils::imagesFromMarkdownFile(QDir(noteFile->basePath).filePath(noteFile->fileName));
|
m_initImages = VUtils::imagesFromMarkdownFile(m_file->retrivePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEdit::clearUnusedImages()
|
void VEdit::clearUnusedImages()
|
||||||
{
|
{
|
||||||
QVector<QString> images = VUtils::imagesFromMarkdownFile(QDir(noteFile->basePath).filePath(noteFile->fileName));
|
QVector<QString> images = VUtils::imagesFromMarkdownFile(m_file->retrivePath());
|
||||||
|
|
||||||
if (!m_insertedImages.isEmpty()) {
|
if (!m_insertedImages.isEmpty()) {
|
||||||
QVector<QString> imageNames(images.size());
|
QVector<QString> imageNames(images.size());
|
||||||
@ -249,7 +257,7 @@ void VEdit::clearUnusedImages()
|
|||||||
imageNames[i] = VUtils::fileNameFromPath(images[i]);
|
imageNames[i] = VUtils::fileNameFromPath(images[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir = QDir(QDir(noteFile->basePath).filePath("images"));
|
QDir dir = QDir(m_file->retriveImagePath());
|
||||||
for (int i = 0; i < m_insertedImages.size(); ++i) {
|
for (int i = 0; i < m_insertedImages.size(); ++i) {
|
||||||
QString name = m_insertedImages[i];
|
QString name = m_insertedImages[i];
|
||||||
int j;
|
int j;
|
||||||
|
12
src/vedit.h
12
src/vedit.h
@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QPointer>
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
#include "vnotefile.h"
|
|
||||||
#include "vtoc.h"
|
#include "vtoc.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
class HGMarkdownHighlighter;
|
class HGMarkdownHighlighter;
|
||||||
class VEditOperations;
|
class VEditOperations;
|
||||||
@ -14,12 +15,12 @@ class VEdit : public QTextEdit
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VEdit(VNoteFile *noteFile, QWidget *parent = 0);
|
VEdit(VFile *p_file, QWidget *p_parent = 0);
|
||||||
~VEdit();
|
~VEdit();
|
||||||
void beginEdit();
|
void beginEdit();
|
||||||
void endEdit();
|
void endEdit();
|
||||||
|
|
||||||
// Save buffer content to noteFile->content.
|
// Save buffer content to VFile.
|
||||||
void saveFile();
|
void saveFile();
|
||||||
|
|
||||||
inline void setModified(bool modified);
|
inline void setModified(bool modified);
|
||||||
@ -48,9 +49,9 @@ private:
|
|||||||
void initInitImages();
|
void initInitImages();
|
||||||
void clearUnusedImages();
|
void clearUnusedImages();
|
||||||
|
|
||||||
|
QPointer<VFile> m_file;
|
||||||
bool isExpandTab;
|
bool isExpandTab;
|
||||||
QString tabSpaces;
|
QString tabSpaces;
|
||||||
VNoteFile *noteFile;
|
|
||||||
HGMarkdownHighlighter *mdHighlighter;
|
HGMarkdownHighlighter *mdHighlighter;
|
||||||
VEditOperations *editOps;
|
VEditOperations *editOps;
|
||||||
QVector<VHeader> headers;
|
QVector<VHeader> headers;
|
||||||
@ -67,6 +68,9 @@ inline bool VEdit::isModified() const
|
|||||||
inline void VEdit::setModified(bool modified)
|
inline void VEdit::setModified(bool modified)
|
||||||
{
|
{
|
||||||
document()->setModified(modified);
|
document()->setModified(modified);
|
||||||
|
if (m_file) {
|
||||||
|
m_file->setModified(modified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // VEDIT_H
|
#endif // VEDIT_H
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "vedittab.h"
|
#include "vedittab.h"
|
||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
VEditArea::VEditArea(VNote *vnote, QWidget *parent)
|
VEditArea::VEditArea(VNote *vnote, QWidget *parent)
|
||||||
: QWidget(parent), vnote(vnote), curWindowIndex(0)
|
: QWidget(parent), vnote(vnote), curWindowIndex(0)
|
||||||
@ -79,25 +80,17 @@ void VEditArea::removeSplitWindow(VEditWindow *win)
|
|||||||
|
|
||||||
// A given file can be opened in multiple split windows. A given file could be
|
// A given file can be opened in multiple split windows. A given file could be
|
||||||
// opened at most in one tab inside a window.
|
// opened at most in one tab inside a window.
|
||||||
void VEditArea::openFile(QJsonObject fileJson)
|
void VEditArea::openFile(VFile *p_file, OpenFileMode p_mode)
|
||||||
{
|
{
|
||||||
if (fileJson.isEmpty()) {
|
if (!p_file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qDebug() << "VEditArea open" << p_file->getName() << (int)p_mode;
|
||||||
QString notebook = fileJson["notebook"].toString();
|
|
||||||
QString relativePath = fileJson["relative_path"].toString();
|
|
||||||
int mode = OpenFileMode::Read;
|
|
||||||
if (fileJson.contains("mode")) {
|
|
||||||
mode = fileJson["mode"].toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "open notebook" << notebook << "path" << relativePath << mode;
|
|
||||||
|
|
||||||
// Find if it has been opened already
|
// Find if it has been opened already
|
||||||
int winIdx, tabIdx;
|
int winIdx, tabIdx;
|
||||||
bool setFocus = false;
|
bool setFocus = false;
|
||||||
auto tabs = findTabsByFile(notebook, relativePath);
|
auto tabs = findTabsByFile(p_file);
|
||||||
if (!tabs.empty()) {
|
if (!tabs.empty()) {
|
||||||
// Current window first
|
// Current window first
|
||||||
winIdx = tabs[0].first;
|
winIdx = tabs[0].first;
|
||||||
@ -115,19 +108,19 @@ void VEditArea::openFile(QJsonObject fileJson)
|
|||||||
|
|
||||||
// Open it in current window
|
// Open it in current window
|
||||||
winIdx = curWindowIndex;
|
winIdx = curWindowIndex;
|
||||||
tabIdx = openFileInWindow(winIdx, notebook, relativePath, mode);
|
tabIdx = openFileInWindow(winIdx, p_file, p_mode);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
setCurrentTab(winIdx, tabIdx, setFocus);
|
setCurrentTab(winIdx, tabIdx, setFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QPair<int, int> > VEditArea::findTabsByFile(const QString ¬ebook, const QString &relativePath)
|
QVector<QPair<int, int> > VEditArea::findTabsByFile(const VFile *p_file)
|
||||||
{
|
{
|
||||||
QVector<QPair<int, int> > tabs;
|
QVector<QPair<int, int> > tabs;
|
||||||
int nrWin = splitter->count();
|
int nrWin = splitter->count();
|
||||||
for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
|
for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
|
||||||
VEditWindow *win = getWindow(winIdx);
|
VEditWindow *win = getWindow(winIdx);
|
||||||
int tabIdx = win->findTabByFile(notebook, relativePath);
|
int tabIdx = win->findTabByFile(p_file);
|
||||||
if (tabIdx != -1) {
|
if (tabIdx != -1) {
|
||||||
QPair<int, int> match;
|
QPair<int, int> match;
|
||||||
match.first = winIdx;
|
match.first = winIdx;
|
||||||
@ -138,12 +131,11 @@ QVector<QPair<int, int> > VEditArea::findTabsByFile(const QString ¬ebook, con
|
|||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditArea::openFileInWindow(int windowIndex, const QString ¬ebook, const QString &relativePath,
|
int VEditArea::openFileInWindow(int windowIndex, VFile *p_file, OpenFileMode p_mode)
|
||||||
int mode)
|
|
||||||
{
|
{
|
||||||
Q_ASSERT(windowIndex < splitter->count());
|
Q_ASSERT(windowIndex < splitter->count());
|
||||||
VEditWindow *win = getWindow(windowIndex);
|
VEditWindow *win = getWindow(windowIndex);
|
||||||
return win->openFile(notebook, relativePath, mode);
|
return win->openFile(p_file, p_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditArea::setCurrentTab(int windowIndex, int tabIndex, bool setFocus)
|
void VEditArea::setCurrentTab(int windowIndex, int tabIndex, bool setFocus)
|
||||||
@ -178,21 +170,18 @@ void VEditArea::updateWindowStatus()
|
|||||||
win->requestUpdateCurHeader();
|
win->requestUpdateCurHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VEditArea::closeFile(QJsonObject fileJson)
|
bool VEditArea::closeFile(const VFile *p_file, bool p_forced)
|
||||||
{
|
{
|
||||||
if (fileJson.isEmpty()) {
|
if (!p_file) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
QString notebook = fileJson["notebook"].toString();
|
|
||||||
QString relativePath = fileJson["relative_path"].toString();
|
|
||||||
bool isForced = fileJson["is_forced"].toBool();
|
|
||||||
|
|
||||||
int nrWin = splitter->count();
|
int nrWin = splitter->count();
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
for (int i = 0; i < nrWin; ++i) {
|
for (int i = 0; i < nrWin; ++i) {
|
||||||
VEditWindow *win = getWindow(i);
|
VEditWindow *win = getWindow(i);
|
||||||
ret = ret || win->closeFile(notebook, relativePath, isForced);
|
ret = ret || win->closeFile(p_file, p_forced);
|
||||||
}
|
}
|
||||||
|
updateWindowStatus();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +195,7 @@ bool VEditArea::closeAllFiles(bool p_forced)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateWindowStatus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,29 +223,6 @@ void VEditArea::saveAndReadFile()
|
|||||||
win->saveAndReadFile();
|
win->saveAndReadFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditArea::handleDirectoryRenamed(const QString ¬ebook, const QString &oldRelativePath,
|
|
||||||
const QString &newRelativePath)
|
|
||||||
{
|
|
||||||
int nrWin = splitter->count();
|
|
||||||
for (int i = 0; i < nrWin; ++i) {
|
|
||||||
VEditWindow *win = getWindow(i);
|
|
||||||
win->handleDirectoryRenamed(notebook, oldRelativePath, newRelativePath);
|
|
||||||
}
|
|
||||||
updateWindowStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VEditArea::handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath)
|
|
||||||
{
|
|
||||||
qDebug() << "fileRenamed" << p_srcNotebook << p_srcRelativePath << p_destNotebook << p_destRelativePath;
|
|
||||||
int nrWin = splitter->count();
|
|
||||||
for (int i = 0; i < nrWin; ++i) {
|
|
||||||
VEditWindow *win = getWindow(i);
|
|
||||||
win->handleFileRenamed(p_srcNotebook, p_srcRelativePath, p_destNotebook, p_destRelativePath);
|
|
||||||
}
|
|
||||||
updateWindowStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VEditArea::handleSplitWindowRequest(VEditWindow *curWindow)
|
void VEditArea::handleSplitWindowRequest(VEditWindow *curWindow)
|
||||||
{
|
{
|
||||||
if (!curWindow) {
|
if (!curWindow) {
|
||||||
@ -287,7 +254,6 @@ void VEditArea::handleRemoveSplitRequest(VEditWindow *curWindow)
|
|||||||
|
|
||||||
void VEditArea::mousePressEvent(QMouseEvent *event)
|
void VEditArea::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
qDebug() << "VEditArea press event" << event;
|
qDebug() << "VEditArea press event" << event;
|
||||||
QPoint pos = event->pos();
|
QPoint pos = event->pos();
|
||||||
int nrWin = splitter->count();
|
int nrWin = splitter->count();
|
||||||
@ -335,7 +301,15 @@ void VEditArea::handleOutlineItemActivated(const VAnchor &anchor)
|
|||||||
getWindow(curWindowIndex)->scrollCurTab(anchor);
|
getWindow(curWindowIndex)->scrollCurTab(anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VEditArea::isFileOpened(const QString ¬ebook, const QString &relativePath)
|
bool VEditArea::isFileOpened(const VFile *p_file)
|
||||||
{
|
{
|
||||||
return !findTabsByFile(notebook, relativePath).isEmpty();
|
return !findTabsByFile(p_file).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VEditArea::handleFileUpdated(const VFile *p_file)
|
||||||
|
{
|
||||||
|
int nrWin = splitter->count();
|
||||||
|
for (int i = 0; i < nrWin; ++i) {
|
||||||
|
getWindow(i)->updateFileInfo(p_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,18 +15,18 @@
|
|||||||
#include "vtoc.h"
|
#include "vtoc.h"
|
||||||
|
|
||||||
class VNote;
|
class VNote;
|
||||||
|
class VFile;
|
||||||
|
|
||||||
class VEditArea : public QWidget
|
class VEditArea : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit VEditArea(VNote *vnote, QWidget *parent = 0);
|
explicit VEditArea(VNote *vnote, QWidget *parent = 0);
|
||||||
bool isFileOpened(const QString ¬ebook, const QString &relativePath);
|
bool isFileOpened(const VFile *p_file);
|
||||||
bool closeAllFiles(bool p_forced);
|
bool closeAllFiles(bool p_forced);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void curTabStatusChanged(const QString ¬ebook, const QString &relativePath,
|
void curTabStatusChanged(const VFile *p_file, bool p_editMode);
|
||||||
bool editMode, bool modifiable, bool modified);
|
|
||||||
void outlineChanged(const VToc &toc);
|
void outlineChanged(const VToc &toc);
|
||||||
void curHeaderChanged(const VAnchor &anchor);
|
void curHeaderChanged(const VAnchor &anchor);
|
||||||
|
|
||||||
@ -34,17 +34,14 @@ protected:
|
|||||||
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void openFile(QJsonObject fileJson);
|
void openFile(VFile *p_file, OpenFileMode p_mode);
|
||||||
bool closeFile(QJsonObject fileJson);
|
bool closeFile(const VFile *p_file, bool p_forced);
|
||||||
void editFile();
|
void editFile();
|
||||||
void saveFile();
|
void saveFile();
|
||||||
void readFile();
|
void readFile();
|
||||||
void saveAndReadFile();
|
void saveAndReadFile();
|
||||||
void handleOutlineItemActivated(const VAnchor &anchor);
|
void handleOutlineItemActivated(const VAnchor &anchor);
|
||||||
void handleDirectoryRenamed(const QString ¬ebook,
|
void handleFileUpdated(const VFile *p_file);
|
||||||
const QString &oldRelativePath, const QString &newRelativePath);
|
|
||||||
void handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleSplitWindowRequest(VEditWindow *curWindow);
|
void handleSplitWindowRequest(VEditWindow *curWindow);
|
||||||
@ -55,9 +52,8 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
QVector<QPair<int, int> > findTabsByFile(const QString ¬ebook, const QString &relativePath);
|
QVector<QPair<int, int> > findTabsByFile(const VFile *p_file);
|
||||||
int openFileInWindow(int windowIndex, const QString ¬ebook, const QString &relativePath,
|
int openFileInWindow(int windowIndex, VFile *p_file, OpenFileMode p_mode);
|
||||||
int mode);
|
|
||||||
void setCurrentTab(int windowIndex, int tabIndex, bool setFocus);
|
void setCurrentTab(int windowIndex, int tabIndex, bool setFocus);
|
||||||
void setCurrentWindow(int windowIndex, bool setFocus);
|
void setCurrentWindow(int windowIndex, bool setFocus);
|
||||||
inline VEditWindow *getWindow(int windowIndex) const;
|
inline VEditWindow *getWindow(int windowIndex) const;
|
||||||
|
@ -3,15 +3,15 @@
|
|||||||
#include "vedit.h"
|
#include "vedit.h"
|
||||||
#include "veditoperations.h"
|
#include "veditoperations.h"
|
||||||
|
|
||||||
VEditOperations::VEditOperations(VEdit *editor, VNoteFile *noteFile)
|
VEditOperations::VEditOperations(VEdit *p_editor, VFile *p_file)
|
||||||
: editor(editor), noteFile(noteFile)
|
: m_editor(p_editor), m_file(p_file)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditOperations::insertTextAtCurPos(const QString &text)
|
void VEditOperations::insertTextAtCurPos(const QString &text)
|
||||||
{
|
{
|
||||||
QTextCursor cursor(editor->document());
|
QTextCursor cursor(m_editor->document());
|
||||||
cursor.setPosition(editor->textCursor().position());
|
cursor.setPosition(m_editor->textCursor().position());
|
||||||
cursor.insertText(text);
|
cursor.insertText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
#ifndef VEDITOPERATIONS_H
|
#ifndef VEDITOPERATIONS_H
|
||||||
#define VEDITOPERATIONS_H
|
#define VEDITOPERATIONS_H
|
||||||
|
|
||||||
class VNoteFile;
|
#include <QPointer>
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
class VEdit;
|
class VEdit;
|
||||||
class QMimeData;
|
class QMimeData;
|
||||||
|
|
||||||
class VEditOperations
|
class VEditOperations
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VEditOperations(VEdit *editor, VNoteFile *noteFile);
|
VEditOperations(VEdit *p_editor, VFile *p_file);
|
||||||
virtual ~VEditOperations();
|
virtual ~VEditOperations();
|
||||||
virtual bool insertImageFromMimeData(const QMimeData *source) = 0;
|
virtual bool insertImageFromMimeData(const QMimeData *source) = 0;
|
||||||
virtual bool insertURLFromMimeData(const QMimeData *source) = 0;
|
virtual bool insertURLFromMimeData(const QMimeData *source) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void insertTextAtCurPos(const QString &text);
|
void insertTextAtCurPos(const QString &text);
|
||||||
VEdit *editor;
|
VEdit *m_editor;
|
||||||
VNoteFile *noteFile;
|
QPointer<VFile> m_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VEDITOPERATIONS_H
|
#endif // VEDITOPERATIONS_H
|
||||||
|
113
src/vedittab.cpp
113
src/vedittab.cpp
@ -18,37 +18,33 @@
|
|||||||
|
|
||||||
extern VConfigManager vconfig;
|
extern VConfigManager vconfig;
|
||||||
|
|
||||||
VEditTab::VEditTab(const QString &path, bool modifiable, QWidget *parent)
|
VEditTab::VEditTab(VFile *p_file, OpenFileMode p_mode, QWidget *p_parent)
|
||||||
: QStackedWidget(parent), mdConverterType(vconfig.getMdConverterType())
|
: QStackedWidget(p_parent), m_file(p_file), isEditMode(false),
|
||||||
|
mdConverterType(vconfig.getMdConverterType())
|
||||||
{
|
{
|
||||||
DocType docType = VUtils::isMarkdown(path) ? DocType::Markdown : DocType::Html;
|
qDebug() << "ready to open" << p_file->getName();
|
||||||
QString basePath = QFileInfo(path).path();
|
Q_ASSERT(!m_file->isOpened());
|
||||||
QString fileName = QFileInfo(path).fileName();
|
m_file->open();
|
||||||
qDebug() << "VEditTab basePath" << basePath << "file" << fileName;
|
|
||||||
QString fileText = VUtils::readFileFromDisk(path);
|
|
||||||
noteFile = new VNoteFile(basePath, fileName, fileText,
|
|
||||||
docType, modifiable);
|
|
||||||
|
|
||||||
isEditMode = false;
|
|
||||||
|
|
||||||
setupUI();
|
setupUI();
|
||||||
|
if (p_mode == OpenFileMode::Edit) {
|
||||||
|
showFileEditMode();
|
||||||
|
} else {
|
||||||
showFileReadMode();
|
showFileReadMode();
|
||||||
|
}
|
||||||
connect(qApp, &QApplication::focusChanged,
|
connect(qApp, &QApplication::focusChanged,
|
||||||
this, &VEditTab::handleFocusChanged);
|
this, &VEditTab::handleFocusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
VEditTab::~VEditTab()
|
VEditTab::~VEditTab()
|
||||||
{
|
{
|
||||||
if (noteFile) {
|
if (m_file) {
|
||||||
delete noteFile;
|
m_file->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditTab::setupUI()
|
void VEditTab::setupUI()
|
||||||
{
|
{
|
||||||
textEditor = new VEdit(noteFile);
|
textEditor = new VEdit(m_file);
|
||||||
connect(textEditor, &VEdit::headersChanged,
|
connect(textEditor, &VEdit::headersChanged,
|
||||||
this, &VEditTab::updateTocFromHeaders);
|
this, &VEditTab::updateTocFromHeaders);
|
||||||
connect(textEditor, SIGNAL(curHeaderChanged(int)),
|
connect(textEditor, SIGNAL(curHeaderChanged(int)),
|
||||||
@ -57,7 +53,7 @@ void VEditTab::setupUI()
|
|||||||
this, &VEditTab::statusChanged);
|
this, &VEditTab::statusChanged);
|
||||||
addWidget(textEditor);
|
addWidget(textEditor);
|
||||||
|
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
setupMarkdownPreview();
|
setupMarkdownPreview();
|
||||||
textBrowser = NULL;
|
textBrowser = NULL;
|
||||||
@ -71,37 +67,38 @@ void VEditTab::setupUI()
|
|||||||
webPreviewer = NULL;
|
webPreviewer = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditTab::showFileReadMode()
|
void VEditTab::showFileReadMode()
|
||||||
{
|
{
|
||||||
|
qDebug() << "read" << m_file->getName();
|
||||||
isEditMode = false;
|
isEditMode = false;
|
||||||
switch (noteFile->docType) {
|
switch (m_file->getDocType()) {
|
||||||
case DocType::Html:
|
case DocType::Html:
|
||||||
textBrowser->setHtml(noteFile->content);
|
textBrowser->setHtml(m_file->getContent());
|
||||||
textBrowser->setFont(vconfig.getBaseEditFont());
|
textBrowser->setFont(vconfig.getBaseEditFont());
|
||||||
textBrowser->setPalette(vconfig.getBaseEditPalette());
|
textBrowser->setPalette(vconfig.getBaseEditPalette());
|
||||||
setCurrentWidget(textBrowser);
|
setCurrentWidget(textBrowser);
|
||||||
break;
|
break;
|
||||||
case DocType::Markdown:
|
case DocType::Markdown:
|
||||||
if (mdConverterType == MarkdownConverterType::Marked) {
|
if (mdConverterType == MarkdownConverterType::Marked) {
|
||||||
document.setText(noteFile->content);
|
document.setText(m_file->getContent());
|
||||||
} else {
|
} else {
|
||||||
previewByConverter();
|
previewByConverter();
|
||||||
}
|
}
|
||||||
setCurrentWidget(webPreviewer);
|
setCurrentWidget(webPreviewer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning() << "error: unknown doc type" << int(noteFile->docType);
|
qWarning() << "error: unknown doc type" << int(m_file->getDocType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditTab::previewByConverter()
|
void VEditTab::previewByConverter()
|
||||||
{
|
{
|
||||||
VMarkdownConverter mdConverter;
|
VMarkdownConverter mdConverter;
|
||||||
QString content = noteFile->content;
|
QString &content = m_file->getContent();
|
||||||
QString html = mdConverter.generateHtml(content, vconfig.getMarkdownExtensions());
|
QString html = mdConverter.generateHtml(content, vconfig.getMarkdownExtensions());
|
||||||
QRegularExpression tocExp("<p>\\[TOC\\]<\\/p>", QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression tocExp("<p>\\[TOC\\]<\\/p>", QRegularExpression::CaseInsensitiveOption);
|
||||||
QString toc = mdConverter.generateToc(content, vconfig.getMarkdownExtensions());
|
QString toc = mdConverter.generateToc(content, vconfig.getMarkdownExtensions());
|
||||||
@ -119,15 +116,22 @@ void VEditTab::showFileEditMode()
|
|||||||
textEditor->setFocus();
|
textEditor->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VEditTab::requestClose()
|
bool VEditTab::closeFile(bool p_forced)
|
||||||
{
|
{
|
||||||
|
if (p_forced && isEditMode) {
|
||||||
|
// Discard buffer content
|
||||||
|
textEditor->reloadFile();
|
||||||
|
textEditor->endEdit();
|
||||||
|
showFileReadMode();
|
||||||
|
} else {
|
||||||
readFile();
|
readFile();
|
||||||
|
}
|
||||||
return !isEditMode;
|
return !isEditMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditTab::editFile()
|
void VEditTab::editFile()
|
||||||
{
|
{
|
||||||
if (isEditMode || !noteFile->modifiable) {
|
if (isEditMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,14 +145,12 @@ void VEditTab::readFile()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (textEditor->isModified()) {
|
if (textEditor->isModified()) {
|
||||||
// Need to save the changes
|
// Prompt to save the changes
|
||||||
QMessageBox msgBox(this);
|
int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
|
||||||
msgBox.setText(QString("The note \"%1\" has been modified.").arg(noteFile->fileName));
|
QString("Note %1 has been modified.").arg(m_file->getName()),
|
||||||
msgBox.setInformativeText("Do you want to save your changes?");
|
tr("Do you want to save your changes?"),
|
||||||
msgBox.setIcon(QMessageBox::Information);
|
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
|
||||||
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
QMessageBox::Save, this);
|
||||||
msgBox.setDefaultButton(QMessageBox::Save);
|
|
||||||
int ret = msgBox.exec();
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case QMessageBox::Save:
|
case QMessageBox::Save:
|
||||||
saveFile();
|
saveFile();
|
||||||
@ -171,33 +173,27 @@ void VEditTab::readFile()
|
|||||||
bool VEditTab::saveFile()
|
bool VEditTab::saveFile()
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
if (!isEditMode || !noteFile->modifiable || !textEditor->isModified()) {
|
if (!isEditMode || !textEditor->isModified()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Make sure the file already exists. Temporary deal with cases when user delete or move
|
// Make sure the file already exists. Temporary deal with cases when user delete or move
|
||||||
// a file.
|
// a file.
|
||||||
QString filePath = QDir(noteFile->basePath).filePath(noteFile->fileName);
|
QString filePath = m_file->retrivePath();
|
||||||
if (!QFile(filePath).exists()) {
|
if (!QFile(filePath).exists()) {
|
||||||
qWarning() << "error:" << filePath << "being written has been removed";
|
qWarning() << filePath << "being written has been removed";
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note"),
|
||||||
QString("%1 being written has been removed.").arg(filePath),
|
QString("%1 being written has been removed.").arg(filePath),
|
||||||
QMessageBox::Ok, this);
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
||||||
msgBox.exec();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
textEditor->saveFile();
|
textEditor->saveFile();
|
||||||
ret = VUtils::writeFileToDisk(filePath, noteFile->content);
|
ret = m_file->save();
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"), tr("Fail to save note"),
|
||||||
QString("Fail to write to disk when saving a note. Please try it again."),
|
QString("Fail to write to disk when saving a note. Please try it again."),
|
||||||
QMessageBox::Ok, this);
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
||||||
msgBox.exec();
|
|
||||||
textEditor->setModified(true);
|
textEditor->setModified(true);
|
||||||
ret = false;
|
|
||||||
}
|
}
|
||||||
ret = true;
|
|
||||||
emit statusChanged();
|
emit statusChanged();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -218,10 +214,10 @@ void VEditTab::setupMarkdownPreview()
|
|||||||
|
|
||||||
if (mdConverterType == MarkdownConverterType::Marked) {
|
if (mdConverterType == MarkdownConverterType::Marked) {
|
||||||
webPreviewer->setHtml(VNote::templateHtml,
|
webPreviewer->setHtml(VNote::templateHtml,
|
||||||
QUrl::fromLocalFile(noteFile->basePath + QDir::separator()));
|
QUrl::fromLocalFile(m_file->retriveBasePath() + QDir::separator()));
|
||||||
} else {
|
} else {
|
||||||
webPreviewer->setHtml(VNote::preTemplateHtml + VNote::postTemplateHtml,
|
webPreviewer->setHtml(VNote::preTemplateHtml + VNote::postTemplateHtml,
|
||||||
QUrl::fromLocalFile(noteFile->basePath + QDir::separator()));
|
QUrl::fromLocalFile(m_file->retriveBasePath() + QDir::separator()));
|
||||||
}
|
}
|
||||||
|
|
||||||
addWidget(webPreviewer);
|
addWidget(webPreviewer);
|
||||||
@ -260,7 +256,7 @@ void VEditTab::updateTocFromHtml(const QString &tocHtml)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tableOfContent.filePath = QDir::cleanPath(QDir(noteFile->basePath).filePath(noteFile->fileName));
|
tableOfContent.filePath = m_file->retrivePath();
|
||||||
tableOfContent.valid = true;
|
tableOfContent.valid = true;
|
||||||
|
|
||||||
emit outlineChanged(tableOfContent);
|
emit outlineChanged(tableOfContent);
|
||||||
@ -270,7 +266,7 @@ void VEditTab::updateTocFromHeaders(const QVector<VHeader> &headers)
|
|||||||
{
|
{
|
||||||
tableOfContent.type = VHeaderType::LineNumber;
|
tableOfContent.type = VHeaderType::LineNumber;
|
||||||
tableOfContent.headers = headers;
|
tableOfContent.headers = headers;
|
||||||
tableOfContent.filePath = QDir::cleanPath(QDir(noteFile->basePath).filePath(noteFile->fileName));
|
tableOfContent.filePath = m_file->retrivePath();
|
||||||
tableOfContent.valid = true;
|
tableOfContent.valid = true;
|
||||||
|
|
||||||
emit outlineChanged(tableOfContent);
|
emit outlineChanged(tableOfContent);
|
||||||
@ -367,8 +363,7 @@ void VEditTab::updateCurHeader(const QString &anchor)
|
|||||||
if (curHeader.anchor.mid(1) == anchor) {
|
if (curHeader.anchor.mid(1) == anchor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
curHeader = VAnchor(QDir::cleanPath(QDir(noteFile->basePath).filePath(noteFile->fileName)),
|
curHeader = VAnchor(m_file->retrivePath(), "#" + anchor, -1);
|
||||||
"#" + anchor, -1);
|
|
||||||
if (!anchor.isEmpty()) {
|
if (!anchor.isEmpty()) {
|
||||||
emit curHeaderChanged(curHeader);
|
emit curHeaderChanged(curHeader);
|
||||||
}
|
}
|
||||||
@ -379,16 +374,8 @@ void VEditTab::updateCurHeader(int lineNumber)
|
|||||||
if (curHeader.lineNumber == lineNumber) {
|
if (curHeader.lineNumber == lineNumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
curHeader = VAnchor(QDir::cleanPath(QDir(noteFile->basePath).filePath(noteFile->fileName)),
|
curHeader = VAnchor(m_file->retrivePath(), "", lineNumber);
|
||||||
"", lineNumber);
|
|
||||||
if (lineNumber > -1) {
|
if (lineNumber > -1) {
|
||||||
emit curHeaderChanged(curHeader);
|
emit curHeaderChanged(curHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditTab::updatePath(const QString &newPath)
|
|
||||||
{
|
|
||||||
QFileInfo info(newPath);
|
|
||||||
noteFile->basePath = info.path();
|
|
||||||
noteFile->fileName = info.fileName();
|
|
||||||
}
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QPointer>
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
#include "vnotefile.h"
|
|
||||||
#include "vdocument.h"
|
#include "vdocument.h"
|
||||||
#include "vmarkdownconverter.h"
|
#include "vmarkdownconverter.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "vedit.h"
|
#include "vedit.h"
|
||||||
#include "vtoc.h"
|
#include "vtoc.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
class QTextBrowser;
|
class QTextBrowser;
|
||||||
class QWebEngineView;
|
class QWebEngineView;
|
||||||
@ -20,9 +21,9 @@ class VEditTab : public QStackedWidget
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VEditTab(const QString &path, bool modifiable, QWidget *parent = 0);
|
VEditTab(VFile *p_file, OpenFileMode p_mode, QWidget *p_parent = 0);
|
||||||
~VEditTab();
|
~VEditTab();
|
||||||
bool requestClose();
|
bool closeFile(bool p_forced);
|
||||||
// Enter edit mode
|
// Enter edit mode
|
||||||
void editFile();
|
void editFile();
|
||||||
// Enter read mode
|
// Enter read mode
|
||||||
@ -36,8 +37,7 @@ public:
|
|||||||
void requestUpdateOutline();
|
void requestUpdateOutline();
|
||||||
void requestUpdateCurHeader();
|
void requestUpdateCurHeader();
|
||||||
void scrollToAnchor(const VAnchor& anchor);
|
void scrollToAnchor(const VAnchor& anchor);
|
||||||
void updatePath(const QString &newPath);
|
inline VFile *getFile();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void getFocused();
|
void getFocused();
|
||||||
void outlineChanged(const VToc &toc);
|
void outlineChanged(const VToc &toc);
|
||||||
@ -61,7 +61,7 @@ private:
|
|||||||
void parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
|
void parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
|
||||||
void parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
|
void parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
|
||||||
|
|
||||||
VNoteFile *noteFile;
|
QPointer<VFile> m_file;
|
||||||
bool isEditMode;
|
bool isEditMode;
|
||||||
QTextBrowser *textBrowser;
|
QTextBrowser *textBrowser;
|
||||||
VEdit *textEditor;
|
VEdit *textEditor;
|
||||||
@ -93,4 +93,9 @@ inline bool VEditTab::isChild(QObject *obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline VFile *VEditTab::getFile()
|
||||||
|
{
|
||||||
|
return m_file;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VEDITTAB_H
|
#endif // VEDITTAB_H
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
extern VConfigManager vconfig;
|
extern VConfigManager vconfig;
|
||||||
|
|
||||||
@ -70,11 +71,9 @@ void VEditWindow::splitWindow()
|
|||||||
void VEditWindow::removeSplit()
|
void VEditWindow::removeSplit()
|
||||||
{
|
{
|
||||||
// Close all the files one by one
|
// Close all the files one by one
|
||||||
// If user do not want to close a file, just stop removing
|
// If user do not want to close a file, just stop removing.
|
||||||
if (closeAllFiles(false)) {
|
// Otherwise, closeAllFiles() will emit requestRemoveSplit.
|
||||||
Q_ASSERT(count() == 0);
|
closeAllFiles(false);
|
||||||
emit requestRemoveSplit(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::setRemoveSplitEnable(bool enabled)
|
void VEditWindow::setRemoveSplitEnable(bool enabled)
|
||||||
@ -82,68 +81,67 @@ void VEditWindow::setRemoveSplitEnable(bool enabled)
|
|||||||
removeSplitAct->setVisible(enabled);
|
removeSplitAct->setVisible(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::openWelcomePage()
|
void VEditWindow::removeEditTab(int p_index)
|
||||||
{
|
{
|
||||||
int idx = openFileInTab("", vconfig.getWelcomePagePath(), false);
|
if (p_index > -1 && p_index < tabBar()->count()) {
|
||||||
setTabText(idx, generateTabText("Welcome to VNote", false));
|
VEditTab *editor = getTab(p_index);
|
||||||
setTabToolTip(idx, "VNote");
|
removeTab(p_index);
|
||||||
|
delete editor;
|
||||||
|
if (tabBar()->count() == 0) {
|
||||||
|
emit requestRemoveSplit(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditWindow::insertTabWithData(int index, QWidget *page,
|
int VEditWindow::insertEditTab(int p_index, VFile *p_file, QWidget *p_page)
|
||||||
const QJsonObject &tabData)
|
|
||||||
{
|
{
|
||||||
QString label = VUtils::fileNameFromPath(tabData["relative_path"].toString());
|
int idx = insertTab(p_index, p_page, p_file->getName());
|
||||||
int idx = insertTab(index, page, label);
|
|
||||||
QTabBar *tabs = tabBar();
|
QTabBar *tabs = tabBar();
|
||||||
tabs->setTabData(idx, tabData);
|
tabs->setTabToolTip(idx, generateTooltip(p_file));
|
||||||
tabs->setTabToolTip(idx, generateTooltip(tabData));
|
|
||||||
noticeStatus(currentIndex());
|
noticeStatus(currentIndex());
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditWindow::appendTabWithData(QWidget *page, const QJsonObject &tabData)
|
int VEditWindow::appendEditTab(VFile *p_file, QWidget *p_page)
|
||||||
{
|
{
|
||||||
return insertTabWithData(count(), page, tabData);
|
return insertEditTab(count(), p_file, p_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditWindow::openFile(const QString ¬ebook, const QString &relativePath, int mode)
|
int VEditWindow::openFile(VFile *p_file, OpenFileMode p_mode)
|
||||||
{
|
{
|
||||||
|
qDebug() << "open" << p_file->getName();
|
||||||
// Find if it has been opened already
|
// Find if it has been opened already
|
||||||
int idx = findTabByFile(notebook, relativePath);
|
int idx = findTabByFile(p_file);
|
||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
idx = openFileInTab(notebook, relativePath, true);
|
idx = openFileInTab(p_file, p_mode);
|
||||||
out:
|
out:
|
||||||
setCurrentIndex(idx);
|
setCurrentIndex(idx);
|
||||||
if (mode == OpenFileMode::Edit) {
|
|
||||||
editFile();
|
|
||||||
}
|
|
||||||
focusWindow();
|
focusWindow();
|
||||||
noticeStatus(idx);
|
noticeStatus(idx);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if we closed the file
|
// Return true if we closed the file actually
|
||||||
bool VEditWindow::closeFile(const QString ¬ebook, const QString &relativePath, bool isForced)
|
bool VEditWindow::closeFile(const VFile *p_file, bool p_forced)
|
||||||
{
|
{
|
||||||
// Find if it has been opened already
|
// Find if it has been opened already
|
||||||
int idx = findTabByFile(notebook, relativePath);
|
int idx = findTabByFile(p_file);
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VEditTab *editor = getTab(idx);
|
VEditTab *editor = getTab(idx);
|
||||||
Q_ASSERT(editor);
|
Q_ASSERT(editor);
|
||||||
bool ok = true;
|
if (!p_forced) {
|
||||||
if (!isForced) {
|
|
||||||
setCurrentIndex(idx);
|
setCurrentIndex(idx);
|
||||||
noticeStatus(idx);
|
noticeStatus(idx);
|
||||||
ok = editor->requestClose();
|
|
||||||
}
|
}
|
||||||
|
// Even p_forced is true we need to delete unused images.
|
||||||
|
bool ok = editor->closeFile(p_forced);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
removeTab(idx);
|
removeEditTab(idx);
|
||||||
delete editor;
|
|
||||||
}
|
}
|
||||||
updateTabListMenu();
|
updateTabListMenu();
|
||||||
return ok;
|
return ok;
|
||||||
@ -155,15 +153,15 @@ bool VEditWindow::closeAllFiles(bool p_forced)
|
|||||||
bool ret = true;
|
bool ret = true;
|
||||||
for (int i = 0; i < nrTab; ++i) {
|
for (int i = 0; i < nrTab; ++i) {
|
||||||
VEditTab *editor = getTab(0);
|
VEditTab *editor = getTab(0);
|
||||||
bool ok = true;
|
|
||||||
if (!p_forced) {
|
if (!p_forced) {
|
||||||
setCurrentIndex(0);
|
setCurrentIndex(0);
|
||||||
noticeStatus(0);
|
noticeStatus(0);
|
||||||
ok = editor->requestClose();
|
|
||||||
}
|
}
|
||||||
|
// Even p_forced is true we need to delete unused images.
|
||||||
|
bool ok = editor->closeFile(p_forced);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
removeTab(0);
|
removeEditTab(0);
|
||||||
delete editor;
|
|
||||||
} else {
|
} else {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
@ -176,11 +174,9 @@ bool VEditWindow::closeAllFiles(bool p_forced)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditWindow::openFileInTab(const QString ¬ebook, const QString &relativePath,
|
int VEditWindow::openFileInTab(VFile *p_file, OpenFileMode p_mode)
|
||||||
bool modifiable)
|
|
||||||
{
|
{
|
||||||
QString path = QDir::cleanPath(QDir(vnote->getNotebookPath(notebook)).filePath(relativePath));
|
VEditTab *editor = new VEditTab(p_file, p_mode);
|
||||||
VEditTab *editor = new VEditTab(path, modifiable);
|
|
||||||
connect(editor, &VEditTab::getFocused,
|
connect(editor, &VEditTab::getFocused,
|
||||||
this, &VEditWindow::getFocused);
|
this, &VEditWindow::getFocused);
|
||||||
connect(editor, &VEditTab::outlineChanged,
|
connect(editor, &VEditTab::outlineChanged,
|
||||||
@ -190,23 +186,16 @@ int VEditWindow::openFileInTab(const QString ¬ebook, const QString &relativeP
|
|||||||
connect(editor, &VEditTab::statusChanged,
|
connect(editor, &VEditTab::statusChanged,
|
||||||
this, &VEditWindow::handleTabStatusChanged);
|
this, &VEditWindow::handleTabStatusChanged);
|
||||||
|
|
||||||
QJsonObject tabJson;
|
int idx = appendEditTab(p_file, editor);
|
||||||
tabJson["notebook"] = notebook;
|
|
||||||
tabJson["relative_path"] = relativePath;
|
|
||||||
tabJson["modifiable"] = modifiable;
|
|
||||||
int idx = appendTabWithData(editor, tabJson);
|
|
||||||
updateTabListMenu();
|
updateTabListMenu();
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VEditWindow::findTabByFile(const QString ¬ebook, const QString &relativePath) const
|
int VEditWindow::findTabByFile(const VFile *p_file) const
|
||||||
{
|
{
|
||||||
QTabBar *tabs = tabBar();
|
int nrTabs = tabBar()->count();
|
||||||
int nrTabs = tabs->count();
|
|
||||||
|
|
||||||
for (int i = 0; i < nrTabs; ++i) {
|
for (int i = 0; i < nrTabs; ++i) {
|
||||||
QJsonObject tabJson = tabs->tabData(i).toJsonObject();
|
if (getTab(i)->getFile() == p_file) {
|
||||||
if (tabJson["notebook"] == notebook && tabJson["relative_path"] == relativePath) {
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,10 +206,9 @@ bool VEditWindow::handleTabCloseRequest(int index)
|
|||||||
{
|
{
|
||||||
VEditTab *editor = getTab(index);
|
VEditTab *editor = getTab(index);
|
||||||
Q_ASSERT(editor);
|
Q_ASSERT(editor);
|
||||||
bool ok = editor->requestClose();
|
bool ok = editor->closeFile(false);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
removeTab(index);
|
removeEditTab(index);
|
||||||
delete editor;
|
|
||||||
}
|
}
|
||||||
updateTabListMenu();
|
updateTabListMenu();
|
||||||
noticeStatus(currentIndex());
|
noticeStatus(currentIndex());
|
||||||
@ -260,81 +248,29 @@ void VEditWindow::saveFile()
|
|||||||
editor->saveFile();
|
editor->saveFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::handleDirectoryRenamed(const QString ¬ebook, const QString &oldRelativePath,
|
void VEditWindow::noticeTabStatus(int p_index)
|
||||||
const QString &newRelativePath)
|
|
||||||
{
|
{
|
||||||
QTabBar *tabs = tabBar();
|
if (p_index == -1) {
|
||||||
int nrTabs = tabs->count();
|
emit tabStatusChanged(NULL, false);
|
||||||
for (int i = 0; i < nrTabs; ++i) {
|
|
||||||
QJsonObject tabJson = tabs->tabData(i).toJsonObject();
|
|
||||||
if (tabJson["notebook"].toString() == notebook) {
|
|
||||||
QString relativePath = tabJson["relative_path"].toString();
|
|
||||||
if (relativePath.startsWith(oldRelativePath)) {
|
|
||||||
relativePath.replace(0, oldRelativePath.size(), newRelativePath);
|
|
||||||
tabJson["relative_path"] = relativePath;
|
|
||||||
tabs->setTabData(i, tabJson);
|
|
||||||
tabs->setTabToolTip(i, generateTooltip(tabJson));
|
|
||||||
QString path = QDir::cleanPath(QDir(vnote->getNotebookPath(notebook)).filePath(relativePath));
|
|
||||||
getTab(i)->updatePath(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateTabListMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VEditWindow::handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath)
|
|
||||||
{
|
|
||||||
QTabBar *tabs = tabBar();
|
|
||||||
int nrTabs = tabs->count();
|
|
||||||
for (int i = 0; i < nrTabs; ++i) {
|
|
||||||
QJsonObject tabJson = tabs->tabData(i).toJsonObject();
|
|
||||||
if (tabJson["notebook"].toString() == p_srcNotebook) {
|
|
||||||
QString relativePath = tabJson["relative_path"].toString();
|
|
||||||
if (relativePath == p_srcRelativePath) {
|
|
||||||
VEditTab *tab = getTab(i);
|
|
||||||
tabJson["notebook"] = p_destNotebook;
|
|
||||||
tabJson["relative_path"] = p_destRelativePath;
|
|
||||||
tabs->setTabData(i, tabJson);
|
|
||||||
tabs->setTabToolTip(i, generateTooltip(tabJson));
|
|
||||||
tabs->setTabText(i, generateTabText(VUtils::fileNameFromPath(p_destRelativePath), tab->isModified()));
|
|
||||||
QString path = QDir::cleanPath(QDir(vnote->getNotebookPath(p_destNotebook)).filePath(p_destRelativePath));
|
|
||||||
tab->updatePath(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateTabListMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VEditWindow::noticeTabStatus(int index)
|
|
||||||
{
|
|
||||||
if (index == -1) {
|
|
||||||
emit tabStatusChanged("", "", false, false, false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject tabJson = tabBar()->tabData(index).toJsonObject();
|
VEditTab *editor = getTab(p_index);
|
||||||
Q_ASSERT(!tabJson.isEmpty());
|
const VFile *file = editor->getFile();
|
||||||
|
|
||||||
QString notebook = tabJson["notebook"].toString();
|
|
||||||
QString relativePath = tabJson["relative_path"].toString();
|
|
||||||
VEditTab *editor = getTab(index);
|
|
||||||
bool editMode = editor->getIsEditMode();
|
bool editMode = editor->getIsEditMode();
|
||||||
bool modifiable = tabJson["modifiable"].toBool();
|
|
||||||
|
|
||||||
// Update tab text
|
// Update tab text
|
||||||
tabBar()->setTabText(index, generateTabText(VUtils::fileNameFromPath(relativePath),
|
tabBar()->setTabText(p_index, generateTabText(file->getName(), file->isModified()));
|
||||||
editor->isModified()));
|
emit tabStatusChanged(file, editMode);
|
||||||
|
|
||||||
emit tabStatusChanged(notebook, relativePath,
|
|
||||||
editMode, modifiable, editor->isModified());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Be requested to report current status
|
||||||
void VEditWindow::requestUpdateTabStatus()
|
void VEditWindow::requestUpdateTabStatus()
|
||||||
{
|
{
|
||||||
noticeTabStatus(currentIndex());
|
noticeTabStatus(currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Be requested to report current outline
|
||||||
void VEditWindow::requestUpdateOutline()
|
void VEditWindow::requestUpdateOutline()
|
||||||
{
|
{
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
@ -345,6 +281,7 @@ void VEditWindow::requestUpdateOutline()
|
|||||||
getTab(idx)->requestUpdateOutline();
|
getTab(idx)->requestUpdateOutline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Be requested to report current header
|
||||||
void VEditWindow::requestUpdateCurHeader()
|
void VEditWindow::requestUpdateCurHeader()
|
||||||
{
|
{
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
@ -355,6 +292,7 @@ void VEditWindow::requestUpdateCurHeader()
|
|||||||
getTab(idx)->requestUpdateCurHeader();
|
getTab(idx)->requestUpdateCurHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Focus this windows. Try to focus current tab.
|
||||||
void VEditWindow::focusWindow()
|
void VEditWindow::focusWindow()
|
||||||
{
|
{
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
@ -392,9 +330,8 @@ void VEditWindow::tabListJump(QAction *action)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject tabJson = action->data().toJsonObject();
|
QPointer<VFile> file = action->data().value<QPointer<VFile>>();
|
||||||
int idx = findTabByFile(tabJson["notebook"].toString(),
|
int idx = findTabByFile(file);
|
||||||
tabJson["relative_path"].toString());
|
|
||||||
Q_ASSERT(idx >= 0);
|
Q_ASSERT(idx >= 0);
|
||||||
setCurrentIndex(idx);
|
setCurrentIndex(idx);
|
||||||
noticeStatus(idx);
|
noticeStatus(idx);
|
||||||
@ -416,54 +353,57 @@ void VEditWindow::updateTabListMenu()
|
|||||||
QTabBar *tabbar = tabBar();
|
QTabBar *tabbar = tabBar();
|
||||||
int nrTab = tabbar->count();
|
int nrTab = tabbar->count();
|
||||||
for (int i = 0; i < nrTab; ++i) {
|
for (int i = 0; i < nrTab; ++i) {
|
||||||
QAction *action = new QAction(tabbar->tabText(i), tabListAct);
|
VEditTab *editor = getTab(i);
|
||||||
action->setStatusTip(generateTooltip(tabbar->tabData(i).toJsonObject()));
|
QPointer<VFile> file = editor->getFile();
|
||||||
action->setData(tabbar->tabData(i));
|
QAction *action = new QAction(file->getName(), tabListAct);
|
||||||
|
action->setStatusTip(generateTooltip(file));
|
||||||
|
action->setData(QVariant::fromValue(file));
|
||||||
menu->addAction(action);
|
menu->addAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::handleOutlineChanged(const VToc &toc)
|
void VEditWindow::handleOutlineChanged(const VToc &p_toc)
|
||||||
{
|
{
|
||||||
// Only propagate it if it is current tab
|
// Only propagate it if it is current tab
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
QJsonObject tabJson = tabBar()->tabData(idx).toJsonObject();
|
if (idx == -1) {
|
||||||
Q_ASSERT(!tabJson.isEmpty());
|
emit outlineChanged(VToc());
|
||||||
QString path = vnote->getNotebookPath(tabJson["notebook"].toString());
|
return;
|
||||||
path = QDir::cleanPath(QDir(path).filePath(tabJson["relative_path"].toString()));
|
}
|
||||||
|
const VFile *file = getTab(idx)->getFile();
|
||||||
if (toc.filePath == path) {
|
if (p_toc.filePath == file->retrivePath()) {
|
||||||
emit outlineChanged(toc);
|
emit outlineChanged(p_toc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::handleCurHeaderChanged(const VAnchor &anchor)
|
void VEditWindow::handleCurHeaderChanged(const VAnchor &p_anchor)
|
||||||
{
|
{
|
||||||
// Only propagate it if it is current tab
|
// Only propagate it if it is current tab
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
QJsonObject tabJson = tabBar()->tabData(idx).toJsonObject();
|
if (idx == -1) {
|
||||||
Q_ASSERT(!tabJson.isEmpty());
|
emit curHeaderChanged(VAnchor());
|
||||||
QString path = vnote->getNotebookPath(tabJson["notebook"].toString());
|
return;
|
||||||
path = QDir::cleanPath(QDir(path).filePath(tabJson["relative_path"].toString()));
|
}
|
||||||
|
const VFile *file = getTab(idx)->getFile();
|
||||||
if (anchor.filePath == path) {
|
if (p_anchor.filePath == file->retrivePath()) {
|
||||||
emit curHeaderChanged(anchor);
|
emit curHeaderChanged(p_anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VEditWindow::scrollCurTab(const VAnchor &anchor)
|
void VEditWindow::scrollCurTab(const VAnchor &p_anchor)
|
||||||
{
|
{
|
||||||
int idx = currentIndex();
|
int idx = currentIndex();
|
||||||
QJsonObject tabJson = tabBar()->tabData(idx).toJsonObject();
|
if (idx == -1) {
|
||||||
Q_ASSERT(!tabJson.isEmpty());
|
emit curHeaderChanged(VAnchor());
|
||||||
QString path = vnote->getNotebookPath(tabJson["notebook"].toString());
|
return;
|
||||||
path = QDir::cleanPath(QDir(path).filePath(tabJson["relative_path"].toString()));
|
}
|
||||||
|
const VFile *file = getTab(idx)->getFile();
|
||||||
if (path == anchor.filePath) {
|
if (file->retrivePath() == p_anchor.filePath) {
|
||||||
getTab(idx)->scrollToAnchor(anchor);
|
getTab(idx)->scrollToAnchor(p_anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update tab status, outline and current header.
|
||||||
void VEditWindow::noticeStatus(int index)
|
void VEditWindow::noticeStatus(int index)
|
||||||
{
|
{
|
||||||
noticeTabStatus(index);
|
noticeTabStatus(index);
|
||||||
@ -482,3 +422,15 @@ void VEditWindow::handleTabStatusChanged()
|
|||||||
{
|
{
|
||||||
noticeTabStatus(currentIndex());
|
noticeTabStatus(currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VEditWindow::updateFileInfo(const VFile *p_file)
|
||||||
|
{
|
||||||
|
if (!p_file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int idx = findTabByFile(p_file);
|
||||||
|
if (idx > -1) {
|
||||||
|
noticeStatus(idx);
|
||||||
|
updateTabListMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,16 +13,16 @@
|
|||||||
class VNote;
|
class VNote;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
|
class VFile;
|
||||||
|
|
||||||
class VEditWindow : public QTabWidget
|
class VEditWindow : public QTabWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit VEditWindow(VNote *vnote, QWidget *parent = 0);
|
explicit VEditWindow(VNote *vnote, QWidget *parent = 0);
|
||||||
int findTabByFile(const QString ¬ebook, const QString &relativePath) const;
|
int findTabByFile(const VFile *p_file) const;
|
||||||
int openFile(const QString ¬ebook, const QString &relativePath,
|
int openFile(VFile *p_file, OpenFileMode p_mode);
|
||||||
int mode);
|
bool closeFile(const VFile *p_file, bool p_forced);
|
||||||
bool closeFile(const QString ¬ebook, const QString &relativePath, bool isForced);
|
|
||||||
void editFile();
|
void editFile();
|
||||||
void saveFile();
|
void saveFile();
|
||||||
void readFile();
|
void readFile();
|
||||||
@ -34,18 +34,14 @@ public:
|
|||||||
void requestUpdateCurHeader();
|
void requestUpdateCurHeader();
|
||||||
// Focus to current tab's editor
|
// Focus to current tab's editor
|
||||||
void focusWindow();
|
void focusWindow();
|
||||||
void scrollCurTab(const VAnchor &anchor);
|
void scrollCurTab(const VAnchor &p_anchor);
|
||||||
void handleDirectoryRenamed(const QString ¬ebook,
|
void updateFileInfo(const VFile *p_file);
|
||||||
const QString &oldRelativePath, const QString &newRelativePath);
|
|
||||||
void handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void tabStatusChanged(const QString ¬ebook, const QString &relativePath,
|
void tabStatusChanged(const VFile *p_file, bool p_editMode);
|
||||||
bool editMode, bool modifiable, bool modified);
|
|
||||||
void requestSplitWindow(VEditWindow *curWindow);
|
void requestSplitWindow(VEditWindow *curWindow);
|
||||||
void requestRemoveSplit(VEditWindow *curWindow);
|
void requestRemoveSplit(VEditWindow *curWindow);
|
||||||
// This widget or its children get the focus
|
// This widget or its children get the focus
|
||||||
@ -60,21 +56,21 @@ private slots:
|
|||||||
void handleTabbarClicked(int index);
|
void handleTabbarClicked(int index);
|
||||||
void contextMenuRequested(QPoint pos);
|
void contextMenuRequested(QPoint pos);
|
||||||
void tabListJump(QAction *action);
|
void tabListJump(QAction *action);
|
||||||
void handleOutlineChanged(const VToc &toc);
|
void handleOutlineChanged(const VToc &p_toc);
|
||||||
void handleCurHeaderChanged(const VAnchor &anchor);
|
void handleCurHeaderChanged(const VAnchor &p_anchor);
|
||||||
void handleTabStatusChanged();
|
void handleTabStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupCornerWidget();
|
void setupCornerWidget();
|
||||||
void openWelcomePage();
|
void removeEditTab(int p_index);
|
||||||
int insertTabWithData(int index, QWidget *page, const QJsonObject &tabData);
|
int insertEditTab(int p_index, VFile *p_file, QWidget *p_page);
|
||||||
int appendTabWithData(QWidget *page, const QJsonObject &tabData);
|
int appendEditTab(VFile *p_file, QWidget *p_page);
|
||||||
int openFileInTab(const QString ¬ebook, const QString &relativePath, bool modifiable);
|
int openFileInTab(VFile *p_file, OpenFileMode p_mode);
|
||||||
inline VEditTab *getTab(int tabIndex) const;
|
inline VEditTab *getTab(int tabIndex) const;
|
||||||
void noticeTabStatus(int index);
|
void noticeTabStatus(int p_index);
|
||||||
void updateTabListMenu();
|
void updateTabListMenu();
|
||||||
void noticeStatus(int index);
|
void noticeStatus(int index);
|
||||||
inline QString generateTooltip(const QJsonObject &tabData) const;
|
inline QString generateTooltip(const VFile *p_file) const;
|
||||||
inline QString generateTabText(const QString &p_name, bool p_modified) const;
|
inline QString generateTabText(const QString &p_name, bool p_modified) const;
|
||||||
|
|
||||||
VNote *vnote;
|
VNote *vnote;
|
||||||
@ -94,10 +90,13 @@ inline VEditTab* VEditWindow::getTab(int tabIndex) const
|
|||||||
return dynamic_cast<VEditTab *>(widget(tabIndex));
|
return dynamic_cast<VEditTab *>(widget(tabIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QString VEditWindow::generateTooltip(const QJsonObject &tabData) const
|
inline QString VEditWindow::generateTooltip(const VFile *p_file) const
|
||||||
{
|
{
|
||||||
// [Notebook]relativePath
|
if (!p_file) {
|
||||||
return QString("[%1] %2").arg(tabData["notebook"].toString()).arg(tabData["relative_path"].toString());
|
return "";
|
||||||
|
}
|
||||||
|
// [Notebook]path
|
||||||
|
return QString("[%1] %2").arg(p_file->retriveNotebook()).arg(p_file->retrivePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QString VEditWindow::generateTabText(const QString &p_name, bool p_modified) const
|
inline QString VEditWindow::generateTabText(const QString &p_name, bool p_modified) const
|
||||||
|
114
src/vfile.cpp
Normal file
114
src/vfile.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
|
VFile::VFile(const QString &p_name, QObject *p_parent)
|
||||||
|
: QObject(p_parent), m_name(p_name), m_opened(false), m_modified(false),
|
||||||
|
m_docType(VUtils::isMarkdown(p_name) ? DocType::Markdown : DocType::Html)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VFile::open()
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_name.isEmpty());
|
||||||
|
if (m_opened) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Q_ASSERT(m_content.isEmpty());
|
||||||
|
Q_ASSERT(m_docType == (VUtils::isMarkdown(m_name) ? DocType::Markdown : DocType::Html));
|
||||||
|
QString path = retrivePath();
|
||||||
|
qDebug() << "path" << path;
|
||||||
|
m_content = VUtils::readFileFromDisk(path);
|
||||||
|
m_modified = false;
|
||||||
|
m_opened = true;
|
||||||
|
qDebug() << "file" << m_name << "opened";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::close()
|
||||||
|
{
|
||||||
|
if (!m_opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_content.clear();
|
||||||
|
m_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::deleteDiskFile()
|
||||||
|
{
|
||||||
|
Q_ASSERT(parent());
|
||||||
|
|
||||||
|
// Delete local images in ./images if it is Markdown
|
||||||
|
if (m_docType == DocType::Markdown) {
|
||||||
|
deleteLocalImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file
|
||||||
|
QString filePath = retrivePath();
|
||||||
|
QFile file(filePath);
|
||||||
|
if (file.remove()) {
|
||||||
|
qDebug() << "deleted" << filePath;
|
||||||
|
} else {
|
||||||
|
qWarning() << "failed to delete" << filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VFile::save()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_opened);
|
||||||
|
bool ret = VUtils::writeFileToDisk(retrivePath(), m_content);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::convert(DocType p_curType, DocType p_targetType)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_opened);
|
||||||
|
m_docType = p_targetType;
|
||||||
|
if (p_curType == p_targetType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString path = retrivePath();
|
||||||
|
QString fileText = VUtils::readFileFromDisk(path);
|
||||||
|
QTextEdit editor;
|
||||||
|
if (p_curType == DocType::Markdown) {
|
||||||
|
editor.setPlainText(fileText);
|
||||||
|
fileText = editor.toHtml();
|
||||||
|
} else {
|
||||||
|
editor.setHtml(fileText);
|
||||||
|
fileText = editor.toPlainText();
|
||||||
|
}
|
||||||
|
VUtils::writeFileToDisk(path, fileText);
|
||||||
|
qDebug() << getName() << "converted" << (int)p_curType << (int)p_targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::setModified(bool p_modified)
|
||||||
|
{
|
||||||
|
m_modified = p_modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::deleteLocalImages()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_docType == DocType::Markdown);
|
||||||
|
QString filePath = retrivePath();
|
||||||
|
QVector<QString> images = VUtils::imagesFromMarkdownFile(filePath);
|
||||||
|
int deleted = 0;
|
||||||
|
for (int i = 0; i < images.size(); ++i) {
|
||||||
|
QFile file(images[i]);
|
||||||
|
if (file.remove()) {
|
||||||
|
++deleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "delete" << deleted << "images for" << filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VFile::setName(const QString &p_name)
|
||||||
|
{
|
||||||
|
m_name = p_name;
|
||||||
|
DocType newType = VUtils::isMarkdown(p_name) ? DocType::Markdown : DocType::Html;
|
||||||
|
if (newType != m_docType) {
|
||||||
|
qWarning() << "setName() change the DocType. A convertion should be followed";
|
||||||
|
}
|
||||||
|
}
|
125
src/vfile.h
Normal file
125
src/vfile.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#ifndef VFILE_H
|
||||||
|
#define VFILE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QDir>
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "vconstants.h"
|
||||||
|
|
||||||
|
class VFile : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VFile(const QString &p_name, QObject *p_parent);
|
||||||
|
bool open();
|
||||||
|
void close();
|
||||||
|
bool save();
|
||||||
|
// Convert current file type.
|
||||||
|
void convert(DocType p_curType, DocType p_targetType);
|
||||||
|
|
||||||
|
inline const QString &getName() const;
|
||||||
|
void setName(const QString &p_name);
|
||||||
|
inline VDirectory *getDirectory();
|
||||||
|
inline const VDirectory *getDirectory() const;
|
||||||
|
inline DocType getDocType() const;
|
||||||
|
inline QString &getContent();
|
||||||
|
inline void setContent(const QString &p_content);
|
||||||
|
inline QString retriveNotebook() const;
|
||||||
|
inline QString retrivePath() const;
|
||||||
|
inline QString retriveRelativePath() const;
|
||||||
|
inline QString retriveBasePath() const;
|
||||||
|
inline QString retriveImagePath() const;
|
||||||
|
inline bool isModified() const;
|
||||||
|
inline bool isOpened() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setModified(bool p_modified);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Delete the file and corresponding images
|
||||||
|
void deleteDiskFile();
|
||||||
|
// Delete local images in ./images of DocType::Markdown
|
||||||
|
void deleteLocalImages();
|
||||||
|
|
||||||
|
QString m_name;
|
||||||
|
bool m_opened;
|
||||||
|
// File has been modified in editor
|
||||||
|
bool m_modified;
|
||||||
|
DocType m_docType;
|
||||||
|
QString m_content;
|
||||||
|
friend class VDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QString &VFile::getName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VDirectory *VFile::getDirectory()
|
||||||
|
{
|
||||||
|
Q_ASSERT(parent());
|
||||||
|
return (VDirectory *)parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const VDirectory *VFile::getDirectory() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(parent());
|
||||||
|
return (const VDirectory *)parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DocType VFile::getDocType() const
|
||||||
|
{
|
||||||
|
return m_docType;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString &VFile::getContent()
|
||||||
|
{
|
||||||
|
return m_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VFile::retriveNotebook() const
|
||||||
|
{
|
||||||
|
return getDirectory()->retriveNotebook();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VFile::retrivePath() const
|
||||||
|
{
|
||||||
|
QString dirPath = getDirectory()->retrivePath();
|
||||||
|
return QDir(dirPath).filePath(m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VFile::retriveRelativePath() const
|
||||||
|
{
|
||||||
|
QString dirRelativePath = getDirectory()->retriveRelativePath();
|
||||||
|
return QDir(dirRelativePath).filePath(m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VFile::retriveBasePath() const
|
||||||
|
{
|
||||||
|
return getDirectory()->retrivePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VFile::retriveImagePath() const
|
||||||
|
{
|
||||||
|
return QDir(retriveBasePath()).filePath("images");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VFile::setContent(const QString &p_content)
|
||||||
|
{
|
||||||
|
m_content = p_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VFile::isModified() const
|
||||||
|
{
|
||||||
|
return m_modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VFile::isOpened() const
|
||||||
|
{
|
||||||
|
return m_opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VFILE_H
|
@ -7,9 +7,10 @@
|
|||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
#include "veditarea.h"
|
#include "veditarea.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
VFileList::VFileList(VNote *vnote, QWidget *parent)
|
VFileList::VFileList(QWidget *parent)
|
||||||
: QWidget(parent), vnote(vnote)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupUI();
|
setupUI();
|
||||||
initActions();
|
initActions();
|
||||||
@ -43,14 +44,14 @@ void VFileList::initActions()
|
|||||||
deleteFileAct = new QAction(QIcon(":/resources/icons/delete_note.svg"),
|
deleteFileAct = new QAction(QIcon(":/resources/icons/delete_note.svg"),
|
||||||
tr("&Delete"), this);
|
tr("&Delete"), this);
|
||||||
deleteFileAct->setStatusTip(tr("Delete selected note"));
|
deleteFileAct->setStatusTip(tr("Delete selected note"));
|
||||||
connect(deleteFileAct, &QAction::triggered,
|
connect(deleteFileAct, SIGNAL(triggered(bool)),
|
||||||
this, &VFileList::deleteCurFile);
|
this, SLOT(deleteFile()));
|
||||||
|
|
||||||
fileInfoAct = new QAction(QIcon(":/resources/icons/note_info.svg"),
|
fileInfoAct = new QAction(QIcon(":/resources/icons/note_info.svg"),
|
||||||
tr("&Info"), this);
|
tr("&Info"), this);
|
||||||
fileInfoAct->setStatusTip(tr("View and edit current note's information"));
|
fileInfoAct->setStatusTip(tr("View and edit current note's information"));
|
||||||
connect(fileInfoAct, &QAction::triggered,
|
connect(fileInfoAct, SIGNAL(triggered(bool)),
|
||||||
this, &VFileList::curFileInfo);
|
this, SLOT(fileInfo()));
|
||||||
|
|
||||||
copyAct = new QAction(QIcon(":/resources/icons/copy.svg"),
|
copyAct = new QAction(QIcon(":/resources/icons/copy.svg"),
|
||||||
tr("&Copy"), this);
|
tr("&Copy"), this);
|
||||||
@ -71,85 +72,49 @@ void VFileList::initActions()
|
|||||||
this, &VFileList::pasteFilesInCurDir);
|
this, &VFileList::pasteFilesInCurDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::setDirectory(QJsonObject dirJson)
|
void VFileList::setDirectory(VDirectory *p_directory)
|
||||||
{
|
{
|
||||||
|
if (m_directory == p_directory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_directory = p_directory;
|
||||||
|
if (!m_directory) {
|
||||||
fileList->clear();
|
fileList->clear();
|
||||||
if (dirJson.isEmpty()) {
|
|
||||||
clearDirectoryInfo();
|
|
||||||
emit directoryChanged("", "");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
notebook = dirJson["notebook"].toString();
|
qDebug() << "filelist set directory" << m_directory->getName();
|
||||||
relativePath = dirJson["relative_path"].toString();
|
|
||||||
rootPath = "";
|
|
||||||
const QVector<VNotebook *> ¬ebooks = vnote->getNotebooks();
|
|
||||||
for (int i = 0; i < notebooks.size(); ++i) {
|
|
||||||
if (notebooks[i]->getName() == notebook) {
|
|
||||||
rootPath = notebooks[i]->getPath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Q_ASSERT(!rootPath.isEmpty());
|
|
||||||
|
|
||||||
updateFileList();
|
updateFileList();
|
||||||
|
|
||||||
emit directoryChanged(notebook, relativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::clearDirectoryInfo()
|
|
||||||
{
|
|
||||||
notebook = relativePath = rootPath = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::updateFileList()
|
void VFileList::updateFileList()
|
||||||
{
|
{
|
||||||
QString path = QDir(rootPath).filePath(relativePath);
|
|
||||||
|
|
||||||
fileList->clear();
|
fileList->clear();
|
||||||
if (!QDir(path).exists()) {
|
if (!m_directory->open()) {
|
||||||
qDebug() << "invalid notebook directory:" << path;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook directory."),
|
|
||||||
QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Notebook directory \"%1\" either does not exist or is not valid.")
|
|
||||||
.arg(path));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const QVector<VFile *> &files = m_directory->getFiles();
|
||||||
QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
|
for (int i = 0; i < files.size(); ++i) {
|
||||||
if (configJson.isEmpty()) {
|
VFile *file = files[i];
|
||||||
qDebug() << "invalid notebook configuration for directory:" << path;
|
insertFileListItem(file);
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook directory configuration."),
|
|
||||||
QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Notebook directory \"%1\" does not contain a valid configuration file.")
|
|
||||||
.arg(path));
|
|
||||||
msgBox.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle files section
|
|
||||||
QJsonArray filesJson = configJson["files"].toArray();
|
|
||||||
for (int i = 0; i < filesJson.size(); ++i) {
|
|
||||||
QJsonObject fileItem = filesJson[i].toObject();
|
|
||||||
insertFileListItem(fileItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::curFileInfo()
|
void VFileList::fileInfo()
|
||||||
{
|
{
|
||||||
QListWidgetItem *curItem = fileList->currentItem();
|
QListWidgetItem *curItem = fileList->currentItem();
|
||||||
QJsonObject curItemJson = curItem->data(Qt::UserRole).toJsonObject();
|
Q_ASSERT(curItem);
|
||||||
Q_ASSERT(!curItemJson.isEmpty());
|
fileInfo(getVFile(curItem));
|
||||||
QString curItemName = curItemJson["name"].toString();
|
|
||||||
fileInfo(notebook, QDir(relativePath).filePath(curItemName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::fileInfo(const QString &p_notebook, const QString &p_relativePath)
|
void VFileList::fileInfo(VFile *p_file)
|
||||||
{
|
{
|
||||||
qDebug() << "fileInfo" << p_notebook << p_relativePath;
|
if (!p_file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VDirectory *dir = p_file->getDirectory();
|
||||||
QString info;
|
QString info;
|
||||||
QString defaultName = VUtils::fileNameFromPath(p_relativePath);
|
QString defaultName = p_file->getName();
|
||||||
QString curName = defaultName;
|
QString curName = defaultName;
|
||||||
do {
|
do {
|
||||||
VFileInfoDialog dialog(tr("Note Information"), info, defaultName, this);
|
VFileInfoDialog dialog(tr("Note Information"), info, defaultName, this);
|
||||||
@ -158,23 +123,22 @@ void VFileList::fileInfo(const QString &p_notebook, const QString &p_relativePat
|
|||||||
if (name == curName) {
|
if (name == curName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isConflictNameWithExisting(name)) {
|
if (dir->findFile(name)) {
|
||||||
info = "Name already exists.\nPlease choose another name:";
|
info = "Name already exists.\nPlease choose another name.";
|
||||||
defaultName = name;
|
defaultName = name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
copyFile(p_notebook, p_relativePath, p_notebook,
|
copyFile(dir, name, p_file, true);
|
||||||
QDir(VUtils::basePathFromPath(p_relativePath)).filePath(name), true);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem* VFileList::insertFileListItem(QJsonObject fileJson, bool atFront)
|
QListWidgetItem* VFileList::insertFileListItem(VFile *file, bool atFront)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!fileJson.isEmpty());
|
Q_ASSERT(file);
|
||||||
QListWidgetItem *item = new QListWidgetItem(fileJson["name"].toString());
|
QListWidgetItem *item = new QListWidgetItem(file->getName());
|
||||||
item->setData(Qt::UserRole, fileJson);
|
item->setData(Qt::UserRole, QVariant::fromValue(file));
|
||||||
|
|
||||||
if (atFront) {
|
if (atFront) {
|
||||||
fileList->insertItem(0, item);
|
fileList->insertItem(0, item);
|
||||||
@ -183,7 +147,7 @@ QListWidgetItem* VFileList::insertFileListItem(QJsonObject fileJson, bool atFron
|
|||||||
}
|
}
|
||||||
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
||||||
fileList->update();
|
fileList->update();
|
||||||
qDebug() << "add new list item:" << fileJson["name"].toString();
|
qDebug() << "VFileList adds" << file->getName();
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,65 +162,91 @@ void VFileList::removeFileListItem(QListWidgetItem *item)
|
|||||||
|
|
||||||
void VFileList::newFile()
|
void VFileList::newFile()
|
||||||
{
|
{
|
||||||
|
if (!m_directory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString info = QString("Create a new note under %1.").arg(m_directory->getName());
|
||||||
QString text("&Note name:");
|
QString text("&Note name:");
|
||||||
QString defaultText("new_note");
|
QString defaultText("new_note");
|
||||||
do {
|
do {
|
||||||
VNewFileDialog dialog(QString("Create a new note under %1").arg(VUtils::directoryNameFromPath(relativePath)),
|
VNewFileDialog dialog(QString("Create new note"), info, text, defaultText, this);
|
||||||
text, defaultText, this);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
QString name = dialog.getNameInput();
|
QString name = dialog.getNameInput();
|
||||||
if (isConflictNameWithExisting(name)) {
|
if (m_directory->findFile(name)) {
|
||||||
text = "Name already exists.\nPlease choose another name:";
|
info = "Name already exists.\nPlease choose another name.";
|
||||||
defaultText = name;
|
defaultText = name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QListWidgetItem *newItem = createFileAndUpdateList(name);
|
VFile *file = m_directory->createFile(name);
|
||||||
if (newItem) {
|
if (!file) {
|
||||||
fileList->setCurrentItem(newItem);
|
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
|
QString("Failed to create file %1.").arg(name), "",
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVector<QListWidgetItem *> items = updateFileListAdded();
|
||||||
|
Q_ASSERT(items.size() == 1);
|
||||||
|
fileList->setCurrentItem(items[0]);
|
||||||
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
||||||
fileList->update();
|
fileList->update();
|
||||||
|
|
||||||
// Open this file in edit mode
|
// Open it in edit mode
|
||||||
QJsonObject itemJson = newItem->data(Qt::UserRole).toJsonObject();
|
emit fileCreated(file, OpenFileMode::Edit);
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
itemJson["notebook"] = notebook;
|
|
||||||
itemJson["relative_path"] = QDir::cleanPath(QDir(relativePath).filePath(name));
|
|
||||||
itemJson["mode"] = OpenFileMode::Edit;
|
|
||||||
emit fileCreated(itemJson);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::deleteCurFile()
|
QVector<QListWidgetItem *> VFileList::updateFileListAdded()
|
||||||
|
{
|
||||||
|
QVector<QListWidgetItem *> ret;
|
||||||
|
const QVector<VFile *> &files = m_directory->getFiles();
|
||||||
|
for (int i = 0; i < files.size(); ++i) {
|
||||||
|
VFile *file = files[i];
|
||||||
|
if (i >= fileList->count()) {
|
||||||
|
QListWidgetItem *item = insertFileListItem(file, false);
|
||||||
|
ret.append(item);
|
||||||
|
} else {
|
||||||
|
VFile *itemFile = getVFile(fileList->item(i));
|
||||||
|
if (itemFile != file) {
|
||||||
|
QListWidgetItem *item = insertFileListItem(file, false);
|
||||||
|
ret.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << ret.size() << "items added";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file related to current item
|
||||||
|
void VFileList::deleteFile()
|
||||||
{
|
{
|
||||||
QListWidgetItem *curItem = fileList->currentItem();
|
QListWidgetItem *curItem = fileList->currentItem();
|
||||||
Q_ASSERT(curItem);
|
Q_ASSERT(curItem);
|
||||||
QJsonObject curItemJson = curItem->data(Qt::UserRole).toJsonObject();
|
deleteFile(getVFile(curItem));
|
||||||
QString curItemName = curItemJson["name"].toString();
|
|
||||||
deleteFile(notebook, QDir(relativePath).filePath(curItemName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @p_relativePath contains the file name
|
// @p_file may or may not be listed in VFileList
|
||||||
void VFileList::deleteFile(const QString &p_notebook, const QString &p_relativePath)
|
void VFileList::deleteFile(VFile *p_file)
|
||||||
{
|
{
|
||||||
QString fileName = VUtils::fileNameFromPath(p_relativePath);
|
if (!p_file) {
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"),
|
return;
|
||||||
QString("Are you sure you want to delete note \"%1\"?")
|
}
|
||||||
.arg(fileName), QMessageBox::Ok | QMessageBox::Cancel,
|
VDirectory *dir = p_file->getDirectory();
|
||||||
this);
|
QString fileName = p_file->getName();
|
||||||
msgBox.setInformativeText(tr("This may be not recoverable."));
|
int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
QString("Are you sure to delete note %1?").arg(fileName), tr("This may be unrecoverable!"),
|
||||||
if (msgBox.exec() == QMessageBox::Ok) {
|
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok, this);
|
||||||
// First close this file forcely
|
if (ret == QMessageBox::Ok) {
|
||||||
QJsonObject curItemJson;
|
editArea->closeFile(p_file, true);
|
||||||
curItemJson["notebook"] = p_notebook;
|
|
||||||
curItemJson["relative_path"] = QDir::cleanPath(p_relativePath);
|
|
||||||
curItemJson["is_forced"] = true;
|
|
||||||
emit fileDeleted(curItemJson);
|
|
||||||
|
|
||||||
deleteFileAndUpdateList(p_notebook, p_relativePath);
|
// Remove the item before deleting it totally, or p_file will be invalid.
|
||||||
|
QListWidgetItem *item = findItem(p_file);
|
||||||
|
if (item) {
|
||||||
|
removeFileListItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
dir->deleteFile(p_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +255,7 @@ void VFileList::contextMenuRequested(QPoint pos)
|
|||||||
QListWidgetItem *item = fileList->itemAt(pos);
|
QListWidgetItem *item = fileList->itemAt(pos);
|
||||||
QMenu menu(this);
|
QMenu menu(this);
|
||||||
|
|
||||||
if (notebook.isEmpty()) {
|
if (!m_directory) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
menu.addAction(newFileAct);
|
menu.addAction(newFileAct);
|
||||||
@ -290,189 +280,58 @@ void VFileList::contextMenuRequested(QPoint pos)
|
|||||||
menu.exec(fileList->mapToGlobal(pos));
|
menu.exec(fileList->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VFileList::isConflictNameWithExisting(const QString &name)
|
QListWidgetItem* VFileList::findItem(const VFile *p_file)
|
||||||
{
|
{
|
||||||
int nrChild = fileList->count();
|
if (!p_file || p_file->getDirectory() != m_directory) {
|
||||||
for (int i = 0; i < nrChild; ++i) {
|
|
||||||
QListWidgetItem *item = fileList->item(i);
|
|
||||||
QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject();
|
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
if (itemJson["name"].toString() == name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidgetItem* VFileList::findItem(const QString &p_notebook, const QString &p_relativePath)
|
|
||||||
{
|
|
||||||
if (p_notebook != notebook || VUtils::basePathFromPath(p_relativePath) != QDir::cleanPath(relativePath)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
QString name = VUtils::fileNameFromPath(p_relativePath);
|
|
||||||
int nrChild = fileList->count();
|
int nrChild = fileList->count();
|
||||||
for (int i = 0; i < nrChild; ++i) {
|
for (int i = 0; i < nrChild; ++i) {
|
||||||
QListWidgetItem *item = fileList->item(i);
|
QListWidgetItem *item = fileList->item(i);
|
||||||
QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject();
|
if (p_file == getVFile(item)) {
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
if (itemJson["name"].toString() == name) {
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem* VFileList::createFileAndUpdateList(const QString &name)
|
|
||||||
{
|
|
||||||
QString path = QDir(rootPath).filePath(relativePath);
|
|
||||||
QString filePath = QDir(path).filePath(name);
|
|
||||||
QFile file(filePath);
|
|
||||||
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
|
||||||
qWarning() << "error: fail to create file:" << filePath;
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Could not create file \"%1\" under \"%2\".")
|
|
||||||
.arg(name).arg(path), QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Please check if there already exists a file named \"%1\".").arg(name));
|
|
||||||
msgBox.exec();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
qDebug() << "create file:" << filePath;
|
|
||||||
|
|
||||||
if (!addFileInConfig(filePath, 0)) {
|
|
||||||
file.remove();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return insertFileListItem(readFileInConfig(filePath), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::deleteFileAndUpdateList(const QString &p_notebook,
|
|
||||||
const QString &p_relativePath)
|
|
||||||
{
|
|
||||||
QString filePath = QDir(vnote->getNotebookPath(p_notebook)).filePath(p_relativePath);
|
|
||||||
|
|
||||||
if (!removeFileInConfig(filePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete local images in ./images
|
|
||||||
deleteLocalImages(filePath);
|
|
||||||
|
|
||||||
// Delete the file
|
|
||||||
QFile file(filePath);
|
|
||||||
if (!file.remove()) {
|
|
||||||
qWarning() << "error: fail to delete" << filePath;
|
|
||||||
} else {
|
|
||||||
qDebug() << "delete" << filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidgetItem *item = findItem(p_notebook, p_relativePath);
|
|
||||||
if (item) {
|
|
||||||
removeFileListItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::handleItemClicked(QListWidgetItem *currentItem)
|
void VFileList::handleItemClicked(QListWidgetItem *currentItem)
|
||||||
{
|
{
|
||||||
if (!currentItem) {
|
if (!currentItem) {
|
||||||
emit fileClicked(QJsonObject());
|
emit fileClicked(NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
|
||||||
fileList->update();
|
fileList->update();
|
||||||
QJsonObject itemJson = currentItem->data(Qt::UserRole).toJsonObject();
|
emit fileClicked(getVFile(currentItem), OpenFileMode::Read);
|
||||||
Q_ASSERT(!itemJson.isEmpty());
|
|
||||||
itemJson["notebook"] = notebook;
|
|
||||||
itemJson["relative_path"] = QDir::cleanPath(QDir(relativePath).filePath(itemJson["name"].toString()));
|
|
||||||
itemJson["mode"] = OpenFileMode::Read;
|
|
||||||
emit fileClicked(itemJson);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VFileList::importFile(const QString &name)
|
bool VFileList::importFile(const QString &p_srcFilePath)
|
||||||
{
|
{
|
||||||
if (name.isEmpty()) {
|
if (p_srcFilePath.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isConflictNameWithExisting(name)) {
|
Q_ASSERT(m_directory);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy file @name to current directory
|
// Copy file @name to current directory
|
||||||
QString targetPath = QDir(rootPath).filePath(relativePath);
|
QString targetPath = m_directory->retrivePath();
|
||||||
QString srcName = QFileInfo(name).fileName();
|
QString srcName = VUtils::fileNameFromPath(p_srcFilePath);
|
||||||
if (srcName.isEmpty()) {
|
if (srcName.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QString targetName = QDir(targetPath).filePath(srcName);
|
QString targetFilePath = QDir(targetPath).filePath(srcName);
|
||||||
|
bool ret = VUtils::copyFile(p_srcFilePath, targetFilePath, false);
|
||||||
bool ret = QFile::copy(name, targetName);
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
qWarning() << "error: fail to copy" << name << "to" << targetName;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update current directory's config file to include this new file
|
VFile *destFile = m_directory->addFile(srcName, -1);
|
||||||
QJsonObject dirJson = VConfigManager::readDirectoryConfig(targetPath);
|
if (destFile) {
|
||||||
Q_ASSERT(!dirJson.isEmpty());
|
return insertFileListItem(destFile, false);
|
||||||
QJsonObject fileJson;
|
}
|
||||||
fileJson["name"] = srcName;
|
|
||||||
QJsonArray fileArray = dirJson["files"].toArray();
|
|
||||||
fileArray.push_front(fileJson);
|
|
||||||
dirJson["files"] = fileArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(targetPath, dirJson)) {
|
|
||||||
qWarning() << "error: fail to update directory's configuration file to add a new file"
|
|
||||||
<< srcName;
|
|
||||||
QFile(targetName).remove();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertFileListItem(fileJson, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::handleDirectoryRenamed(const QString ¬ebook,
|
|
||||||
const QString &oldRelativePath, const QString &newRelativePath)
|
|
||||||
{
|
|
||||||
if (notebook == this->notebook
|
|
||||||
&& relativePath.startsWith(oldRelativePath)) {
|
|
||||||
relativePath.replace(0, oldRelativePath.size(), newRelativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::convertFileType(const QString ¬ebook, const QString &fileRelativePath,
|
|
||||||
DocType oldType, DocType newType)
|
|
||||||
{
|
|
||||||
Q_ASSERT(oldType != newType);
|
|
||||||
QString filePath = QDir(vnote->getNotebookPath(notebook)).filePath(fileRelativePath);
|
|
||||||
QString fileText = VUtils::readFileFromDisk(filePath);
|
|
||||||
QTextEdit editor;
|
|
||||||
if (oldType == DocType::Markdown) {
|
|
||||||
editor.setPlainText(fileText);
|
|
||||||
fileText = editor.toHtml();
|
|
||||||
} else {
|
|
||||||
editor.setHtml(fileText);
|
|
||||||
fileText = editor.toPlainText();
|
|
||||||
}
|
|
||||||
VUtils::writeFileToDisk(filePath, fileText);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::deleteLocalImages(const QString &filePath)
|
|
||||||
{
|
|
||||||
if (!VUtils::isMarkdown(filePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<QString> images = VUtils::imagesFromMarkdownFile(filePath);
|
|
||||||
int deleted = 0;
|
|
||||||
for (int i = 0; i < images.size(); ++i) {
|
|
||||||
QFile file(images[i]);
|
|
||||||
if (file.remove()) {
|
|
||||||
++deleted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "delete" << deleted << "images for" << filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFileList::copySelectedFiles(bool p_isCut)
|
void VFileList::copySelectedFiles(bool p_isCut)
|
||||||
{
|
{
|
||||||
QList<QListWidgetItem *> items = fileList->selectedItems();
|
QList<QListWidgetItem *> items = fileList->selectedItems();
|
||||||
@ -480,14 +339,15 @@ void VFileList::copySelectedFiles(bool p_isCut)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonArray files;
|
QJsonArray files;
|
||||||
QDir dir(relativePath);
|
m_copiedFiles.clear();
|
||||||
for (int i = 0; i < items.size(); ++i) {
|
for (int i = 0; i < items.size(); ++i) {
|
||||||
QJsonObject itemJson = items[i]->data(Qt::UserRole).toJsonObject();
|
VFile *file = getVFile(items[i]);
|
||||||
QString itemName = itemJson["name"].toString();
|
|
||||||
QJsonObject fileJson;
|
QJsonObject fileJson;
|
||||||
fileJson["notebook"] = notebook;
|
fileJson["notebook"] = file->retriveNotebook();
|
||||||
fileJson["relative_path"] = dir.filePath(itemName);
|
fileJson["path"] = file->retrivePath();
|
||||||
files.append(fileJson);
|
files.append(fileJson);
|
||||||
|
|
||||||
|
m_copiedFiles.append(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyFileInfoToClipboard(files, p_isCut);
|
copyFileInfoToClipboard(files, p_isCut);
|
||||||
@ -511,219 +371,71 @@ void VFileList::copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut)
|
|||||||
|
|
||||||
void VFileList::pasteFilesInCurDir()
|
void VFileList::pasteFilesInCurDir()
|
||||||
{
|
{
|
||||||
pasteFiles(notebook, relativePath);
|
pasteFiles(m_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFileList::pasteFiles(const QString &p_notebook, const QString &p_dirRelativePath)
|
void VFileList::pasteFiles(VDirectory *p_destDir)
|
||||||
{
|
{
|
||||||
qDebug() << "paste files to" << p_notebook << p_dirRelativePath;
|
qDebug() << "paste files to" << p_destDir->getName();
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
QString text = clipboard->text();
|
QString text = clipboard->text();
|
||||||
QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object();
|
QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object();
|
||||||
Q_ASSERT(!clip.isEmpty() && clip["operation"] == (int)ClipboardOpType::CopyFile);
|
Q_ASSERT(!clip.isEmpty() && clip["operation"] == (int)ClipboardOpType::CopyFile);
|
||||||
|
|
||||||
bool isCut = clip["is_cut"].toBool();
|
bool isCut = clip["is_cut"].toBool();
|
||||||
QJsonArray sources = clip["sources"].toArray();
|
|
||||||
|
|
||||||
int nrFiles = sources.size();
|
|
||||||
QDir destDir(p_dirRelativePath);
|
|
||||||
int nrPasted = 0;
|
int nrPasted = 0;
|
||||||
for (int i = 0; i < nrFiles; ++i) {
|
for (int i = 0; i < m_copiedFiles.size(); ++i) {
|
||||||
QJsonObject file = sources[i].toObject();
|
QPointer<VFile> srcFile = m_copiedFiles[i];
|
||||||
QString srcNotebook = file["notebook"].toString();
|
if (!srcFile) {
|
||||||
QString srcRelativePath = file["relative_path"].toString();
|
continue;
|
||||||
bool ret = copyFile(srcNotebook, srcRelativePath, p_notebook,
|
}
|
||||||
destDir.filePath(VUtils::fileNameFromPath(srcRelativePath)), isCut);
|
QString fileName = srcFile->getName();
|
||||||
if (ret) {
|
VDirectory *srcDir = srcFile->getDirectory();
|
||||||
|
if (srcDir == p_destDir && !isCut) {
|
||||||
|
// Copy and paste in the same directory.
|
||||||
|
// Rename it to xx_copy.md
|
||||||
|
fileName = VUtils::generateCopiedFileName(srcDir->retrivePath(), fileName);
|
||||||
|
}
|
||||||
|
if (copyFile(p_destDir, fileName, srcFile, isCut)) {
|
||||||
nrPasted++;
|
nrPasted++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "pasted" << nrPasted << "files sucessfully";
|
qDebug() << "pasted" << nrPasted << "files sucessfully";
|
||||||
clipboard->clear();
|
clipboard->clear();
|
||||||
|
m_copiedFiles.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VFileList::copyFile(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_file, bool p_cut)
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath,
|
|
||||||
bool p_isCut)
|
|
||||||
{
|
{
|
||||||
QString srcPath = QDir(vnote->getNotebookPath(p_srcNotebook)).filePath(p_srcRelativePath);
|
QString srcPath = QDir::cleanPath(p_file->retrivePath());
|
||||||
srcPath = QDir::cleanPath(srcPath);
|
QString destPath = QDir::cleanPath(QDir(p_destDir->retrivePath()).filePath(p_destName));
|
||||||
QString destPath = QDir(vnote->getNotebookPath(p_destNotebook)).filePath(p_destRelativePath);
|
|
||||||
destPath = QDir::cleanPath(destPath);
|
|
||||||
if (srcPath == destPath) {
|
if (srcPath == destPath) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// If change the file type, we need to close it first
|
||||||
// If change the file type, we need to convert it
|
DocType docType = p_file->getDocType();
|
||||||
bool needConversion = false;
|
|
||||||
DocType docType = VUtils::isMarkdown(srcPath) ? DocType::Markdown : DocType::Html;
|
|
||||||
DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html;
|
DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html;
|
||||||
if (docType != newDocType) {
|
if (docType != newDocType) {
|
||||||
if (editArea->isFileOpened(p_srcNotebook, p_srcRelativePath)) {
|
if (editArea->isFileOpened(p_file)) {
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Rename will change the note type"),
|
int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
||||||
QMessageBox::Ok | QMessageBox::Cancel, this);
|
QString("The renaming will change the note type."),
|
||||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
QString("You should close the note %1 before continue.").arg(p_file->getName()),
|
||||||
msgBox.setInformativeText(QString("You should close the note %1 before continue")
|
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok, this);
|
||||||
.arg(VUtils::fileNameFromPath(p_srcRelativePath)));
|
if (QMessageBox::Ok == ret) {
|
||||||
if (QMessageBox::Ok == msgBox.exec()) {
|
if (!editArea->closeFile(p_file, false)) {
|
||||||
QJsonObject curItemJson;
|
|
||||||
curItemJson["notebook"] = p_srcNotebook;
|
|
||||||
curItemJson["relative_path"] = p_srcRelativePath;
|
|
||||||
curItemJson["is_forced"] = false;
|
|
||||||
if (!editArea->closeFile(curItemJson)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Convert it later
|
|
||||||
needConversion = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QString> images;
|
VFile *destFile = VDirectory::copyFile(p_destDir, p_destName, p_file, p_cut);
|
||||||
if (docType == DocType::Markdown) {
|
|
||||||
images = VUtils::imagesFromMarkdownFile(srcPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the file
|
|
||||||
if (!VUtils::copyFile(srcPath, destPath, p_isCut)) {
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Fail to copy %1 from %2.")
|
|
||||||
.arg(p_srcRelativePath).arg(p_srcNotebook), QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Please check if there already exists a file with the same name"));
|
|
||||||
msgBox.exec();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needConversion) {
|
|
||||||
convertFileType(p_destNotebook, p_destRelativePath, docType, newDocType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to copy images when it is still markdown
|
|
||||||
if (!images.isEmpty()) {
|
|
||||||
if (newDocType == DocType::Markdown) {
|
|
||||||
QString dirPath = QDir(VUtils::basePathFromPath(destPath)).filePath("images");
|
|
||||||
VUtils::makeDirectory(dirPath);
|
|
||||||
int nrPasted = 0;
|
|
||||||
for (int i = 0; i < images.size(); ++i) {
|
|
||||||
if (!QFile(images[i]).exists()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString destImagePath = QDir(dirPath).filePath(VUtils::fileNameFromPath(images[i]));
|
|
||||||
if (VUtils::copyFile(images[i], destImagePath, p_isCut)) {
|
|
||||||
nrPasted++;
|
|
||||||
} else {
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Fail to copy image %1.")
|
|
||||||
.arg(images[i]), QMessageBox::Ok, this);
|
|
||||||
msgBox.setInformativeText(QString("Please check if there already exists a file with the same name and manually copy it"));
|
|
||||||
msgBox.exec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "pasted" << nrPasted << "images sucessfully";
|
|
||||||
} else {
|
|
||||||
// Delete the images
|
|
||||||
for (int i = 0; i < images.size(); ++i) {
|
|
||||||
QFile file(images[i]);
|
|
||||||
file.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int idx = -1;
|
|
||||||
if (p_isCut) {
|
|
||||||
// Remove src in the config
|
|
||||||
idx = removeFileInConfig(srcPath);
|
|
||||||
if (VUtils::basePathFromPath(srcPath) != VUtils::basePathFromPath(destPath)) {
|
|
||||||
idx = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add dest in the config
|
|
||||||
addFileInConfig(destPath, idx);
|
|
||||||
|
|
||||||
updateFileList();
|
updateFileList();
|
||||||
|
if (destFile) {
|
||||||
if (p_isCut) {
|
emit fileUpdated(destFile);
|
||||||
emit fileRenamed(p_srcNotebook, p_srcRelativePath,
|
|
||||||
p_destNotebook, p_destRelativePath);
|
|
||||||
}
|
}
|
||||||
return true;
|
return destFile != NULL;
|
||||||
}
|
|
||||||
|
|
||||||
int VFileList::removeFileInConfig(const QString &p_filePath)
|
|
||||||
{
|
|
||||||
QString dirPath = VUtils::basePathFromPath(p_filePath);
|
|
||||||
QString fileName = VUtils::fileNameFromPath(p_filePath);
|
|
||||||
// Update current directory's config file to exclude this file
|
|
||||||
QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath);
|
|
||||||
Q_ASSERT(!dirJson.isEmpty());
|
|
||||||
QJsonArray fileArray = dirJson["files"].toArray();
|
|
||||||
bool deleted = false;
|
|
||||||
int idx = -1;
|
|
||||||
for (int i = 0; i < fileArray.size(); ++i) {
|
|
||||||
QJsonObject ele = fileArray[i].toObject();
|
|
||||||
if (ele["name"].toString() == fileName) {
|
|
||||||
fileArray.removeAt(i);
|
|
||||||
deleted = true;
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!deleted) {
|
|
||||||
qWarning() << "error: fail to find" << fileName << "to delete";
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
dirJson["files"] = fileArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(dirPath, dirJson)) {
|
|
||||||
qWarning() << "error: fail to update directory's configuration file to delete"
|
|
||||||
<< fileName;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @index = -1, add it to the end of the list
|
|
||||||
bool VFileList::addFileInConfig(const QString &p_filePath, int p_index)
|
|
||||||
{
|
|
||||||
QString dirPath = VUtils::basePathFromPath(p_filePath);
|
|
||||||
QString fileName = VUtils::fileNameFromPath(p_filePath);
|
|
||||||
|
|
||||||
// Update current directory's config file to include this file
|
|
||||||
QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath);
|
|
||||||
Q_ASSERT(!dirJson.isEmpty());
|
|
||||||
QJsonObject fileJson;
|
|
||||||
fileJson["name"] = fileName;
|
|
||||||
QJsonArray fileArray = dirJson["files"].toArray();
|
|
||||||
if (p_index == -1) {
|
|
||||||
p_index = fileArray.size();
|
|
||||||
}
|
|
||||||
fileArray.insert(p_index, fileJson);
|
|
||||||
dirJson["files"] = fileArray;
|
|
||||||
if (!VConfigManager::writeDirectoryConfig(dirPath, dirJson)) {
|
|
||||||
qWarning() << "error: fail to update directory's configuration file to add a new file"
|
|
||||||
<< fileName;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject VFileList::readFileInConfig(const QString &p_filePath)
|
|
||||||
{
|
|
||||||
QString dirPath = VUtils::basePathFromPath(p_filePath);
|
|
||||||
QString fileName = VUtils::fileNameFromPath(p_filePath);
|
|
||||||
|
|
||||||
QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath);
|
|
||||||
Q_ASSERT(!dirJson.isEmpty());
|
|
||||||
|
|
||||||
qDebug() << "config" << p_filePath;
|
|
||||||
QJsonArray fileArray = dirJson["files"].toArray();
|
|
||||||
for (int i = 0; i < fileArray.size(); ++i) {
|
|
||||||
QJsonObject ele = fileArray[i].toObject();
|
|
||||||
if (ele["name"].toString() == fileName) {
|
|
||||||
return ele;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QJsonObject();
|
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,16 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QListWidgetItem>
|
||||||
#include "vnotebook.h"
|
#include "vnotebook.h"
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
class VNote;
|
class VNote;
|
||||||
class QListWidget;
|
class QListWidget;
|
||||||
class QListWidgetItem;
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class VEditArea;
|
class VEditArea;
|
||||||
|
|
||||||
@ -19,69 +22,49 @@ class VFileList : public QWidget
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit VFileList(VNote *vnote, QWidget *parent = 0);
|
explicit VFileList(QWidget *parent = 0);
|
||||||
bool importFile(const QString &name);
|
bool importFile(const QString &p_srcFilePath);
|
||||||
inline void setEditArea(VEditArea *editArea);
|
inline void setEditArea(VEditArea *editArea);
|
||||||
void fileInfo(const QString &p_notebook, const QString &p_relativePath);
|
void fileInfo(VFile *p_file);
|
||||||
void deleteFile(const QString &p_notebook, const QString &p_relativePath);
|
void deleteFile(VFile *p_file);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void fileClicked(QJsonObject fileJson);
|
void fileClicked(VFile *p_file, OpenFileMode mode = OpenFileMode::Read);
|
||||||
void fileDeleted(QJsonObject fileJson);
|
void fileCreated(VFile *p_file, OpenFileMode mode = OpenFileMode::Read);
|
||||||
void fileCreated(QJsonObject fileJson);
|
void fileUpdated(const VFile *p_file);
|
||||||
void fileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath);
|
|
||||||
void directoryChanged(const QString ¬ebook, const QString &relativePath);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void contextMenuRequested(QPoint pos);
|
void contextMenuRequested(QPoint pos);
|
||||||
void handleItemClicked(QListWidgetItem *currentItem);
|
void handleItemClicked(QListWidgetItem *currentItem);
|
||||||
void curFileInfo();
|
void fileInfo();
|
||||||
void deleteCurFile();
|
// m_copiedFiles will keep the files's VFile.
|
||||||
void copySelectedFiles(bool p_isCut = false);
|
void copySelectedFiles(bool p_isCut = false);
|
||||||
void cutSelectedFiles();
|
void cutSelectedFiles();
|
||||||
void pasteFilesInCurDir();
|
void pasteFilesInCurDir();
|
||||||
|
void deleteFile();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setDirectory(QJsonObject dirJson);
|
void setDirectory(VDirectory *p_directory);
|
||||||
void handleDirectoryRenamed(const QString ¬ebook, const QString &oldRelativePath,
|
|
||||||
const QString &newRelativePath);
|
|
||||||
void newFile();
|
void newFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
void updateFileList();
|
void updateFileList();
|
||||||
QListWidgetItem *insertFileListItem(QJsonObject fileJson, bool atFront = false);
|
QListWidgetItem *insertFileListItem(VFile *file, bool atFront = false);
|
||||||
void removeFileListItem(QListWidgetItem *item);
|
void removeFileListItem(QListWidgetItem *item);
|
||||||
void initActions();
|
void initActions();
|
||||||
bool isConflictNameWithExisting(const QString &name);
|
QListWidgetItem *findItem(const VFile *p_file);
|
||||||
QListWidgetItem *createFileAndUpdateList(const QString &name);
|
|
||||||
void deleteFileAndUpdateList(const QString &p_notebook,
|
|
||||||
const QString &p_relativePath);
|
|
||||||
void clearDirectoryInfo();
|
|
||||||
void convertFileType(const QString ¬ebook, const QString &fileRelativePath,
|
|
||||||
DocType oldType, DocType newType);
|
|
||||||
QListWidgetItem *findItem(const QString &p_notebook, const QString &p_relativePath);
|
|
||||||
void deleteLocalImages(const QString &filePath);
|
|
||||||
void copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut);
|
void copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut);
|
||||||
void pasteFiles(const QString &p_notebook, const QString &p_dirRelativePath);
|
void pasteFiles(VDirectory *p_destDir);
|
||||||
bool copyFile(const QString &p_srcNotebook, const QString &p_srcRelativePath,
|
bool copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_file, bool p_cut);
|
||||||
const QString &p_destNotebook, const QString &p_destRelativePath,
|
// New items have been added to direcotry. Update file list accordingly.
|
||||||
bool p_isCut);
|
QVector<QListWidgetItem *> updateFileListAdded();
|
||||||
int removeFileInConfig(const QString &p_filePath);
|
inline QPointer<VFile> getVFile(QListWidgetItem *p_item);
|
||||||
bool addFileInConfig(const QString &p_filePath, int p_index);
|
|
||||||
QJsonObject readFileInConfig(const QString &p_filePath);
|
|
||||||
|
|
||||||
VNote *vnote;
|
|
||||||
QString notebook;
|
|
||||||
// Current directory's relative path
|
|
||||||
QString relativePath;
|
|
||||||
// Used for cache
|
|
||||||
QString rootPath;
|
|
||||||
|
|
||||||
VEditArea *editArea;
|
VEditArea *editArea;
|
||||||
|
|
||||||
QListWidget *fileList;
|
QListWidget *fileList;
|
||||||
|
QPointer<VDirectory> m_directory;
|
||||||
|
QVector<QPointer<VFile> > m_copiedFiles;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
QAction *newFileAct;
|
QAction *newFileAct;
|
||||||
@ -97,4 +80,10 @@ inline void VFileList::setEditArea(VEditArea *editArea)
|
|||||||
this->editArea = editArea;
|
this->editArea = editArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QPointer<VFile> VFileList::getVFile(QListWidgetItem *p_item)
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_item);
|
||||||
|
return p_item->data(Qt::UserRole).value<VFile *>();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VFILELIST_H
|
#endif // VFILELIST_H
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
#include "vfilelocation.h"
|
|
||||||
|
|
||||||
VFileLocation::VFileLocation()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VFileLocation::VFileLocation(const QString &p_notebook, const QString &p_relativePath)
|
|
||||||
: m_notebook(p_notebook), m_relativePath(p_relativePath)
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef VFILELOCATION_H
|
|
||||||
#define VFILELOCATION_H
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class VFileLocation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VFileLocation();
|
|
||||||
VFileLocation(const QString &p_notebook, const QString &p_relativePath);
|
|
||||||
QString m_notebook;
|
|
||||||
QString m_relativePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VFILELOCATION_H
|
|
@ -35,7 +35,7 @@ void VMainWindow::setupUI()
|
|||||||
{
|
{
|
||||||
QWidget *directoryPanel = setupDirectoryPanel();
|
QWidget *directoryPanel = setupDirectoryPanel();
|
||||||
|
|
||||||
fileList = new VFileList(vnote);
|
fileList = new VFileList();
|
||||||
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
||||||
|
|
||||||
editArea = new VEditArea(vnote);
|
editArea = new VEditArea(vnote);
|
||||||
@ -57,23 +57,14 @@ void VMainWindow::setupUI()
|
|||||||
|
|
||||||
connect(directoryTree, &VDirectoryTree::currentDirectoryChanged,
|
connect(directoryTree, &VDirectoryTree::currentDirectoryChanged,
|
||||||
fileList, &VFileList::setDirectory);
|
fileList, &VFileList::setDirectory);
|
||||||
connect(directoryTree, &VDirectoryTree::directoryRenamed,
|
|
||||||
fileList, &VFileList::handleDirectoryRenamed);
|
|
||||||
connect(fileList, &VFileList::directoryChanged,
|
|
||||||
this, &VMainWindow::handleFileListDirectoryChanged);
|
|
||||||
|
|
||||||
connect(fileList, &VFileList::fileClicked,
|
connect(fileList, &VFileList::fileClicked,
|
||||||
editArea, &VEditArea::openFile);
|
editArea, &VEditArea::openFile);
|
||||||
connect(fileList, &VFileList::fileDeleted,
|
|
||||||
editArea, &VEditArea::closeFile);
|
|
||||||
connect(fileList, &VFileList::fileCreated,
|
connect(fileList, &VFileList::fileCreated,
|
||||||
editArea, &VEditArea::openFile);
|
editArea, &VEditArea::openFile);
|
||||||
|
connect(fileList, &VFileList::fileUpdated,
|
||||||
|
editArea, &VEditArea::handleFileUpdated);
|
||||||
connect(editArea, &VEditArea::curTabStatusChanged,
|
connect(editArea, &VEditArea::curTabStatusChanged,
|
||||||
this, &VMainWindow::handleCurTabStatusChanged);
|
this, &VMainWindow::handleCurTabStatusChanged);
|
||||||
connect(directoryTree, &VDirectoryTree::directoryRenamed,
|
|
||||||
editArea, &VEditArea::handleDirectoryRenamed);
|
|
||||||
connect(fileList, &VFileList::fileRenamed,
|
|
||||||
editArea, &VEditArea::handleFileRenamed);
|
|
||||||
|
|
||||||
connect(newNotebookBtn, &QPushButton::clicked,
|
connect(newNotebookBtn, &QPushButton::clicked,
|
||||||
this, &VMainWindow::onNewNotebookBtnClicked);
|
this, &VMainWindow::onNewNotebookBtnClicked);
|
||||||
@ -433,10 +424,10 @@ void VMainWindow::setCurNotebookIndex(int index)
|
|||||||
}
|
}
|
||||||
Q_ASSERT(index < vnote->getNotebooks().size());
|
Q_ASSERT(index < vnote->getNotebooks().size());
|
||||||
// Update directoryTree
|
// Update directoryTree
|
||||||
QString notebook;
|
VNotebook *notebook = NULL;
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
vconfig.setCurNotebookIndex(index);
|
vconfig.setCurNotebookIndex(index);
|
||||||
notebook = vnote->getNotebooks()[index]->getName();
|
notebook = vnote->getNotebooks()[index];
|
||||||
newRootDirAct->setEnabled(true);
|
newRootDirAct->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
newRootDirAct->setEnabled(false);
|
newRootDirAct->setEnabled(false);
|
||||||
@ -525,7 +516,8 @@ void VMainWindow::onNotebookInfoBtnClicked()
|
|||||||
void VMainWindow::importNoteFromFile()
|
void VMainWindow::importNoteFromFile()
|
||||||
{
|
{
|
||||||
static QString lastPath = QDir::homePath();
|
static QString lastPath = QDir::homePath();
|
||||||
QStringList files = QFileDialog::getOpenFileNames(this,tr("Select files(HTML or Markdown) to be imported as notes"),
|
QStringList files = QFileDialog::getOpenFileNames(this,
|
||||||
|
tr("Select files(HTML or Markdown) to be imported as notes"),
|
||||||
lastPath);
|
lastPath);
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -668,15 +660,15 @@ void VMainWindow::setRenderBackgroundColor(QAction *action)
|
|||||||
vnote->updateTemplate();
|
vnote->updateTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::updateToolbarFromTabChage(bool empty, bool editMode, bool modifiable)
|
void VMainWindow::updateToolbarFromTabChage(const VFile *p_file, bool p_editMode)
|
||||||
{
|
{
|
||||||
if (empty || !modifiable) {
|
if (!p_file) {
|
||||||
editNoteAct->setEnabled(false);
|
editNoteAct->setEnabled(false);
|
||||||
saveExitAct->setVisible(false);
|
saveExitAct->setVisible(false);
|
||||||
discardExitAct->setVisible(false);
|
discardExitAct->setVisible(false);
|
||||||
saveNoteAct->setVisible(false);
|
saveNoteAct->setVisible(false);
|
||||||
deleteNoteAct->setEnabled(false);
|
deleteNoteAct->setEnabled(false);
|
||||||
} else if (editMode) {
|
} else if (p_editMode) {
|
||||||
editNoteAct->setEnabled(false);
|
editNoteAct->setEnabled(false);
|
||||||
saveExitAct->setVisible(true);
|
saveExitAct->setVisible(true);
|
||||||
discardExitAct->setVisible(true);
|
discardExitAct->setVisible(true);
|
||||||
@ -690,29 +682,26 @@ void VMainWindow::updateToolbarFromTabChage(bool empty, bool editMode, bool modi
|
|||||||
deleteNoteAct->setEnabled(true);
|
deleteNoteAct->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty) {
|
if (p_file) {
|
||||||
noteInfoAct->setEnabled(false);
|
|
||||||
} else {
|
|
||||||
noteInfoAct->setEnabled(true);
|
noteInfoAct->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
noteInfoAct->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::handleCurTabStatusChanged(const QString ¬ebook, const QString &relativePath,
|
void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, bool p_editMode)
|
||||||
bool editMode, bool modifiable, bool modified)
|
|
||||||
{
|
{
|
||||||
updateToolbarFromTabChage(notebook.isEmpty(), editMode, modifiable);
|
updateToolbarFromTabChage(p_file, p_editMode);
|
||||||
|
|
||||||
QString title;
|
QString title;
|
||||||
if (!notebook.isEmpty()) {
|
if (p_file) {
|
||||||
title = QString("[%1] %2").arg(notebook).arg(relativePath);
|
title = QString("[%1] %2").arg(p_file->retriveNotebook()).arg(p_file->retrivePath());
|
||||||
if (modified) {
|
if (p_file->isModified()) {
|
||||||
title.append('*');
|
title.append('*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateWindowTitle(title);
|
updateWindowTitle(title);
|
||||||
|
m_curFile = const_cast<VFile *>(p_file);
|
||||||
curEditNotebook = notebook;
|
|
||||||
curEditRelativePath = relativePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::changePanelView(QAction *action)
|
void VMainWindow::changePanelView(QAction *action)
|
||||||
@ -751,15 +740,6 @@ void VMainWindow::changeSplitterView(int nrPanel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::handleFileListDirectoryChanged(const QString ¬ebook, const QString &relativePath)
|
|
||||||
{
|
|
||||||
if (relativePath.isEmpty()) {
|
|
||||||
newNoteAct->setEnabled(false);
|
|
||||||
} else {
|
|
||||||
newNoteAct->setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VMainWindow::updateWindowTitle(const QString &str)
|
void VMainWindow::updateWindowTitle(const QString &str)
|
||||||
{
|
{
|
||||||
QString title = "VNote";
|
QString title = "VNote";
|
||||||
@ -771,12 +751,14 @@ void VMainWindow::updateWindowTitle(const QString &str)
|
|||||||
|
|
||||||
void VMainWindow::curEditFileInfo()
|
void VMainWindow::curEditFileInfo()
|
||||||
{
|
{
|
||||||
fileList->fileInfo(curEditNotebook, curEditRelativePath);
|
Q_ASSERT(m_curFile);
|
||||||
|
fileList->fileInfo(m_curFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::deleteCurNote()
|
void VMainWindow::deleteCurNote()
|
||||||
{
|
{
|
||||||
fileList->deleteFile(curEditNotebook, curEditRelativePath);
|
Q_ASSERT(m_curFile);
|
||||||
|
fileList->deleteFile(m_curFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMainWindow::closeEvent(QCloseEvent *event)
|
void VMainWindow::closeEvent(QCloseEvent *event)
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
@ -48,15 +50,13 @@ private slots:
|
|||||||
void setTabStopWidth(QAction *action);
|
void setTabStopWidth(QAction *action);
|
||||||
void setEditorBackgroundColor(QAction *action);
|
void setEditorBackgroundColor(QAction *action);
|
||||||
void setRenderBackgroundColor(QAction *action);
|
void setRenderBackgroundColor(QAction *action);
|
||||||
void handleCurTabStatusChanged(const QString ¬ebook, const QString &relativePath,
|
void handleCurTabStatusChanged(const VFile *p_file, bool p_editMode);
|
||||||
bool editMode, bool modifiable, bool modified);
|
|
||||||
void changePanelView(QAction *action);
|
void changePanelView(QAction *action);
|
||||||
void handleFileListDirectoryChanged(const QString ¬ebook, const QString &relativePath);
|
|
||||||
void curEditFileInfo();
|
void curEditFileInfo();
|
||||||
void deleteCurNote();
|
void deleteCurNote();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void curNotebookChanged(const QString ¬ebookName);
|
void curNotebookChanged(VNotebook *p_notebook);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
||||||
@ -74,16 +74,14 @@ private:
|
|||||||
void initEditorBackgroundMenu(QMenu *menu);
|
void initEditorBackgroundMenu(QMenu *menu);
|
||||||
void changeSplitterView(int nrPanel);
|
void changeSplitterView(int nrPanel);
|
||||||
void updateWindowTitle(const QString &str);
|
void updateWindowTitle(const QString &str);
|
||||||
void updateToolbarFromTabChage(bool empty, bool editMode, bool modifiable);
|
void updateToolbarFromTabChage(const VFile *p_file, bool p_editMode);
|
||||||
void saveStateAndGeometry();
|
void saveStateAndGeometry();
|
||||||
void restoreStateAndGeometry();
|
void restoreStateAndGeometry();
|
||||||
|
|
||||||
// If true, comboBox changes will not trigger any signal out
|
// If true, comboBox changes will not trigger any signal out
|
||||||
bool notebookComboMuted;
|
bool notebookComboMuted;
|
||||||
VNote *vnote;
|
VNote *vnote;
|
||||||
|
QPointer<VFile> m_curFile;
|
||||||
QString curEditNotebook;
|
|
||||||
QString curEditRelativePath;
|
|
||||||
|
|
||||||
QLabel *notebookLabel;
|
QLabel *notebookLabel;
|
||||||
QLabel *directoryLabel;
|
QLabel *directoryLabel;
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "vmdeditoperations.h"
|
#include "vmdeditoperations.h"
|
||||||
#include "dialog/vinsertimagedialog.h"
|
#include "dialog/vinsertimagedialog.h"
|
||||||
#include "vnotefile.h"
|
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
#include "vedit.h"
|
#include "vedit.h"
|
||||||
#include "vdownloader.h"
|
#include "vdownloader.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
|
||||||
VMdEditOperations::VMdEditOperations(VEdit *editor, VNoteFile *noteFile)
|
VMdEditOperations::VMdEditOperations(VEdit *p_editor, VFile *p_file)
|
||||||
: VEditOperations(editor, noteFile)
|
: VEditOperations(p_editor, p_file)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,13 +26,11 @@ bool VMdEditOperations::insertImageFromMimeData(const QMimeData *source)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
VInsertImageDialog dialog(QObject::tr("Insert image from clipboard"), QObject::tr("image_title"),
|
VInsertImageDialog dialog(QObject::tr("Insert image from clipboard"), QObject::tr("image_title"),
|
||||||
"", (QWidget *)editor);
|
"", (QWidget *)m_editor);
|
||||||
dialog.setBrowseable(false);
|
dialog.setBrowseable(false);
|
||||||
dialog.setImage(image);
|
dialog.setImage(image);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
insertImageFromQImage(dialog.getImageTitleInput(),
|
insertImageFromQImage(dialog.getImageTitleInput(), m_file->retriveImagePath(), image);
|
||||||
QDir::cleanPath(QDir(noteFile->basePath).filePath("images")),
|
|
||||||
image);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -48,7 +46,7 @@ void VMdEditOperations::insertImageFromQImage(const QString &title, const QStrin
|
|||||||
bool ret = image.save(filePath);
|
bool ret = image.save(filePath);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
QMessageBox msgBox(QMessageBox::Warning, QObject::tr("Warning"), QString("Fail to save image %1").arg(filePath),
|
QMessageBox msgBox(QMessageBox::Warning, QObject::tr("Warning"), QString("Fail to save image %1").arg(filePath),
|
||||||
QMessageBox::Ok, (QWidget *)editor);
|
QMessageBox::Ok, (QWidget *)m_editor);
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -56,7 +54,7 @@ void VMdEditOperations::insertImageFromQImage(const QString &title, const QStrin
|
|||||||
QString md = QString("").arg(title).arg(fileName);
|
QString md = QString("").arg(title).arg(fileName);
|
||||||
insertTextAtCurPos(md);
|
insertTextAtCurPos(md);
|
||||||
|
|
||||||
editor->insertImage(fileName);
|
m_editor->insertImage(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMdEditOperations::insertImageFromPath(const QString &title,
|
void VMdEditOperations::insertImageFromPath(const QString &title,
|
||||||
@ -71,7 +69,7 @@ void VMdEditOperations::insertImageFromPath(const QString &title,
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
qWarning() << "error: fail to copy" << oriImagePath << "to" << filePath;
|
qWarning() << "error: fail to copy" << oriImagePath << "to" << filePath;
|
||||||
QMessageBox msgBox(QMessageBox::Warning, QObject::tr("Warning"), QString("Fail to save image %1").arg(filePath),
|
QMessageBox msgBox(QMessageBox::Warning, QObject::tr("Warning"), QString("Fail to save image %1").arg(filePath),
|
||||||
QMessageBox::Ok, (QWidget *)editor);
|
QMessageBox::Ok, (QWidget *)m_editor);
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -79,7 +77,7 @@ void VMdEditOperations::insertImageFromPath(const QString &title,
|
|||||||
QString md = QString("").arg(title).arg(fileName);
|
QString md = QString("").arg(title).arg(fileName);
|
||||||
insertTextAtCurPos(md);
|
insertTextAtCurPos(md);
|
||||||
|
|
||||||
editor->insertImage(fileName);
|
m_editor->insertImage(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)
|
bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)
|
||||||
@ -105,7 +103,7 @@ bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VInsertImageDialog dialog(title, QObject::tr("image_title"), imagePath, (QWidget *)editor);
|
VInsertImageDialog dialog(title, QObject::tr("image_title"), imagePath, (QWidget *)m_editor);
|
||||||
dialog.setBrowseable(false);
|
dialog.setBrowseable(false);
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
dialog.setImage(image);
|
dialog.setImage(image);
|
||||||
@ -118,12 +116,10 @@ bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)
|
|||||||
}
|
}
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
insertImageFromPath(dialog.getImageTitleInput(),
|
insertImageFromPath(dialog.getImageTitleInput(), m_file->retriveImagePath(),
|
||||||
QDir::cleanPath(QDir(noteFile->basePath).filePath("images")),
|
|
||||||
imagePath);
|
imagePath);
|
||||||
} else {
|
} else {
|
||||||
insertImageFromQImage(dialog.getImageTitleInput(),
|
insertImageFromQImage(dialog.getImageTitleInput(), m_file->retriveImagePath(),
|
||||||
QDir::cleanPath(QDir(noteFile->basePath).filePath("images")),
|
|
||||||
dialog.getImage());
|
dialog.getImage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
class VMdEditOperations : public VEditOperations
|
class VMdEditOperations : public VEditOperations
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VMdEditOperations(VEdit *editor, VNoteFile *noteFile);
|
VMdEditOperations(VEdit *p_editor, VFile *p_file);
|
||||||
bool insertImageFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE;
|
bool insertImageFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE;
|
||||||
bool insertURLFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE;
|
bool insertURLFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE;
|
||||||
bool insertImageFromURL(const QUrl &imageUrl);
|
bool insertImageFromURL(const QUrl &imageUrl);
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include "vnotebook.h"
|
#include "vnotebook.h"
|
||||||
|
#include "vconstants.h"
|
||||||
enum OpenFileMode {Read = 0, Edit};
|
|
||||||
|
|
||||||
class VNote : public QObject
|
class VNote : public QObject
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
#include "vnotebook.h"
|
#include "vnotebook.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
VNotebook::VNotebook(QObject *parent)
|
#include "utils/vutils.h"
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent)
|
VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent)
|
||||||
: QObject(parent), m_name(name), m_path(path)
|
: QObject(parent), m_name(name), m_path(path)
|
||||||
{
|
{
|
||||||
|
m_rootDir = new VDirectory(this, VUtils::directoryNameFromPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
VNotebook::~VNotebook()
|
||||||
|
{
|
||||||
|
delete m_rootDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VNotebook::getName() const
|
QString VNotebook::getName() const
|
||||||
@ -33,5 +35,10 @@ void VNotebook::setPath(const QString &path)
|
|||||||
|
|
||||||
void VNotebook::close(bool p_forced)
|
void VNotebook::close(bool p_forced)
|
||||||
{
|
{
|
||||||
//TODO
|
m_rootDir->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VNotebook::open()
|
||||||
|
{
|
||||||
|
return m_rootDir->open();
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,17 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
class VDirectory;
|
||||||
|
|
||||||
class VNotebook : public QObject
|
class VNotebook : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VNotebook(QObject *parent = 0);
|
|
||||||
VNotebook(const QString &name, const QString &path, QObject *parent = 0);
|
VNotebook(const QString &name, const QString &path, QObject *parent = 0);
|
||||||
|
~VNotebook();
|
||||||
|
|
||||||
|
// Open the root directory to load contents
|
||||||
|
bool open();
|
||||||
// Close all the directory and files of this notebook.
|
// Close all the directory and files of this notebook.
|
||||||
// If @p_forced, unsaved files will also be closed without a confirm.
|
// If @p_forced, unsaved files will also be closed without a confirm.
|
||||||
void close(bool p_forced);
|
void close(bool p_forced);
|
||||||
@ -19,10 +23,21 @@ public:
|
|||||||
QString getPath() const;
|
QString getPath() const;
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
void setPath(const QString &path);
|
void setPath(const QString &path);
|
||||||
|
inline VDirectory *getRootDir();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void contentChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
|
// Parent is NULL for root directory
|
||||||
|
VDirectory *m_rootDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline VDirectory *VNotebook::getRootDir()
|
||||||
|
{
|
||||||
|
return m_rootDir;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VNOTEBOOK_H
|
#endif // VNOTEBOOK_H
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#include "vnotefile.h"
|
|
||||||
|
|
||||||
VNoteFile::VNoteFile(const QString &basePath, const QString &fileName,
|
|
||||||
const QString &content, DocType docType, bool modifiable)
|
|
||||||
: basePath(basePath), fileName(fileName),
|
|
||||||
content(content), docType(docType), modifiable(modifiable)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#ifndef VNOTEFILE_H
|
|
||||||
#define VNOTEFILE_H
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include "vconstants.h"
|
|
||||||
|
|
||||||
class VNoteFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VNoteFile(const QString &basePath, const QString &fileName, const QString &content,
|
|
||||||
DocType docType, bool modifiable);
|
|
||||||
|
|
||||||
QString basePath;
|
|
||||||
QString fileName;
|
|
||||||
QString content;
|
|
||||||
DocType docType;
|
|
||||||
bool modifiable;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VNOTEFILE_H
|
|
Loading…
x
Reference in New Issue
Block a user