refactor directory and file related logics

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2016-10-25 22:25:34 +08:00
parent 51d0eedcb2
commit 5409ce9769
20 changed files with 386 additions and 265 deletions

View File

@ -2,10 +2,9 @@
#include "vdirinfodialog.h" #include "vdirinfodialog.h"
VDirInfoDialog::VDirInfoDialog(const QString &title, const QString &info, VDirInfoDialog::VDirInfoDialog(const QString &title, const QString &info,
const QString &defaultName, const QString &defaultDescription, const QString &defaultName,
QWidget *parent) QWidget *parent)
: QDialog(parent), infoLabel(NULL), title(title), info(info), defaultName(defaultName), : QDialog(parent), infoLabel(NULL), title(title), info(info), defaultName(defaultName)
defaultDescription(defaultDescription)
{ {
setupUI(); setupUI();
@ -26,10 +25,6 @@ void VDirInfoDialog::setupUI()
nameEdit->selectAll(); nameEdit->selectAll();
nameLabel->setBuddy(nameEdit); nameLabel->setBuddy(nameEdit);
QLabel *descriptionLabel = new QLabel(tr("&Description"));
descriptionEdit = new QLineEdit(defaultDescription);
descriptionLabel->setBuddy(descriptionEdit);
okBtn = new QPushButton(tr("&OK")); okBtn = new QPushButton(tr("&OK"));
okBtn->setDefault(true); okBtn->setDefault(true);
cancelBtn = new QPushButton(tr("&Cancel")); cancelBtn = new QPushButton(tr("&Cancel"));
@ -40,8 +35,6 @@ void VDirInfoDialog::setupUI()
} }
topLayout->addWidget(nameLabel); topLayout->addWidget(nameLabel);
topLayout->addWidget(nameEdit); topLayout->addWidget(nameEdit);
topLayout->addWidget(descriptionLabel);
topLayout->addWidget(descriptionEdit);
QHBoxLayout *btmLayout = new QHBoxLayout(); QHBoxLayout *btmLayout = new QHBoxLayout();
btmLayout->addStretch(); btmLayout->addStretch();
@ -65,8 +58,3 @@ QString VDirInfoDialog::getNameInput() const
{ {
return nameEdit->text(); return nameEdit->text();
} }
QString VDirInfoDialog::getDescriptionInput() const
{
return descriptionEdit->text();
}

View File

@ -13,9 +13,8 @@ class VDirInfoDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
VDirInfoDialog(const QString &title, const QString &info, const QString &defaultName, VDirInfoDialog(const QString &title, const QString &info, const QString &defaultName,
const QString &defaultDescription, QWidget *parent = 0); QWidget *parent = 0);
QString getNameInput() const; QString getNameInput() const;
QString getDescriptionInput() const;
private slots: private slots:
void enableOkButton(); void enableOkButton();
@ -26,13 +25,11 @@ private:
QLabel *infoLabel; QLabel *infoLabel;
QLabel *nameLabel; QLabel *nameLabel;
QLineEdit *nameEdit; QLineEdit *nameEdit;
QLineEdit *descriptionEdit;
QPushButton *okBtn; QPushButton *okBtn;
QPushButton *cancelBtn; QPushButton *cancelBtn;
QString title; QString title;
QString info; QString info;
QString defaultName; QString defaultName;
QString defaultDescription;
}; };
#endif // VDIRINFODIALOG_H #endif // VDIRINFODIALOG_H

View File

@ -2,10 +2,8 @@
#include "vnewdirdialog.h" #include "vnewdirdialog.h"
VNewDirDialog::VNewDirDialog(const QString &title, const QString &name, const QString &defaultName, VNewDirDialog::VNewDirDialog(const QString &title, const QString &name, const QString &defaultName,
const QString &description, const QString &defaultDescription,
QWidget *parent) QWidget *parent)
: QDialog(parent), title(title), name(name), defaultName(defaultName), : QDialog(parent), title(title), name(name), defaultName(defaultName)
description(description), defaultDescription(defaultDescription)
{ {
setupUI(); setupUI();
@ -21,10 +19,6 @@ void VNewDirDialog::setupUI()
nameEdit->selectAll(); nameEdit->selectAll();
nameLabel->setBuddy(nameEdit); nameLabel->setBuddy(nameEdit);
descriptionLabel = new QLabel(description);
descriptionEdit = new QLineEdit(defaultDescription);
descriptionLabel->setBuddy(descriptionEdit);
okBtn = new QPushButton(tr("&OK")); okBtn = new QPushButton(tr("&OK"));
okBtn->setDefault(true); okBtn->setDefault(true);
cancelBtn = new QPushButton(tr("&Cancel")); cancelBtn = new QPushButton(tr("&Cancel"));
@ -32,8 +26,6 @@ void VNewDirDialog::setupUI()
QVBoxLayout *topLayout = new QVBoxLayout(); QVBoxLayout *topLayout = new QVBoxLayout();
topLayout->addWidget(nameLabel); topLayout->addWidget(nameLabel);
topLayout->addWidget(nameEdit); topLayout->addWidget(nameEdit);
topLayout->addWidget(descriptionLabel);
topLayout->addWidget(descriptionEdit);
QHBoxLayout *btmLayout = new QHBoxLayout(); QHBoxLayout *btmLayout = new QHBoxLayout();
btmLayout->addStretch(); btmLayout->addStretch();
@ -57,8 +49,3 @@ QString VNewDirDialog::getNameInput() const
{ {
return nameEdit->text(); return nameEdit->text();
} }
QString VNewDirDialog::getDescriptionInput() const
{
return descriptionEdit->text();
}

View File

@ -12,10 +12,9 @@ class VNewDirDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
VNewDirDialog(const QString &title, const QString &name, const QString &defaultName, VNewDirDialog(const QString &title, const QString &name,
const QString &description, const QString &defaultDescription, QWidget *parent = 0); const QString &defaultName, QWidget *parent = 0);
QString getNameInput() const; QString getNameInput() const;
QString getDescriptionInput() const;
private slots: private slots:
void enableOkButton(const QString &editText); void enableOkButton(const QString &editText);
@ -24,17 +23,13 @@ private:
void setupUI(); void setupUI();
QLabel *nameLabel; QLabel *nameLabel;
QLabel *descriptionLabel;
QLineEdit *nameEdit; QLineEdit *nameEdit;
QLineEdit *descriptionEdit;
QPushButton *okBtn; QPushButton *okBtn;
QPushButton *cancelBtn; QPushButton *cancelBtn;
QString title; QString title;
QString name; QString name;
QString defaultName; QString defaultName;
QString description;
QString defaultDescription;
}; };
#endif // VNEWDIRDIALOG_H #endif // VNEWDIRDIALOG_H

View File

@ -2,10 +2,8 @@
#include "vnewfiledialog.h" #include "vnewfiledialog.h"
VNewFileDialog::VNewFileDialog(const QString &title, const QString &name, const QString &defaultName, VNewFileDialog::VNewFileDialog(const QString &title, const QString &name, const QString &defaultName,
const QString &description, const QString &defaultDescription,
QWidget *parent) QWidget *parent)
: QDialog(parent), title(title), name(name), defaultName(defaultName), : QDialog(parent), title(title), name(name), defaultName(defaultName)
description(description), defaultDescription(defaultDescription)
{ {
setupUI(); setupUI();
@ -21,10 +19,6 @@ void VNewFileDialog::setupUI()
nameEdit->selectAll(); nameEdit->selectAll();
nameLabel->setBuddy(nameEdit); nameLabel->setBuddy(nameEdit);
descriptionLabel = new QLabel(description);
descriptionEdit = new QLineEdit(defaultDescription);
descriptionLabel->setBuddy(descriptionEdit);
okBtn = new QPushButton(tr("&OK")); okBtn = new QPushButton(tr("&OK"));
okBtn->setDefault(true); okBtn->setDefault(true);
cancelBtn = new QPushButton(tr("&Cancel")); cancelBtn = new QPushButton(tr("&Cancel"));
@ -32,8 +26,6 @@ void VNewFileDialog::setupUI()
QVBoxLayout *topLayout = new QVBoxLayout(); QVBoxLayout *topLayout = new QVBoxLayout();
topLayout->addWidget(nameLabel); topLayout->addWidget(nameLabel);
topLayout->addWidget(nameEdit); topLayout->addWidget(nameEdit);
topLayout->addWidget(descriptionLabel);
topLayout->addWidget(descriptionEdit);
QHBoxLayout *btmLayout = new QHBoxLayout(); QHBoxLayout *btmLayout = new QHBoxLayout();
btmLayout->addStretch(); btmLayout->addStretch();
@ -57,8 +49,3 @@ QString VNewFileDialog::getNameInput() const
{ {
return nameEdit->text(); return nameEdit->text();
} }
QString VNewFileDialog::getDescriptionInput() const
{
return descriptionEdit->text();
}

View File

@ -13,9 +13,8 @@ class VNewFileDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
VNewFileDialog(const QString &title, const QString &name, const QString &defaultName, VNewFileDialog(const QString &title, const QString &name, const QString &defaultName,
const QString &description, const QString &defaultDescription, QWidget *parent = 0); QWidget *parent = 0);
QString getNameInput() const; QString getNameInput() const;
QString getDescriptionInput() const;
private slots: private slots:
void enableOkButton(const QString &editText); void enableOkButton(const QString &editText);
@ -24,17 +23,13 @@ private:
void setupUI(); void setupUI();
QLabel *nameLabel; QLabel *nameLabel;
QLabel *descriptionLabel;
QLineEdit *nameEdit; QLineEdit *nameEdit;
QLineEdit *descriptionEdit;
QPushButton *okBtn; QPushButton *okBtn;
QPushButton *cancelBtn; QPushButton *cancelBtn;
QString title; QString title;
QString name; QString name;
QString defaultName; QString defaultName;
QString description;
QString defaultDescription;
}; };
#endif // VNEWFILEDIALOG_H #endif // VNEWFILEDIALOG_H

