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