notebook: support relative path (to app's directory)

This commit is contained in:
Le Tan 2018-05-23 20:09:14 +08:00
parent 3c8ac8094d
commit 89677c8261
11 changed files with 194 additions and 47 deletions

View File

@ -39,6 +39,12 @@ void VFixNotebookDialog::setupUI()
connect(m_browseBtn, &QPushButton::clicked,
this, &VFixNotebookDialog::handleBrowseBtnClicked);
m_relativePathCB = new QCheckBox(tr("Use relative path"), this);
m_relativePathCB->setToolTip(tr("Use relative path (to VNote's executable) in configuration file"));
m_relativePathCB->setChecked(!QDir::isAbsolutePath(m_notebook->getPathInConfig()));
connect(m_relativePathCB, &QCheckBox::stateChanged,
this, &VFixNotebookDialog::handleInputChanged);
QHBoxLayout *pathLayout = new QHBoxLayout();
pathLayout->addWidget(m_pathEdit);
pathLayout->addWidget(m_browseBtn);
@ -46,6 +52,7 @@ void VFixNotebookDialog::setupUI()
QFormLayout *topLayout = new QFormLayout();
topLayout->addRow(tr("Notebook name:"), nameLabel);
topLayout->addRow(tr("Notebook root folder:"), pathLayout);
topLayout->addRow(m_relativePathCB);
// Warning label.
m_warnLabel = new QLabel(this);
@ -89,7 +96,12 @@ void VFixNotebookDialog::handleBrowseBtnClicked()
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dirPath.isEmpty()) {
if (m_pathEdit->text() == dirPath) {
handleInputChanged();
} else {
m_pathEdit->setText(dirPath);
}
defaultPath = VUtils::basePathFromPath(dirPath);
}
}
@ -103,7 +115,11 @@ void VFixNotebookDialog::handleInputChanged()
QString path = m_pathEdit->text();
if (!path.isEmpty()) {
if (VConfigManager::directoryConfigExist(path)) {
if (!QDir::isAbsolutePath(path)) {
QString tmp = tr("<span style=\"%1\">WARNING</span>: Please specify absolute path.")
.arg(g_config->c_warningTextStyle);
m_warnLabel->setText(tmp);
} else if (VConfigManager::directoryConfigExist(path)) {
pathOk = true;
}
}
@ -131,6 +147,18 @@ void VFixNotebookDialog::handleInputChanged()
m_warnLabel->setText(warnText);
}
if (pathOk && isUseRelativePath()) {
if (!VUtils::inSameDrive(QCoreApplication::applicationDirPath(), path)) {
pathOk = false;
QString existText = tr("<span style=\"%1\">WARNING</span>: Please choose a folder in the same drive as "
"<span style=\"%2\">%3</span> when relative path is enabled.")
.arg(g_config->c_warningTextStyle)
.arg(g_config->c_dataTextStyle)
.arg(QCoreApplication::applicationDirPath());
m_warnLabel->setText(existText);
}
}
m_warnLabel->setVisible(!pathOk);
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
okBtn->setEnabled(pathOk);
@ -140,5 +168,19 @@ QString VFixNotebookDialog::getPathInput() const
{
// absoluteFilePath() to convert the drive to upper case.
// cleanPath() to remove duplicate separator, '.', and '..'.
return QDir::cleanPath(QFileInfo(m_pathEdit->text()).absoluteFilePath());
QString ret;
if (isUseRelativePath()) {
// Use relative path in config file.
QDir appDir(QCoreApplication::applicationDirPath());
ret = QDir::cleanPath(appDir.relativeFilePath(m_pathEdit->text()));
} else {
ret = QDir::cleanPath(QFileInfo(m_pathEdit->text()).absoluteFilePath());
}
return ret;
}
bool VFixNotebookDialog::isUseRelativePath() const
{
return m_relativePathCB->isChecked();
}

View File