View File

@ -3,9 +3,10 @@
#include "dialog/vnewdirdialog.h" #include "dialog/vnewdirdialog.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "dialog/vdirinfodialog.h" #include "dialog/vdirinfodialog.h"
#include "vnote.h"
VDirectoryTree::VDirectoryTree(QWidget *parent) VDirectoryTree::VDirectoryTree(VNote *vnote, QWidget *parent)
: QTreeWidget(parent) : QTreeWidget(parent), vnote(vnote)
{ {
setColumnCount(1); setColumnCount(1);
setHeaderHidden(true); setHeaderHidden(true);
@ -43,19 +44,26 @@ void VDirectoryTree::initActions()
this, &VDirectoryTree::deleteDirectory); this, &VDirectoryTree::deleteDirectory);
} }
void VDirectoryTree::setTreePath(const QString& path) void VDirectoryTree::setNotebook(const QString& notebookName)
{ {
if (path == treePath) { if (notebook == notebookName) {
return; return;
} }
treePath = path; notebook = notebookName;
if (path.isEmpty()) { treePath = "";
if (notebook.isEmpty()) {
clear(); clear();
return; return;
} }
const QVector<VNotebook> &notebooks = vnote->getNotebooks();
qDebug() << "set directory tree path:" << path; for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
treePath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!treePath.isEmpty());
updateDirectoryTree(); updateDirectoryTree();
if (topLevelItemCount() > 0) { if (topLevelItemCount() > 0) {
@ -76,21 +84,15 @@ void VDirectoryTree::updateDirectoryTree()
for (int i = 0; i < nrTopLevelItems; ++i) { for (int i = 0; i < nrTopLevelItems; ++i) {
QTreeWidgetItem *item = topLevelItem(i); QTreeWidgetItem *item = topLevelItem(i);
Q_ASSERT(item); Q_ASSERT(item);
updateDirectoryTreeOne(*item, 1); QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty());
updateDirectoryTreeOne(*item, itemJson["name"].toString(), 1);
} }
} }
// QJsonObject stored in each item's data[UserRole]: void VDirectoryTree::fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson)
// 1. @item's related item in its parent's [sub_directories] section;
// 2. "relative_path": the path where this item exists, relative to the treePath.
void VDirectoryTree::fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson, const QString &relativePath)
{ {
item.setText(0, itemJson["name"].toString()); item.setText(0, itemJson["name"].toString());
QString description = itemJson["description"].toString();
if (!description.isEmpty()) {
item.setToolTip(0, description);
}
itemJson["relative_path"] = relativePath;
item.setData(0, Qt::UserRole, itemJson); item.setData(0, Qt::UserRole, itemJson);
} }
@ -98,30 +100,21 @@ QTreeWidgetItem* VDirectoryTree::insertDirectoryTreeItem(QTreeWidgetItem *parent
const QJsonObject &newItem) const QJsonObject &newItem)
{ {
QTreeWidgetItem *item; QTreeWidgetItem *item;
QString relativePath;
if (parent) { if (parent) {
if (preceding) { if (preceding) {
item = new QTreeWidgetItem(parent, preceding); item = new QTreeWidgetItem(parent, preceding);
} else { } else {
item = new QTreeWidgetItem(parent); item = new QTreeWidgetItem(parent);
} }
QJsonObject parentJson = parent->data(0, Qt::UserRole).toJsonObject();
Q_ASSERT(!parentJson.isEmpty());
QString parentRelativePath = parentJson["relative_path"].toString();
QString parentName = parentJson["name"].toString();
relativePath = QDir(parentRelativePath).filePath(parentName);
} else { } else {
if (preceding) { if (preceding) {
item = new QTreeWidgetItem(this, preceding); item = new QTreeWidgetItem(this, preceding);
} else { } else {
item = new QTreeWidgetItem(this); item = new QTreeWidgetItem(this);
} }
relativePath = "";
} }
fillDirectoryTreeItem(*item, newItem, relativePath); fillDirectoryTreeItem(*item, newItem);
qDebug() << "insert new Item name:" << newItem["name"].toString()
<< "relative_path:" << relativePath;
return item; return item;
} }
@ -169,15 +162,17 @@ void VDirectoryTree::updateDirectoryTreeTopLevel()
qDebug() << "updated" << dirJson.size() << "top-level items"; qDebug() << "updated" << dirJson.size() << "top-level items";
} }
void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem &parent, int depth) void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem &parent, const QString &relativePath,
int depth)
{ {
Q_ASSERT(parent.childCount() == 0); Q_ASSERT(parent.childCount() == 0);
// Going deep enough // Going deep enough
if (depth <= 0) { if (depth <= 0) {
return; return;
} }
QJsonObject parentJson = parent.data(0, Qt::UserRole).toJsonObject();
QString relativePath = QDir(parentJson["relative_path"].toString()).filePath(parentJson["name"].toString()); qDebug() << "update directory" << relativePath;
QString path(QDir::cleanPath(treePath + QDir::separator() + relativePath)); QString path(QDir::cleanPath(treePath + QDir::separator() + relativePath));
if (!validatePath(path)) { if (!validatePath(path)) {
qDebug() << "invalide notebook directory:" << path; qDebug() << "invalide notebook directory:" << path;
@ -209,24 +204,41 @@ void VDirectoryTree::updateDirectoryTreeOne(QTreeWidgetItem &parent, int depth)
preItem = treeItem; preItem = treeItem;
// Update its sub-directory recursively // Update its sub-directory recursively
updateDirectoryTreeOne(*treeItem, depth - 1); updateDirectoryTreeOne(*treeItem, QDir::cleanPath(QDir(relativePath).filePath(dirItem["name"].toString())), depth - 1);
} }
} }
QString VDirectoryTree::calculateItemRelativePath(QTreeWidgetItem *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) void VDirectoryTree::updateItemSubtree(QTreeWidgetItem *item)
{ {
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject(); QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty()); Q_ASSERT(!itemJson.isEmpty());
QString relativePath = calculateItemRelativePath(item);
int nrChild = item->childCount(); int nrChild = item->childCount();
if (nrChild == 0) { if (nrChild == 0) {
updateDirectoryTreeOne(*item, 2); updateDirectoryTreeOne(*item, relativePath, 2);
} else { } else {
for (int i = 0; i < nrChild; ++i) { for (int i = 0; i < nrChild; ++i) {
QTreeWidgetItem *childItem = item->child(i); QTreeWidgetItem *childItem = item->child(i);
if (childItem->childCount() > 0) { if (childItem->childCount() > 0) {
continue; continue;
} }
updateDirectoryTreeOne(*childItem, 1); QJsonObject childJson = childItem->data(0, Qt::UserRole).toJsonObject();
Q_ASSERT(!childJson.isEmpty());
updateDirectoryTreeOne(*childItem,
QDir::cleanPath(QDir(relativePath).filePath(childJson["name"].toString())), 1);
} }
} }
} }
@ -264,20 +276,17 @@ void VDirectoryTree::newSiblingDirectory()
QString text("&Directory name:"); QString text("&Directory name:");
QString defaultText("new_directory"); QString defaultText("new_directory");
QString defaultDescription("");
do { do {
VNewDirDialog dialog(QString("Create a new directory under %1").arg(parentItemName), text, VNewDirDialog dialog(QString("Create a new directory under %1").arg(parentItemName), text,
defaultText, tr("&Description:"), defaultDescription, this); defaultText, this);
if (dialog.exec() == QDialog::Accepted) { if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput(); QString name = dialog.getNameInput();
QString description = dialog.getDescriptionInput();
if (isConflictNameWithChildren(parentItem, name)) { if (isConflictNameWithChildren(parentItem, name)) {
text = "Name already exists.\nPlease choose another name:"; text = "Name already exists.\nPlease choose another name:";
defaultText = name; defaultText = name;
defaultDescription = description;
continue; continue;
} }
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(parentItem, name, description); QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(parentItem, name);
if (newItem) { if (newItem) {
this->setCurrentItem(newItem); this->setCurrentItem(newItem);
} }
@ -297,20 +306,18 @@ void VDirectoryTree::newSubDirectory()
QString text("&Directory name:"); QString text("&Directory name:");
QString defaultText("new_directory"); QString defaultText("new_directory");
QString defaultDescription("");
do { do {
VNewDirDialog dialog(QString("Create a new directory under %1").arg(curItemName), text, VNewDirDialog dialog(QString("Create a new directory under %1").arg(curItemName), text,
defaultText, tr("&Description:"), defaultDescription, this); defaultText, this);
if (dialog.exec() == QDialog::Accepted) { if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput(); QString name = dialog.getNameInput();
QString description = dialog.getDescriptionInput();
if (isConflictNameWithChildren(curItem, name)) { if (isConflictNameWithChildren(curItem, name)) {
text = "Name already exists.\nPlease choose another name:"; text = "Name already exists.\nPlease choose another name:";
defaultText = name; defaultText = name;
defaultDescription = description;
continue; continue;
} }
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(curItem, name, description); QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(curItem, name);
if (newItem) { if (newItem) {
this->setCurrentItem(newItem); this->setCurrentItem(newItem);
} }
@ -323,20 +330,18 @@ void VDirectoryTree::newRootDirectory()
{ {
QString text("&Directory name:"); QString text("&Directory name:");
QString defaultText("new_directory"); QString defaultText("new_directory");
QString defaultDescription("");
do { do {
VNewDirDialog dialog(tr("Create a new root directory"), text, VNewDirDialog dialog(tr("Create a new root directory"), text,
defaultText, tr("&Description:"), defaultDescription, this); defaultText, this);
if (dialog.exec() == QDialog::Accepted) { if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput(); QString name = dialog.getNameInput();
QString description = dialog.getDescriptionInput();
if (isConflictNameWithChildren(NULL, name)) { if (isConflictNameWithChildren(NULL, name)) {
text = "Name already exists.\nPlease choose another name:"; text = "Name already exists.\nPlease choose another name:";
defaultText = name; defaultText = name;
defaultDescription = description;
continue; continue;
} }
QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(NULL, name, description); QTreeWidgetItem *newItem = createDirectoryAndUpdateTree(NULL, name);
if (newItem) { if (newItem) {
this->setCurrentItem(newItem); this->setCurrentItem(newItem);
} }
@ -364,15 +369,10 @@ void VDirectoryTree::deleteDirectory()
} }
QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *parent, QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *parent,
const QString &name, const QString &description) const QString &name)
{ {
QString relativePath(""); QString relativePath = calculateItemRelativePath(parent);
QJsonObject parentJson; QString path = QDir::cleanPath(QDir(treePath).filePath(relativePath));
if (parent) {
parentJson = parent->data(0, Qt::UserRole).toJsonObject();
relativePath = QDir(parentJson["relative_path"].toString()).filePath(parentJson["name"].toString());
}
QString path = QDir(treePath).filePath(relativePath);
QDir dir(path); QDir dir(path);
if (!dir.mkdir(name)) { if (!dir.mkdir(name)) {
qWarning() << "error: fail to create directory" << name << "under" << path; qWarning() << "error: fail to create directory" << name << "under" << path;
@ -388,7 +388,7 @@ QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *p
configJson["sub_directories"] = QJsonArray(); configJson["sub_directories"] = QJsonArray();
configJson["files"] = QJsonArray(); configJson["files"] = QJsonArray();
if (!VConfigManager::writeDirectoryConfig(QDir(path).filePath(name), configJson)) { if (!VConfigManager::writeDirectoryConfig(QDir::cleanPath(QDir(path).filePath(name)), configJson)) {
return NULL; return NULL;
} }
@ -397,12 +397,11 @@ QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *p
Q_ASSERT(!configJson.isEmpty()); Q_ASSERT(!configJson.isEmpty());
QJsonObject itemJson; QJsonObject itemJson;
itemJson["name"] = name; itemJson["name"] = name;
itemJson["description"] = description;
QJsonArray subDirArray = configJson["sub_directories"].toArray(); QJsonArray subDirArray = configJson["sub_directories"].toArray();
subDirArray.append(itemJson); subDirArray.append(itemJson);
configJson["sub_directories"] = subDirArray; configJson["sub_directories"] = subDirArray;
if (!VConfigManager::writeDirectoryConfig(path, configJson)) { if (!VConfigManager::writeDirectoryConfig(path, configJson)) {
VConfigManager::deleteDirectoryConfig(QDir(path).filePath(name)); VConfigManager::deleteDirectoryConfig(QDir::cleanPath(QDir(path).filePath(name)));
dir.rmdir(name); dir.rmdir(name);
return NULL; return NULL;
} }
@ -412,12 +411,15 @@ QTreeWidgetItem* VDirectoryTree::createDirectoryAndUpdateTree(QTreeWidgetItem *p
void VDirectoryTree::deleteDirectoryAndUpdateTree(QTreeWidgetItem *item) void VDirectoryTree::deleteDirectoryAndUpdateTree(QTreeWidgetItem *item)
{ {
if (!item) {
return;
}
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject(); QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
QString itemName = itemJson["name"].toString(); QString itemName = itemJson["name"].toString();
QString relativePath = itemJson["relative_path"].toString(); QString parentRelativePath = calculateItemRelativePath(item->parent());
// Update parent's config file to exclude this directory // Update parent's config file to exclude this directory
QString path = QDir(treePath).filePath(relativePath); QString path = QDir::cleanPath(QDir(treePath).filePath(parentRelativePath));
QJsonObject configJson = VConfigManager::readDirectoryConfig(path); QJsonObject configJson = VConfigManager::readDirectoryConfig(path);
Q_ASSERT(!configJson.isEmpty()); Q_ASSERT(!configJson.isEmpty());
QJsonArray subDirArray = configJson["sub_directories"].toArray(); QJsonArray subDirArray = configJson["sub_directories"].toArray();
@ -441,7 +443,7 @@ void VDirectoryTree::deleteDirectoryAndUpdateTree(QTreeWidgetItem *item)
} }
// Delete the entire directory // Delete the entire directory
QString dirName = QDir(path).filePath(itemName); QString dirName = QDir::cleanPath(QDir(path).filePath(itemName));
QDir dir(dirName); QDir dir(dirName);
if (!dir.removeRecursively()) { if (!dir.removeRecursively()) {
qWarning() << "error: fail to delete" << dirName << "recursively"; qWarning() << "error: fail to delete" << dirName << "recursively";
@ -485,8 +487,8 @@ void VDirectoryTree::currentDirectoryItemChanged(QTreeWidgetItem *currentItem)
} }
QJsonObject itemJson = currentItem->data(0, Qt::UserRole).toJsonObject(); QJsonObject itemJson = currentItem->data(0, Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty()); Q_ASSERT(!itemJson.isEmpty());
itemJson["root_path"] = treePath; itemJson["notebook"] = notebook;
qDebug() << "click dir:" << itemJson; itemJson["relative_path"] = calculateItemRelativePath(currentItem);
emit currentDirectoryChanged(itemJson); emit currentDirectoryChanged(itemJson);
} }
@ -498,35 +500,29 @@ void VDirectoryTree::editDirectoryInfo()
} }
QJsonObject curItemJson = curItem->data(0, Qt::UserRole).toJsonObject(); QJsonObject curItemJson = curItem->data(0, Qt::UserRole).toJsonObject();
QString curItemName = curItemJson["name"].toString(); QString curItemName = curItemJson["name"].toString();
QString curDescription = curItemJson["description"].toString();
QString info; QString info;
QString defaultName = curItemName; QString defaultName = curItemName;
QString defaultDescription = curDescription;
do { do {
VDirInfoDialog dialog(tr("Directory Information"), info, defaultName, VDirInfoDialog dialog(tr("Directory Information"), info, defaultName, this);
defaultDescription, this);
if (dialog.exec() == QDialog::Accepted) { if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput(); QString name = dialog.getNameInput();
QString description = dialog.getDescriptionInput(); if (name == curItemName) {
if (name == curItemName && description == curDescription) {
return; return;
} }
if (isConflictNameWithChildren(curItem->parent(), name)) { if (isConflictNameWithChildren(curItem->parent(), name)) {
info = "Name already exists.\nPlease choose another name:"; info = "Name already exists.\nPlease choose another name:";
defaultName = name; defaultName = name;
defaultDescription = description;
continue; continue;
} }
setDirectoryInfo(curItem, name, description); renameDirectory(curItem, name);
} }
break; break;
} while (true); } while (true);
} }
void VDirectoryTree::setDirectoryInfo(QTreeWidgetItem *item, const QString &newName, void VDirectoryTree::renameDirectory(QTreeWidgetItem *item, const QString &newName)
const QString &newDescription)
{ {
if (!item) { if (!item) {
return; return;
@ -534,14 +530,10 @@ void VDirectoryTree::setDirectoryInfo(QTreeWidgetItem *item, const QString &newN
QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject(); QJsonObject itemJson = item->data(0, Qt::UserRole).toJsonObject();
QString name = itemJson["name"].toString(); QString name = itemJson["name"].toString();
QString relativePath("");
QJsonObject parentJson;
QTreeWidgetItem *parent = item->parent(); QTreeWidgetItem *parent = item->parent();
if (parent) { QString parentRelativePath = calculateItemRelativePath(parent);
parentJson = parent->data(0, Qt::UserRole).toJsonObject();
relativePath = QDir(parentJson["relative_path"].toString()).filePath(parentJson["name"].toString()); QString path = QDir::cleanPath(QDir(treePath).filePath(parentRelativePath));
}
QString path = QDir(treePath).filePath(relativePath);
QDir dir(path); QDir dir(path);
if (!dir.rename(name, newName)) { if (!dir.rename(name, newName)) {
@ -562,7 +554,6 @@ void VDirectoryTree::setDirectoryInfo(QTreeWidgetItem *item, const QString &newN
QJsonObject tmp = subDirArray[index].toObject(); QJsonObject tmp = subDirArray[index].toObject();
if (tmp["name"].toString() == name) { if (tmp["name"].toString() == name) {
tmp["name"] = newName; tmp["name"] = newName;
tmp["description"] = newDescription;
subDirArray[index] = tmp; subDirArray[index] = tmp;
break; break;
} }
@ -576,16 +567,30 @@ void VDirectoryTree::setDirectoryInfo(QTreeWidgetItem *item, const QString &newN
// Update item // Update item
itemJson["name"] = newName; itemJson["name"] = newName;
itemJson["description"] = newDescription;
item->setData(0, Qt::UserRole, itemJson); item->setData(0, Qt::UserRole, itemJson);
item->setText(0, newName); item->setText(0, newName);
item->setToolTip(0, newDescription);
// Reconstruct every child QString oldPath = QDir::cleanPath(QDir(parentRelativePath).filePath(name));
for (int i = 0; i < item->childCount(); ++i) { QString newPath = QDir::cleanPath(QDir(parentRelativePath).filePath(newName));
QTreeWidgetItem *tmp = item->child(i); qDebug() << "directory renamed" << oldPath << "to" << newPath;
item->removeChild(tmp); emit directoryRenamed(notebook, oldPath, newPath);
delete tmp; }
void VDirectoryTree::handleNotebookRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName)
{
if (oldName == notebook) {
// Update treePath (though treePath actually will not be changed)
notebook = newName;
treePath.clear();
const QVector<VNotebook> &notebooks = vnote->getNotebooks();
for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
treePath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!treePath.isEmpty());
qDebug() << "directoryTree update notebook" << oldName << "to" << newName << "path" << treePath;
} }
updateDirectoryTreeOne(*item, 2);
} }

View File

@ -3,21 +3,28 @@
#include <QTreeWidget> #include <QTreeWidget>
#include <QJsonObject> #include <QJsonObject>
#include "vnotebook.h"
class VNote;
class VDirectoryTree : public QTreeWidget class VDirectoryTree : public QTreeWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VDirectoryTree(QWidget *parent = 0); explicit VDirectoryTree(VNote *vnote, QWidget *parent = 0);
signals: signals:
void currentDirectoryChanged(QJsonObject itemJson); void currentDirectoryChanged(QJsonObject itemJson);
void directoryRenamed(const QString &notebook, const QString &oldRelativePath,
const QString &newRelativePath);
public slots: public slots:
void setTreePath(const QString& path); void setNotebook(const QString &notebookName);
void newRootDirectory(); void newRootDirectory();
void deleteDirectory(); void deleteDirectory();
void editDirectoryInfo(); void editDirectoryInfo();
void handleNotebookRenamed(const QVector<VNotebook> &notebooks, const QString &oldName,
const QString &newName);
private slots: private slots:
// Read config file and pdate the subtree of @item in the directory tree. // Read config file and pdate the subtree of @item in the directory tree.
@ -31,30 +38,33 @@ private slots:
void currentDirectoryItemChanged(QTreeWidgetItem *currentItem); void currentDirectoryItemChanged(QTreeWidgetItem *currentItem);
private: private:
QString calculateItemRelativePath(QTreeWidgetItem *item);
// Clean and pdate the TreeWidget according to treePath // Clean and pdate the TreeWidget according to treePath
void updateDirectoryTree(); void updateDirectoryTree();
// Update the top-level items of the directory tree. Will not clean the tree at first. // Update the top-level items of the directory tree. Will not clean the tree at first.
void updateDirectoryTreeTopLevel(); void updateDirectoryTreeTopLevel();
// Update one directory, going into @depth levels. Not cleaning the tree item at first,
// so you must ensure @parent has no child before calling this function. // @relativePath is the relative path of the direcotry we are updating
void updateDirectoryTreeOne(QTreeWidgetItem &parent, int depth); void updateDirectoryTreeOne(QTreeWidgetItem &parent, const QString &relativePath, int depth);
// Validate if a directory is valid // Validate if a directory is valid
bool validatePath(const QString &path); bool validatePath(const QString &path);
// Fill the QTreeWidgetItem according to its QJsonObject.
// @relative_path is the path related to treePath. void fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson);
void fillDirectoryTreeItem(QTreeWidgetItem &item, QJsonObject itemJson, const QString &relativePath);
void initActions(); void initActions();
QTreeWidgetItem* createDirectoryAndUpdateTree(QTreeWidgetItem *parent, const QString &name, QTreeWidgetItem* createDirectoryAndUpdateTree(QTreeWidgetItem *parent, const QString &name);
const QString &description);
void deleteDirectoryAndUpdateTree(QTreeWidgetItem *item); void deleteDirectoryAndUpdateTree(QTreeWidgetItem *item);
// If @name conflict with the children's names of @parent. // If @name conflict with the children's names of @parent.
bool isConflictNameWithChildren(const QTreeWidgetItem *parent, const QString &name); bool isConflictNameWithChildren(const QTreeWidgetItem *parent, const QString &name);
QTreeWidgetItem* insertDirectoryTreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, QTreeWidgetItem* insertDirectoryTreeItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding,
const QJsonObject &newItem); const QJsonObject &newItem);
void removeDirectoryTreeItem(QTreeWidgetItem *item); void removeDirectoryTreeItem(QTreeWidgetItem *item);
void setDirectoryInfo(QTreeWidgetItem *item, const QString &newName, const QString &newDescription); void renameDirectory(QTreeWidgetItem *item, const QString &newName);
// The path of the directory tree root VNote *vnote;
QString notebook;
// Used for cache
QString treePath; QString treePath;
// Actions // Actions

View File

@ -2,6 +2,7 @@
#include <QTextBrowser> #include <QTextBrowser>
#include <QWebChannel> #include <QWebChannel>
#include <QWebEngineView> #include <QWebEngineView>
#include <QFileInfo>
#include "veditor.h" #include "veditor.h"
#include "vedit.h" #include "vedit.h"
#include "vdocument.h" #include "vdocument.h"
@ -11,16 +12,20 @@
#include "hgmarkdownhighlighter.h" #include "hgmarkdownhighlighter.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "vmarkdownconverter.h" #include "vmarkdownconverter.h"
#include "vnotebook.h"
extern VConfigManager vconfig; extern VConfigManager vconfig;
VEditor::VEditor(const QString &path, const QString &name, bool modifiable, VEditor::VEditor(const QString &path, bool modifiable, QWidget *parent)
QWidget *parent)
: QStackedWidget(parent), mdConverterType(vconfig.getMdConverterType()) : QStackedWidget(parent), mdConverterType(vconfig.getMdConverterType())
{ {
DocType docType = isMarkdown(name) ? DocType::Markdown : DocType::Html; DocType docType = isMarkdown(path) ? DocType::Markdown : DocType::Html;
QString fileText = VUtils::readFileFromDisk(QDir(path).filePath(name)); QString basePath = QFileInfo(path).path();
noteFile = new VNoteFile(path, name, fileText, docType, modifiable); QString fileName = QFileInfo(path).fileName();
qDebug() << "VEditor basePath" << basePath << "file" << fileName;
QString fileText = VUtils::readFileFromDisk(path);
noteFile = new VNoteFile(basePath, fileName, fileText,
docType, modifiable);
isEditMode = false; isEditMode = false;
@ -105,7 +110,7 @@ void VEditor::previewByConverter()
QString toc = mdConverter.generateToc(content, vconfig.getMarkdownExtensions()); QString toc = mdConverter.generateToc(content, vconfig.getMarkdownExtensions());
html.replace(tocExp, toc); html.replace(tocExp, toc);
QString completeHtml = VNote::preTemplateHtml + html + VNote::postTemplateHtml; QString completeHtml = VNote::preTemplateHtml + html + VNote::postTemplateHtml;
webPreviewer->setHtml(completeHtml, QUrl::fromLocalFile(noteFile->path + QDir::separator())); webPreviewer->setHtml(completeHtml, QUrl::fromLocalFile(noteFile->basePath + QDir::separator()));
} }
void VEditor::showFileEditMode() void VEditor::showFileEditMode()
@ -171,7 +176,7 @@ bool VEditor::saveFile()
return true; return true;
} }
textEditor->saveFile(); textEditor->saveFile();
bool ret = VUtils::writeFileToDisk(QDir(noteFile->path).filePath(noteFile->name), bool ret = VUtils::writeFileToDisk(QDir(noteFile->basePath).filePath(noteFile->fileName),
noteFile->content); noteFile->content);
if (!ret) { if (!ret) {
QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"), QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
@ -196,7 +201,8 @@ void VEditor::setupMarkdownPreview()
QWebChannel *channel = new QWebChannel(this); QWebChannel *channel = new QWebChannel(this);
channel->registerObject(QStringLiteral("content"), &document); channel->registerObject(QStringLiteral("content"), &document);
page->setWebChannel(channel); page->setWebChannel(channel);
webPreviewer->setHtml(VNote::templateHtml, QUrl::fromLocalFile(noteFile->path + QDir::separator())); webPreviewer->setHtml(VNote::templateHtml,
QUrl::fromLocalFile(noteFile->basePath + QDir::separator()));
} }
addWidget(webPreviewer); addWidget(webPreviewer);

View File

@ -12,12 +12,12 @@
class QTextBrowser; class QTextBrowser;
class VEdit; class VEdit;
class QWebEngineView; class QWebEngineView;
class VNote;
class VEditor : public QStackedWidget class VEditor : public QStackedWidget
{ {
public: public:
VEditor(const QString &path, const QString &name, bool modifiable, VEditor(const QString &path, bool modifiable, QWidget *parent = 0);
QWidget *parent = 0);
~VEditor(); ~VEditor();
bool requestClose(); bool requestClose();
// Enter edit mode // Enter edit mode

View File

@ -5,8 +5,8 @@
#include "dialog/vnewfiledialog.h" #include "dialog/vnewfiledialog.h"
#include "vnote.h" #include "vnote.h"
VFileList::VFileList(QWidget *parent) VFileList::VFileList(VNote *vnote, QWidget *parent)
: QListWidget(parent) : QListWidget(parent), vnote(vnote)
{ {
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
initActions(); initActions();
@ -37,17 +37,24 @@ void VFileList::setDirectory(QJsonObject dirJson)
return; return;
} }
directoryName = dirJson["name"].toString(); notebook = dirJson["notebook"].toString();
rootPath = dirJson["root_path"].toString(); relativePath = dirJson["relative_path"].toString();
relativePath = QDir(dirJson["relative_path"].toString()).filePath(directoryName); rootPath = "";
qDebug() << "FileList update:" << rootPath << relativePath << directoryName; const QVector<VNotebook> &notebooks = vnote->getNotebooks();
for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
rootPath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!rootPath.isEmpty());
updateFileList(); updateFileList();
} }
void VFileList::clearDirectoryInfo() void VFileList::clearDirectoryInfo()
{ {
directoryName = rootPath = relativePath = ""; notebook = relativePath = rootPath = "";
clear(); clear();
} }
@ -89,9 +96,6 @@ QListWidgetItem* VFileList::insertFileListItem(QJsonObject fileJson, bool atFron
{ {
Q_ASSERT(!fileJson.isEmpty()); Q_ASSERT(!fileJson.isEmpty());
QListWidgetItem *item = new QListWidgetItem(fileJson["name"].toString()); QListWidgetItem *item = new QListWidgetItem(fileJson["name"].toString());
if (!fileJson["description"].toString().isEmpty()) {
item->setToolTip(fileJson["description"].toString());
}
item->setData(Qt::UserRole, fileJson); item->setData(Qt::UserRole, fileJson);
if (atFront) { if (atFront) {
@ -118,20 +122,17 @@ void VFileList::newFile()
{ {
QString text("&Note name:"); QString text("&Note name:");
QString defaultText("new_note"); QString defaultText("new_note");
QString defaultDescription("");
do { do {
VNewFileDialog dialog(QString("Create a new note under %1").arg(directoryName), text, VNewFileDialog dialog(QString("Create a new note under %1").arg(getDirectoryName()), text,
defaultText, tr("&Description:"), defaultDescription, this); defaultText, this);
if (dialog.exec() == QDialog::Accepted) { if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput(); QString name = dialog.getNameInput();
QString description = dialog.getDescriptionInput();
if (isConflictNameWithExisting(name)) { if (isConflictNameWithExisting(name)) {
text = "Name already exists.\nPlease choose another name:"; text = "Name already exists.\nPlease choose another name:";
defaultText = name; defaultText = name;
defaultDescription = description;
continue; continue;
} }
QListWidgetItem *newItem = createFileAndUpdateList(name, description); QListWidgetItem *newItem = createFileAndUpdateList(name);
if (newItem) { if (newItem) {
setCurrentItem(newItem); setCurrentItem(newItem);
// Qt seems not to update the QListWidget correctly. Manually force it to repaint. // Qt seems not to update the QListWidget correctly. Manually force it to repaint.
@ -140,7 +141,8 @@ void VFileList::newFile()
// Open this file in edit mode // Open this file in edit mode
QJsonObject itemJson = newItem->data(Qt::UserRole).toJsonObject(); QJsonObject itemJson = newItem->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty()); Q_ASSERT(!itemJson.isEmpty());
itemJson["path"] = QDir::cleanPath(QDir(rootPath).filePath(relativePath)); itemJson["notebook"] = notebook;
itemJson["relative_path"] = QDir::cleanPath(QDir(relativePath).filePath(name));
itemJson["mode"] = OpenFileMode::Edit; itemJson["mode"] = OpenFileMode::Edit;
emit fileCreated(itemJson); emit fileCreated(itemJson);
} }
@ -164,7 +166,8 @@ void VFileList::deleteFile()
msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok);
if (msgBox.exec() == QMessageBox::Ok) { if (msgBox.exec() == QMessageBox::Ok) {
// First close this file forcely // First close this file forcely
curItemJson["path"] = QDir::cleanPath(QDir(rootPath).filePath(relativePath)); curItemJson["notebook"] = notebook;
curItemJson["relative_path"] = QDir::cleanPath(QDir(relativePath).filePath(curItemName));
emit fileDeleted(curItemJson); emit fileDeleted(curItemJson);
deleteFileAndUpdateList(curItem); deleteFileAndUpdateList(curItem);
@ -176,7 +179,7 @@ void VFileList::contextMenuRequested(QPoint pos)
QListWidgetItem *item = itemAt(pos); QListWidgetItem *item = itemAt(pos);
QMenu menu(this); QMenu menu(this);
if (directoryName.isEmpty()) { if (notebook.isEmpty()) {
return; return;
} }
menu.addAction(newFileAct); menu.addAction(newFileAct);
@ -201,8 +204,7 @@ bool VFileList::isConflictNameWithExisting(const QString &name)
return false; return false;
} }
QListWidgetItem* VFileList::createFileAndUpdateList(const QString &name, QListWidgetItem* VFileList::createFileAndUpdateList(const QString &name)
const QString &description)
{ {
QString path = QDir(rootPath).filePath(relativePath); QString path = QDir(rootPath).filePath(relativePath);
QString filePath = QDir(path).filePath(name); QString filePath = QDir(path).filePath(name);
@ -224,7 +226,6 @@ QListWidgetItem* VFileList::createFileAndUpdateList(const QString &name,
Q_ASSERT(!dirJson.isEmpty()); Q_ASSERT(!dirJson.isEmpty());
QJsonObject fileJson; QJsonObject fileJson;
fileJson["name"] = name; fileJson["name"] = name;
fileJson["description"] = description;
QJsonArray fileArray = dirJson["files"].toArray(); QJsonArray fileArray = dirJson["files"].toArray();
fileArray.push_front(fileJson); fileArray.push_front(fileJson);
dirJson["files"] = fileArray; dirJson["files"] = fileArray;
@ -291,7 +292,8 @@ void VFileList::handleItemClicked(QListWidgetItem *currentItem)
update(); update();
QJsonObject itemJson = currentItem->data(Qt::UserRole).toJsonObject(); QJsonObject itemJson = currentItem->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty()); Q_ASSERT(!itemJson.isEmpty());
itemJson["path"] = QDir::cleanPath(QDir(rootPath).filePath(relativePath)); itemJson["notebook"] = notebook;
itemJson["relative_path"] = QDir::cleanPath(QDir(relativePath).filePath(itemJson["name"].toString()));
itemJson["mode"] = OpenFileMode::Read; itemJson["mode"] = OpenFileMode::Read;
emit fileClicked(itemJson); emit fileClicked(itemJson);
} }
@ -324,7 +326,6 @@ bool VFileList::importFile(const QString &name)
Q_ASSERT(!dirJson.isEmpty()); Q_ASSERT(!dirJson.isEmpty());
QJsonObject fileJson; QJsonObject fileJson;
fileJson["name"] = srcName; fileJson["name"] = srcName;
fileJson["description"] = "";
QJsonArray fileArray = dirJson["files"].toArray(); QJsonArray fileArray = dirJson["files"].toArray();
fileArray.push_front(fileJson); fileArray.push_front(fileJson);
dirJson["files"] = fileArray; dirJson["files"] = fileArray;
@ -337,3 +338,30 @@ bool VFileList::importFile(const QString &name)
return insertFileListItem(fileJson, true); return insertFileListItem(fileJson, true);
} }
void VFileList::handleNotebookRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName)
{
if (oldName == notebook) {
// Update treePath (though treePath actually will not be changed)
notebook = newName;
rootPath.clear();
const QVector<VNotebook> &notebooks = vnote->getNotebooks();
for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
rootPath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!rootPath.isEmpty());
}
}
void VFileList::handleDirectoryRenamed(const QString &notebook,
const QString &oldRelativePath, const QString &newRelativePath)
{
if (notebook == this->notebook
&& oldRelativePath == relativePath) {
relativePath = newRelativePath;
}
}

View File

@ -3,14 +3,18 @@
#include <QListWidget> #include <QListWidget>
#include <QJsonObject> #include <QJsonObject>
#include <QFileInfo>
#include <QDir>
#include "vnotebook.h"
class QAction; class QAction;
class VNote;
class VFileList : public QListWidget class VFileList : public QListWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VFileList(QWidget *parent = 0); explicit VFileList(VNote *vnote, QWidget *parent = 0);
bool importFile(const QString &name); bool importFile(const QString &name);
signals: signals:
@ -26,6 +30,10 @@ private slots:
public slots: public slots:
void setDirectory(QJsonObject dirJson); void setDirectory(QJsonObject dirJson);
void handleNotebookRenamed(const QVector<VNotebook> &notebooks, const QString &oldName,
const QString &newName);
void handleDirectoryRenamed(const QString &notebook, const QString &oldRelativePath,
const QString &newRelativePath);
private: private:
void updateFileList(); void updateFileList();
@ -33,18 +41,29 @@ private:
void removeFileListItem(QListWidgetItem *item); void removeFileListItem(QListWidgetItem *item);
void initActions(); void initActions();
bool isConflictNameWithExisting(const QString &name); bool isConflictNameWithExisting(const QString &name);
QListWidgetItem *createFileAndUpdateList(const QString &name, QListWidgetItem *createFileAndUpdateList(const QString &name);
const QString &description);
void deleteFileAndUpdateList(QListWidgetItem *item); void deleteFileAndUpdateList(QListWidgetItem *item);
void clearDirectoryInfo(); void clearDirectoryInfo();
inline QString getDirectoryName();
QString rootPath; VNote *vnote;
QString notebook;
// Current directory's relative path
QString relativePath; QString relativePath;
QString directoryName; // Used for cache
QString rootPath;
// Actions // Actions
QAction *newFileAct; QAction *newFileAct;
QAction *deleteFileAct; QAction *deleteFileAct;
}; };
inline QString VFileList::getDirectoryName()
{
if (relativePath.isEmpty()) {
return "";
}
return QFileInfo(QDir::cleanPath(relativePath)).fileName();
}
#endif // VFILELIST_H #endif // VFILELIST_H

View File

@ -11,7 +11,7 @@
extern VConfigManager vconfig; extern VConfigManager vconfig;
VMainWindow::VMainWindow(QWidget *parent) VMainWindow::VMainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent), notebookComboMuted(false)
{ {
// Must be called before those who uses VConfigManager // Must be called before those who uses VConfigManager
vnote = new VNote(); vnote = new VNote();
@ -50,7 +50,7 @@ void VMainWindow::setupUI()
notebookComboBox = new QComboBox(); notebookComboBox = new QComboBox();
notebookComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); notebookComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
directoryTree = new VDirectoryTree(); directoryTree = new VDirectoryTree(vnote);
QHBoxLayout *nbBtnLayout = new QHBoxLayout; QHBoxLayout *nbBtnLayout = new QHBoxLayout;
nbBtnLayout->addWidget(notebookLabel); nbBtnLayout->addWidget(notebookLabel);
@ -74,11 +74,11 @@ void VMainWindow::setupUI()
nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
// File list widget // File list widget
fileList = new VFileList(); fileList = new VFileList(vnote);
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
// Editor tab widget // Editor tab widget
tabs = new VTabWidget(); tabs = new VTabWidget(vnote);
tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
tabs->setTabBarAutoHide(true); tabs->setTabBarAutoHide(true);
@ -94,24 +94,41 @@ void VMainWindow::setupUI()
// Signals // Signals
connect(notebookComboBox, SIGNAL(currentIndexChanged(int)), this, connect(notebookComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(setCurNotebookIndex(int))); SLOT(setCurNotebookIndex(int)));
connect(this, SIGNAL(curNotebookIndexChanged(const QString&)), directoryTree,
SLOT(setTreePath(const QString&))); connect(vnote, &VNote::notebooksRenamed,
fileList, &VFileList::handleNotebookRenamed);
connect(directoryTree, &VDirectoryTree::currentDirectoryChanged, connect(directoryTree, &VDirectoryTree::currentDirectoryChanged,
fileList, &VFileList::setDirectory); fileList, &VFileList::setDirectory);
connect(directoryTree, &VDirectoryTree::directoryRenamed,
fileList, &VFileList::handleDirectoryRenamed);
connect(fileList, &VFileList::fileClicked, connect(fileList, &VFileList::fileClicked,
tabs, &VTabWidget::openFile); tabs, &VTabWidget::openFile);
connect(fileList, &VFileList::fileDeleted, connect(fileList, &VFileList::fileDeleted,
tabs, &VTabWidget::closeFile); tabs, &VTabWidget::closeFile);
connect(fileList, &VFileList::fileCreated, connect(fileList, &VFileList::fileCreated,
tabs, &VTabWidget::openFile); tabs, &VTabWidget::openFile);
connect(newNotebookBtn, &QPushButton::clicked, connect(newNotebookBtn, &QPushButton::clicked,
this, &VMainWindow::onNewNotebookBtnClicked); this, &VMainWindow::onNewNotebookBtnClicked);
connect(deleteNotebookBtn, &QPushButton::clicked, connect(deleteNotebookBtn, &QPushButton::clicked,
this, &VMainWindow::onDeleteNotebookBtnClicked); this, &VMainWindow::onDeleteNotebookBtnClicked);
connect(notebookInfoBtn, &QPushButton::clicked, connect(notebookInfoBtn, &QPushButton::clicked,
this, &VMainWindow::onNotebookInfoBtnClicked); this, &VMainWindow::onNotebookInfoBtnClicked);
connect(vnote, &VNote::notebooksChanged, connect(vnote, &VNote::notebooksChanged,
this, &VMainWindow::updateNotebookComboBox); this, &VMainWindow::updateNotebookComboBox);
connect(vnote, &VNote::notebooksDeleted,
this, &VMainWindow::notebookComboBoxDeleted);
connect(vnote, &VNote::notebooksRenamed,
this, &VMainWindow::notebookComboBoxRenamed);
connect(vnote, &VNote::notebooksAdded,
this, &VMainWindow::notebookComboBoxAdded);
connect(this, &VMainWindow::curNotebookChanged,
directoryTree, &VDirectoryTree::setNotebook);
connect(vnote, &VNote::notebooksRenamed,
directoryTree, &VDirectoryTree::handleNotebookRenamed);
connect(newRootDirBtn, &QPushButton::clicked, connect(newRootDirBtn, &QPushButton::clicked,
directoryTree, &VDirectoryTree::newRootDirectory); directoryTree, &VDirectoryTree::newRootDirectory);
connect(deleteDirBtn, &QPushButton::clicked, connect(deleteDirBtn, &QPushButton::clicked,
@ -207,38 +224,87 @@ void VMainWindow::initMenuBar()
void VMainWindow::updateNotebookComboBox(const QVector<VNotebook> &notebooks) void VMainWindow::updateNotebookComboBox(const QVector<VNotebook> &notebooks)
{ {
// Clearing and inserting items will emit the signal which corrupt the vconfig's notebookComboMuted = true;
// current index. We save it first and then set the combobox index to the
// right one to resrote it.
int curIndex = vconfig.getCurNotebookIndex();
notebookComboBox->clear(); notebookComboBox->clear();
if (notebooks.isEmpty()) {
return;
}
for (int i = 0; i < notebooks.size(); ++i) { for (int i = 0; i < notebooks.size(); ++i) {
notebookComboBox->addItem(notebooks[i].getName()); notebookComboBox->addItem(notebooks[i].getName());
} }
notebookComboMuted = false;
qDebug() << "update notebook combobox with" << notebookComboBox->count() int index = vconfig.getCurNotebookIndex();
<< "items, current notebook" << curIndex; if (notebooks.isEmpty()) {
notebookComboBox->setCurrentIndex(curIndex); index = -1;
}
if (notebookComboBox->currentIndex() == index) {
setCurNotebookIndex(index);
} else {
notebookComboBox->setCurrentIndex(index);
}
} }
void VMainWindow::notebookComboBoxAdded(const QVector<VNotebook> &notebooks, int idx)
{
notebookComboMuted = true;
notebookComboBox->insertItem(idx, notebooks[idx].getName());
notebookComboMuted = false;
if (notebookComboBox->currentIndex() == vconfig.getCurNotebookIndex()) {
setCurNotebookIndex(vconfig.getCurNotebookIndex());
} else {
notebookComboBox->setCurrentIndex(vconfig.getCurNotebookIndex());
}
}
void VMainWindow::notebookComboBoxDeleted(const QVector<VNotebook> &notebooks, const QString &deletedName)
{
notebookComboMuted = true;
int nrItem = notebookComboBox->count();
for (int i = 0; i < nrItem; ++i) {
if (notebookComboBox->itemText(i) == deletedName) {
notebookComboBox->removeItem(i);
break;
}
}
notebookComboMuted = false;
if (notebookComboBox->currentIndex() == vconfig.getCurNotebookIndex()) {
setCurNotebookIndex(vconfig.getCurNotebookIndex());
} else {
notebookComboBox->setCurrentIndex(vconfig.getCurNotebookIndex());
}
Q_ASSERT(notebooks.size() == notebookComboBox->count());
}
void VMainWindow::notebookComboBoxRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName)
{
int nrItem = notebookComboBox->count();
for (int i = 0; i < nrItem; ++i) {
if (notebookComboBox->itemText(i) == oldName) {
notebookComboBox->setItemText(i, newName);
break;
}
}
// Renaming a notebook won't change current index
}
// Maybe called multiple times
void VMainWindow::setCurNotebookIndex(int index) void VMainWindow::setCurNotebookIndex(int index)
{ {
if (notebookComboMuted) {
return;
}
Q_ASSERT(index < vnote->getNotebooks().size()); Q_ASSERT(index < vnote->getNotebooks().size());
// Update directoryTree // Update directoryTree
QString treePath; QString notebook;
if (index > -1) { if (index > -1) {
vconfig.setCurNotebookIndex(index); vconfig.setCurNotebookIndex(index);
treePath = vnote->getNotebooks()[index].getPath(); notebook = vnote->getNotebooks()[index].getName();
} }
emit curNotebookIndexChanged(treePath); emit curNotebookChanged(notebook);
} }
void VMainWindow::onNewNotebookBtnClicked() void VMainWindow::onNewNotebookBtnClicked()
{ {
qDebug() << "request to create a notebook";
QString info; QString info;
QString defaultName("new_notebook"); QString defaultName("new_notebook");
QString defaultPath; QString defaultPath;

View File

@ -27,19 +27,22 @@ public:
~VMainWindow(); ~VMainWindow();
private slots: private slots:
// Change current notebook index and update the directory tree
void setCurNotebookIndex(int index); void setCurNotebookIndex(int index);
// Create a notebook // Create a notebook
void onNewNotebookBtnClicked(); void onNewNotebookBtnClicked();
void onDeleteNotebookBtnClicked(); void onDeleteNotebookBtnClicked();
void onNotebookInfoBtnClicked(); void onNotebookInfoBtnClicked();
void updateNotebookComboBox(const QVector<VNotebook> &notebooks); void updateNotebookComboBox(const QVector<VNotebook> &notebooks);
void notebookComboBoxAdded(const QVector<VNotebook> &notebooks, int idx);
void notebookComboBoxDeleted(const QVector<VNotebook> &notebooks, const QString &deletedName);
void notebookComboBoxRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName);
void importNoteFromFile(); void importNoteFromFile();
void changeMarkdownConverter(QAction *action); void changeMarkdownConverter(QAction *action);
void aboutMessage(); void aboutMessage();
signals: signals:
void curNotebookIndexChanged(const QString &path); void curNotebookChanged(const QString &notebookName);
private: private:
void setupUI(); void setupUI();
@ -48,6 +51,9 @@ private:
void initMenuBar(); void initMenuBar();
bool isConflictWithExistingNotebooks(const QString &name); bool isConflictWithExistingNotebooks(const QString &name);
// If true, comboBox changes will not trigger any signal out
bool notebookComboMuted;
QLabel *notebookLabel; QLabel *notebookLabel;
QLabel *directoryLabel; QLabel *directoryLabel;
QComboBox *notebookComboBox; QComboBox *notebookComboBox;

View File

@ -46,7 +46,6 @@ void VNote::createNotebook(const QString &name, const QString &path)
// Create a directory config file in @path // Create a directory config file in @path
QJsonObject configJson; QJsonObject configJson;
configJson["version"] = "1"; configJson["version"] = "1";
configJson["name"] = name;
configJson["sub_directories"] = QJsonArray(); configJson["sub_directories"] = QJsonArray();
configJson["files"] = QJsonArray(); configJson["files"] = QJsonArray();
if (!vconfig.writeDirectoryConfig(path, configJson)) { if (!vconfig.writeDirectoryConfig(path, configJson)) {
@ -60,13 +59,14 @@ void VNote::createNotebook(const QString &name, const QString &path)
// Set current index to the new notebook // Set current index to the new notebook
vconfig.setCurNotebookIndex(0); vconfig.setCurNotebookIndex(0);
emit notebooksChanged(notebooks); emit notebooksAdded(notebooks, 0);
} }
void VNote::removeNotebook(const QString &name) void VNote::removeNotebook(const QString &name)
{ {
// Update notebooks settings // Update notebooks settings
QString path; QString path;
int curIndex = vconfig.getCurNotebookIndex();
int index; int index;
for (index = 0; index < notebooks.size(); ++index) { for (index = 0; index < notebooks.size(); ++index) {
if (notebooks[index].getName() == name) { if (notebooks[index].getName() == name) {
@ -79,7 +79,11 @@ void VNote::removeNotebook(const QString &name)
} }
notebooks.remove(index); notebooks.remove(index);
vconfig.setNotebooks(notebooks); vconfig.setNotebooks(notebooks);
vconfig.setCurNotebookIndex(notebooks.isEmpty() ? -1 : 0); if (notebooks.isEmpty()) {
vconfig.setCurNotebookIndex(-1);
} else if (index == curIndex) {
vconfig.setCurNotebookIndex(0);
}
// Delete the directory // Delete the directory
QDir dir(path); QDir dir(path);
@ -88,7 +92,7 @@ void VNote::removeNotebook(const QString &name)
} else { } else {
qDebug() << "delete" << path << "recursively"; qDebug() << "delete" << path << "recursively";
} }
emit notebooksChanged(notebooks); emit notebooksDeleted(notebooks, name);
} }
void VNote::renameNotebook(const QString &name, const QString &newName) void VNote::renameNotebook(const QString &name, const QString &newName)
@ -108,5 +112,5 @@ void VNote::renameNotebook(const QString &name, const QString &newName)
notebooks[index].setName(newName); notebooks[index].setName(newName);
vconfig.setNotebooks(notebooks); vconfig.setNotebooks(notebooks);
emit notebooksChanged(notebooks); emit notebooksRenamed(notebooks, name, newName);
} }

View File

@ -32,7 +32,12 @@ public:
void renameNotebook(const QString &name, const QString &newName); void renameNotebook(const QString &name, const QString &newName);
signals: signals:
// Force to do a fully update
void notebooksChanged(const QVector<VNotebook> &notebooks); void notebooksChanged(const QVector<VNotebook> &notebooks);
void notebooksAdded(const QVector<VNotebook> &notebooks, int idx);
void notebooksDeleted(const QVector<VNotebook> &notebooks, const QString &deletedName);
void notebooksRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName);
private: private:
QVector<VNotebook> notebooks; QVector<VNotebook> notebooks;

View File

@ -1,9 +1,9 @@
#include "vnotefile.h" #include "vnotefile.h"
VNoteFile::VNoteFile(const QString &path, const QString &name, VNoteFile::VNoteFile(const QString &basePath, const QString &fileName,
const QString &content, DocType docType, bool modifiable) const QString &content, DocType docType, bool modifiable)
: path(path), name(name), content(content), docType(docType), : basePath(basePath), fileName(fileName),
modifiable(modifiable) content(content), docType(docType), modifiable(modifiable)
{ {
} }

View File

@ -7,11 +7,11 @@
class VNoteFile class VNoteFile
{ {
public: public:
VNoteFile(const QString &path, const QString &name, const QString &content, VNoteFile(const QString &basePath, const QString &fileName, const QString &content,
DocType docType, bool modifiable); DocType docType, bool modifiable);
QString path; QString basePath;
QString name; QString fileName;
QString content; QString content;
DocType docType; DocType docType;
bool modifiable; bool modifiable;

View File

@ -7,8 +7,8 @@
extern VConfigManager vconfig; extern VConfigManager vconfig;
VTabWidget::VTabWidget(QWidget *parent) VTabWidget::VTabWidget(VNote *vnote, QWidget *parent)
: QTabWidget(parent) : QTabWidget(parent), vnote(vnote)
{ {
setTabsClosable(true); setTabsClosable(true);
setMovable(true); setMovable(true);
@ -20,24 +20,25 @@ VTabWidget::VTabWidget(QWidget *parent)
void VTabWidget::openWelcomePage() void VTabWidget::openWelcomePage()
{ {
int idx = openFileInTab(vconfig.getWelcomePagePath(), "", false); int idx = openFileInTab("", vconfig.getWelcomePagePath(), false);
setTabText(idx, "Welcome to VNote"); setTabText(idx, "Welcome to VNote");
setTabToolTip(idx, "VNote"); setTabToolTip(idx, "VNote");
} }
int VTabWidget::insertTabWithData(int index, QWidget *page, const QString &label, int VTabWidget::insertTabWithData(int index, QWidget *page,
const QJsonObject &tabData) const QJsonObject &tabData)
{ {
QString label = getFileName(tabData["relative_path"].toString());
int idx = insertTab(index, page, label); int idx = insertTab(index, page, label);
QTabBar *tabs = tabBar(); QTabBar *tabs = tabBar();
tabs->setTabData(idx, tabData); tabs->setTabData(idx, tabData);
Q_ASSERT(tabs->tabText(idx) == label);
return idx; return idx;
} }
int VTabWidget::appendTabWithData(QWidget *page, const QString &label, const QJsonObject &tabData) int VTabWidget::appendTabWithData(QWidget *page, const QJsonObject &tabData)
{ {
return insertTabWithData(count(), page, label, tabData); return insertTabWithData(count(), page, tabData);
} }
void VTabWidget::openFile(QJsonObject fileJson) void VTabWidget::openFile(QJsonObject fileJson)
@ -45,22 +46,23 @@ void VTabWidget::openFile(QJsonObject fileJson)
if (fileJson.isEmpty()) { if (fileJson.isEmpty()) {
return; return;
} }
qDebug() << "open file:" << fileJson;
QString path = fileJson["path"].toString(); QString notebook = fileJson["notebook"].toString();
QString name = fileJson["name"].toString(); QString relativePath = fileJson["relative_path"].toString();
int mode = OpenFileMode::Read; int mode = OpenFileMode::Read;
if (fileJson.contains("mode")) { if (fileJson.contains("mode")) {
mode = fileJson["mode"].toInt(); mode = fileJson["mode"].toInt();
} }
qDebug() << "open notebook[" << notebook << "] path[" << relativePath << "]" << mode;
// Find if it has been opened already // Find if it has been opened already
int idx = findTabByFile(path, name); int idx = findTabByFile(notebook, relativePath);
if (idx > -1) { if (idx > -1) {
goto out; goto out;
} }
idx = openFileInTab(path, name, true); idx = openFileInTab(notebook, relativePath, true);
out: out:
setCurrentIndex(idx); setCurrentIndex(idx);
@ -78,11 +80,11 @@ void VTabWidget::closeFile(QJsonObject fileJson)
} }
qDebug() << "close file:" << fileJson; qDebug() << "close file:" << fileJson;
QString path = fileJson["path"].toString(); QString notebook = fileJson["notebook"].toString();
QString name = fileJson["name"].toString(); QString relativePath = fileJson["relative_path"].toString();
// Find if it has been opened already // Find if it has been opened already
int idx = findTabByFile(path, name); int idx = findTabByFile(notebook, relativePath);
if (idx == -1) { if (idx == -1) {
return; return;
} }
@ -93,25 +95,34 @@ void VTabWidget::closeFile(QJsonObject fileJson)
delete page; delete page;
} }
int VTabWidget::openFileInTab(const QString &path, const QString &name, bool modifiable) int VTabWidget::openFileInTab(const QString &notebook, const QString &relativePath,
bool modifiable)
{ {
VEditor *editor = new VEditor(path, name, modifiable); QString rootPath;
QJsonObject tabJson; const QVector<VNotebook> &notebooks = vnote->getNotebooks();
tabJson["path"] = path; for (int i = 0; i < notebooks.size(); ++i) {
tabJson["name"] = name; if (notebooks[i].getName() == notebook) {
int idx = appendTabWithData(editor, name, tabJson); rootPath = notebooks[i].getPath();
setTabToolTip(idx, path); break;
return idx; }
} }
int VTabWidget::findTabByFile(const QString &path, const QString &name) VEditor *editor = new VEditor(QDir::cleanPath(QDir(rootPath).filePath(relativePath)),
modifiable);
QJsonObject tabJson;
tabJson["notebook"] = notebook;
tabJson["relative_path"] = relativePath;
return appendTabWithData(editor, tabJson);
}
int VTabWidget::findTabByFile(const QString &notebook, const QString &relativePath) const
{ {
QTabBar *tabs = tabBar(); QTabBar *tabs = tabBar();
int nrTabs = tabs->count(); int nrTabs = tabs->count();
for (int i = 0; i < nrTabs; ++i) { for (int i = 0; i < nrTabs; ++i) {
QJsonObject tabJson = tabs->tabData(i).toJsonObject(); QJsonObject tabJson = tabs->tabData(i).toJsonObject();
if (tabJson["name"] == name && tabJson["path"] == path) { if (tabJson["notebook"] == notebook && tabJson["relative_path"] == relativePath) {
return i; return i;
} }
} }

View File

@ -4,12 +4,16 @@
#include <QTabWidget> #include <QTabWidget>
#include <QJsonObject> #include <QJsonObject>
#include <QString> #include <QString>
#include <QFileInfo>
#include <QDir>
class VNote;
class VTabWidget : public QTabWidget class VTabWidget : public QTabWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VTabWidget(QWidget *parent = 0); explicit VTabWidget(VNote *vnote, QWidget *parent = 0);
signals: signals:
@ -26,10 +30,18 @@ private slots:
private: private:
void openWelcomePage(); void openWelcomePage();
int insertTabWithData(int index, QWidget *page, const QString &label, const QJsonObject &tabData); int insertTabWithData(int index, QWidget *page, const QJsonObject &tabData);
int appendTabWithData(QWidget *page, const QString &label, const QJsonObject &tabData); int appendTabWithData(QWidget *page, const QJsonObject &tabData);
int findTabByFile(const QString &path, const QString &name); int findTabByFile(const QString &notebook, const QString &relativePath) const;
int openFileInTab(const QString &path, const QString &name, bool modifiable); int openFileInTab(const QString &notebook, const QString &relativePath, bool modifiable);
inline QString getFileName(const QString &relativePath) const;
VNote *vnote;
}; };
inline QString VTabWidget::getFileName(const QString &path) const
{
return QFileInfo(QDir::cleanPath(path)).fileName();
}
#endif // VTABWIDGET_H #endif // VTABWIDGET_H