@ -8,6 +8,7 @@ class VLineEdit;
class QLabel;
class QPushButton;
class QDialogButtonBox;
class QCheckBox;
class VFixNotebookDialog : public QDialog
{
@ -27,6 +28,9 @@ private slots:
private:
void setupUI();
// Whether relative path will be used in config file.
bool isUseRelativePath() const;
const VNotebook *m_notebook;
const QVector<VNotebook *> &m_notebooks;
@ -35,6 +39,8 @@ private:
QPushButton *m_browseBtn;
QCheckBox *m_relativePathCB;
QLabel *m_warnLabel;
QDialogButtonBox *m_btnBox;

View File

@ -20,7 +20,7 @@ VNewNotebookDialog::VNewNotebookDialog(const QString &title, const QString &info
setupUI(title, info);
connect(m_nameEdit, &VMetaWordLineEdit::textChanged, this, &VNewNotebookDialog::handleInputChanged);
connect(pathEdit, &VLineEdit::textChanged, this, &VNewNotebookDialog::handleInputChanged);
connect(m_pathEdit, &VLineEdit::textChanged, this, &VNewNotebookDialog::handleInputChanged);
connect(browseBtn, &QPushButton::clicked, this, &VNewNotebookDialog::handleBrowseBtnClicked);
handleInputChanged();
@ -42,10 +42,15 @@ void VNewNotebookDialog::setupUI(const QString &p_title, const QString &p_info)
nameLabel->setBuddy(m_nameEdit);
QLabel *pathLabel = new QLabel(tr("Notebook &root folder:"));
pathEdit = new VLineEdit(defaultPath);
pathLabel->setBuddy(pathEdit);
m_pathEdit = new VLineEdit(defaultPath);
pathLabel->setBuddy(m_pathEdit);
browseBtn = new QPushButton(tr("&Browse"));
m_relativePathCB = new QCheckBox(tr("Use relative path"));
m_relativePathCB->setToolTip(tr("Use relative path (to VNote's executable) in configuration file"));
connect(m_relativePathCB, &QCheckBox::stateChanged,
this, &VNewNotebookDialog::handleInputChanged);
QLabel *imageFolderLabel = new QLabel(tr("&Image folder:"));
m_imageFolderEdit = new VLineEdit();
imageFolderLabel->setBuddy(m_imageFolderEdit);
@ -72,12 +77,13 @@ void VNewNotebookDialog::setupUI(const QString &p_title, const QString &p_info)
topLayout->addWidget(nameLabel, 0, 0);
topLayout->addWidget(m_nameEdit, 0, 1, 1, 2);
topLayout->addWidget(pathLabel, 1, 0);
topLayout->addWidget(pathEdit, 1, 1);
topLayout->addWidget(m_pathEdit, 1, 1);
topLayout->addWidget(browseBtn, 1, 2);
topLayout->addWidget(imageFolderLabel, 2, 0);
topLayout->addWidget(m_imageFolderEdit, 2, 1);
topLayout->addWidget(attachmentFolderLabel, 3, 0);
topLayout->addWidget(m_attachmentFolderEdit, 3, 1);
topLayout->addWidget(m_relativePathCB, 2, 1);
topLayout->addWidget(imageFolderLabel, 3, 0);
topLayout->addWidget(m_imageFolderEdit, 3, 1);
topLayout->addWidget(attachmentFolderLabel, 4, 0);
topLayout->addWidget(m_attachmentFolderEdit, 4, 1);
// Warning label.
m_warnLabel = new QLabel();
@ -91,7 +97,7 @@ void VNewNotebookDialog::setupUI(const QString &p_title, const QString &p_info)
QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
okBtn->setProperty("SpecialBtn", true);
pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
if (infoLabel) {
@ -116,7 +122,16 @@ QString VNewNotebookDialog::getPathInput() const
{
// absoluteFilePath() to convert the drive to upper case.
// cleanPath() to remove duplicate separator, '.', and '..'.
return QDir::cleanPath(QFileInfo(pathEdit->text()).absoluteFilePath());
QString ret;
if (isUseRelativePath()) {
// Use relative path in config file.
QDir appDir(QCoreApplication::applicationDirPath());
ret = QDir::cleanPath(appDir.relativeFilePath(m_pathEdit->text()));
} else {
ret = QDir::cleanPath(QFileInfo(m_pathEdit->text()).absoluteFilePath());
}
return ret;
}
QString VNewNotebookDialog::getImageFolder() const
@ -140,6 +155,7 @@ QString VNewNotebookDialog::getAttachmentFolder() const
void VNewNotebookDialog::handleBrowseBtnClicked()
{
static QString defaultPath;
if (defaultPath.isEmpty()) {
defaultPath = g_config->getVnoteNotebookFolderPath();
if (!QFileInfo::exists(defaultPath)) {
@ -154,7 +170,12 @@ void VNewNotebookDialog::handleBrowseBtnClicked()
if (!dirPath.isEmpty()) {
m_manualPath = true;
pathEdit->setText(dirPath);
if (m_pathEdit->text() == dirPath) {
handleInputChanged();
} else {
m_pathEdit->setText(dirPath);
}
defaultPath = VUtils::basePathFromPath(dirPath);
}
}
@ -184,7 +205,7 @@ void VNewNotebookDialog::handleInputChanged()
bool showWarnLabel = false;
// User has input some texts.
if (pathEdit->isModified()) {
if (m_pathEdit->isModified()) {
m_manualPath = true;
}
@ -196,9 +217,14 @@ void VNewNotebookDialog::handleInputChanged()
return;
}
QString path = pathEdit->text();
QString path = m_pathEdit->text();
if (!path.isEmpty()) {
if (QFileInfo::exists(path)) {
if (!QDir::isAbsolutePath(path)) {
showWarnLabel = true;
QString tmp = tr("<span style=\"%1\">WARNING</span>: Please specify absolute path.")
.arg(g_config->c_warningTextStyle);
m_warnLabel->setText(tmp);
} else if (QFileInfo::exists(path)) {
QDir dir(path);
QStringList files = dir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden);
if (files.isEmpty()) {
@ -206,13 +232,6 @@ void VNewNotebookDialog::handleInputChanged()
} else {
// Folder is not empty.
configExist = VConfigManager::directoryConfigExist(path);
showWarnLabel = true;
}
} else {
pathOk = true;
}
}
if (configExist) {
pathOk = true;
m_warnLabel->setText(infoText);
@ -220,6 +239,13 @@ void VNewNotebookDialog::handleInputChanged()
m_warnLabel->setText(warnText);
}
showWarnLabel = true;
}
} else {
pathOk = true;
}
}
// Try to validate if this is a legal path on the OS.
if (pathOk) {
pathOk = VUtils::checkPathLegal(path);
@ -253,6 +279,19 @@ void VNewNotebookDialog::handleInputChanged()
}
}
if (pathOk && isUseRelativePath()) {
if (!VUtils::inSameDrive(QCoreApplication::applicationDirPath(), path)) {
pathOk = false;
showWarnLabel = true;
QString existText = tr("<span style=\"%1\">WARNING</span>: Please choose a folder in the same drive as "
"<span style=\"%2\">%3</span> when relative path is enabled.")
.arg(g_config->c_warningTextStyle)
.arg(g_config->c_dataTextStyle)
.arg(QCoreApplication::applicationDirPath());
m_warnLabel->setText(existText);
}
}
QString name = m_nameEdit->getEvaluatedText();
bool nameOk = !name.isEmpty();
if (pathOk && nameOk) {
@ -310,7 +349,7 @@ bool VNewNotebookDialog::autoComplete()
}
// Set the name according to user-chosen path.
QString pathText = pathEdit->text();
QString pathText = m_pathEdit->text();
if (!pathText.isEmpty()) {
QString autoName = VUtils::directoryNameFromPath(pathText);
if (autoName != nameText) {
@ -323,7 +362,7 @@ bool VNewNotebookDialog::autoComplete()
}
QString vnoteFolder = g_config->getVnoteNotebookFolderPath();
QString pathText = pathEdit->text();
QString pathText = m_pathEdit->text();
if (!pathText.isEmpty()
&& !VUtils::equalPath(vnoteFolder, VUtils::basePathFromPath(pathText))) {
return false;
@ -344,10 +383,15 @@ bool VNewNotebookDialog::autoComplete()
// Use the name as the folder name under vnoteFolder.
QString autoPath = QDir::cleanPath(QDir(vnoteFolder).filePath(nameText));
if (autoPath != pathText) {
pathEdit->setText(autoPath);
m_pathEdit->setText(autoPath);
ret = true;
}
}
return ret;
}
bool VNewNotebookDialog::isUseRelativePath() const
{
return m_relativePathCB->isChecked();
}

View File

@ -10,6 +10,7 @@ class VMetaWordLineEdit;
class QPushButton;
class QDialogButtonBox;
class VNotebook;
class QCheckBox;
class VNewNotebookDialog : public QDialog
{
@ -53,9 +54,13 @@ private:
// Returns true if name or path is modified.
bool autoComplete();
// Whether relative path will be used in config file.
bool isUseRelativePath() const;
VMetaWordLineEdit *m_nameEdit;
VLineEdit *pathEdit;
VLineEdit *m_pathEdit;
QPushButton *browseBtn;
QCheckBox *m_relativePathCB;
QLabel *m_warnLabel;
VLineEdit *m_imageFolderEdit;
VLineEdit *m_attachmentFolderEdit;

View File

@ -1525,3 +1525,20 @@ QFormLayout *VUtils::getFormLayout()
return layout;
}
bool VUtils::inSameDrive(const QString &p_a, const QString &p_b)
{
#if defined(Q_OS_WIN)
QChar sep(':');
int ai = p_a.indexOf(sep);
int bi = p_b.indexOf(sep);
if (ai == -1 || bi == -1) {
return false;
}
return p_a.left(ai).toLower() == p_b.left(bi).toLower();
#else
return true;
#endif
}

View File

@ -331,6 +331,8 @@ public:
// Return QFormLayout.
static QFormLayout *getFormLayout();
static bool inSameDrive(const QString &p_a, const QString &p_b);
// Regular expression for image link.
// ![image title]( http://github.com/tamlok/vnote.jpg "alt text" =200x100)
// Captured texts (need to be trimmed):

View File

@ -396,7 +396,7 @@ void VConfigManager::writeNotebookToSettings(QSettings *p_settings,
p_settings->setArrayIndex(i);
const VNotebook &notebook = *p_notebooks[i];
p_settings->setValue("name", notebook.getName());
p_settings->setValue("path", notebook.getPath());
p_settings->setValue("path", notebook.getPathInConfig());
}
p_settings->endArray();

View File

@ -1,6 +1,8 @@
#include "vnotebook.h"
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
#include "vdirectory.h"
#include "utils/vutils.h"
#include "vconfigmanager.h"
@ -11,7 +13,7 @@ extern VConfigManager *g_config;
VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent)
: QObject(parent), m_name(name), m_valid(false)
{
m_path = QDir::cleanPath(path);
setPath(path);
m_recycleBinFolder = g_config->getRecycleBinFolder();
m_rootDir = new VDirectory(this,
NULL,
@ -24,6 +26,16 @@ VNotebook::~VNotebook()
delete m_rootDir;
}
void VNotebook::setPath(const QString &p_path)
{
m_pathInConfig = QDir::cleanPath(p_path);
if (QDir::isAbsolutePath(m_pathInConfig)) {
m_path = m_pathInConfig;
} else {
m_path = QDir::cleanPath(QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(m_pathInConfig));
}
}
bool VNotebook::readConfigNotebook()
{
QJsonObject configJson = VConfigManager::readDirectoryConfig(m_path);
@ -115,16 +127,6 @@ bool VNotebook::writeConfigNotebook() const
return VConfigManager::writeDirectoryConfig(m_path, configJson);
}
const QString &VNotebook::getName() const
{
return m_name;
}
const QString &VNotebook::getPath() const
{
return m_path;
}
void VNotebook::close()
{
m_rootDir->close();
@ -171,13 +173,13 @@ VNotebook *VNotebook::createNotebook(const QString &p_name,
nb->setAttachmentFolder(attachmentFolder);
// Check if there alread exists a config file.
if (p_import && VConfigManager::directoryConfigExist(p_path)) {
if (p_import && VConfigManager::directoryConfigExist(nb->getPath())) {
qDebug() << "import existing notebook";
nb->readConfigNotebook();
return nb;
}
VUtils::makePath(p_path);
VUtils::makePath(nb->getPath());
if (!nb->writeToConfig()) {
delete nb;
@ -397,7 +399,7 @@ void VNotebook::updatePath(const QString &p_path)
{
Q_ASSERT(!isOpened());
m_valid = false;
m_path = QDir::cleanPath(p_path);
setPath(p_path);
delete m_rootDir;
m_rootDir = new VDirectory(this,
NULL,

View File

@ -47,6 +47,8 @@ public:
const QString &getPath() const;
const QString &getPathInConfig() const;
void updatePath(const QString &p_path);
VDirectory *getRootDir() const;
@ -107,9 +109,16 @@ private:
// Write current instance to config file.
bool writeToConfig() const;
void setPath(const QString &p_path);
QString m_name;
QString m_path;
// Path in vnote.ini.
// May be relative path to VNote's executable.
QString m_pathInConfig;
// Folder name to store images.
// If not empty, VNote will store images in this folder within the same directory of the note.
// Otherwise, VNote will use the global configured folder.
@ -146,4 +155,19 @@ inline bool VNotebook::isValid() const
return m_valid;
}
inline const QString &VNotebook::getPath() const
{
return m_path;
}
inline const QString &VNotebook::getPathInConfig() const
{
return m_pathInConfig;
}
inline const QString &VNotebook::getName() const
{
return m_name;
}
#endif // VNOTEBOOK_H

View File

@ -320,8 +320,11 @@ void VNotebookSelector::createNotebook(const QString &p_name,
const QString &p_imageFolder,
const QString &p_attachmentFolder)
{
VNotebook *nb = VNotebook::createNotebook(p_name, p_path, p_import,
p_imageFolder, p_attachmentFolder,
VNotebook *nb = VNotebook::createNotebook(p_name,
p_path,
p_import,
p_imageFolder,
p_attachmentFolder,
g_vnote);
if (!nb) {
VUtils::showMessage(QMessageBox::Warning, tr("Warning"),

View File

@ -77,8 +77,10 @@ private:
// If @p_import is true, we will use the existing config file.
// If @p_imageFolder is empty, we will use the global one.
// If @p_attachmentFolder is empty, we will use the global one.
void createNotebook(const QString &p_name, const QString &p_path,
bool p_import, const QString &p_imageFolder,
void createNotebook(const QString &p_name,
const QString &p_path,
bool p_import,
const QString &p_imageFolder,
const QString &p_attachmentFolder);
void deleteNotebook(VNotebook *p_notebook, bool p_deleteFiles);