| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- #include "vnotefile.h"
- #include <QDir>
- #include <QDebug>
- #include <QTextEdit>
- #include <QFileInfo>
- #include <QJsonObject>
- #include <QJsonArray>
- #include <QDebug>
- #include "utils/vutils.h"
- #include "vdirectory.h"
- VNoteFile::VNoteFile(VDirectory *p_directory,
- const QString &p_name,
- FileType p_type,
- bool p_modifiable,
- QDateTime p_createdTimeUtc,
- QDateTime p_modifiedTimeUtc,
- const QString &p_attachmentFolder,
- const QVector<VAttachment> &p_attachments)
- : VFile(p_directory, p_name, p_type, p_modifiable, p_createdTimeUtc, p_modifiedTimeUtc),
- m_attachmentFolder(p_attachmentFolder),
- m_attachments(p_attachments)
- {
- }
- QString VNoteFile::fetchPath() const
- {
- return QDir(getDirectory()->fetchPath()).filePath(m_name);
- }
- QString VNoteFile::fetchBasePath() const
- {
- return getDirectory()->fetchPath();
- }
- QString VNoteFile::fetchImageFolderPath() const
- {
- return QDir(fetchBasePath()).filePath(getNotebook()->getImageFolder());
- }
- bool VNoteFile::useRelativeImageFolder() const
- {
- // Always use relative image folder.
- return true;
- }
- QString VNoteFile::getImageFolderInLink() const
- {
- return getNotebook()->getImageFolder();
- }
- void VNoteFile::setName(const QString &p_name)
- {
- m_name = p_name;
- }
- bool VNoteFile::rename(const QString &p_name)
- {
- if (m_name == p_name) {
- return true;
- }
- QString oldName = m_name;
- VDirectory *dir = getDirectory();
- Q_ASSERT(dir);
- // Rename it in disk.
- QDir diskDir(dir->fetchPath());
- if (!diskDir.rename(m_name, p_name)) {
- qWarning() << "fail to rename file" << m_name << "to" << p_name << "in disk";
- return false;
- }
- m_name = p_name;
- // Update parent directory's config file.
- if (!dir->updateFileConfig(this)) {
- m_name = oldName;
- diskDir.rename(p_name, m_name);
- return false;
- }
- // Can't not change doc type.
- Q_ASSERT(m_docType == DocType::Unknown
- || m_docType == VUtils::docTypeFromName(m_name));
- m_docType = VUtils::docTypeFromName(m_name);
- qDebug() << "file renamed from" << oldName << "to" << m_name;
- return true;
- }
- VDirectory *VNoteFile::getDirectory()
- {
- Q_ASSERT(parent());
- return (VDirectory *)parent();
- }
- const VDirectory *VNoteFile::getDirectory() const
- {
- Q_ASSERT(parent());
- return (const VDirectory *)parent();
- }
- VNotebook *VNoteFile::getNotebook()
- {
- return getDirectory()->getNotebook();
- }
- const VNotebook *VNoteFile::getNotebook() const
- {
- return getDirectory()->getNotebook();
- }
- QString VNoteFile::getNotebookName() const
- {
- return getDirectory()->getNotebookName();
- }
- QString VNoteFile::fetchRelativePath() const
- {
- return QDir(getDirectory()->fetchRelativePath()).filePath(m_name);
- }
- VNoteFile *VNoteFile::fromJson(VDirectory *p_directory,
- const QJsonObject &p_json,
- FileType p_type,
- bool p_modifiable)
- {
- // Attachments.
- QJsonArray attachmentJson = p_json[DirConfig::c_attachments].toArray();
- QVector<VAttachment> attachments;
- for (int i = 0; i < attachmentJson.size(); ++i) {
- QJsonObject attachmentItem = attachmentJson[i].toObject();
- attachments.push_back(VAttachment(attachmentItem[DirConfig::c_name].toString()));
- }
- return new VNoteFile(p_directory,
- p_json[DirConfig::c_name].toString(),
- p_type,
- p_modifiable,
- QDateTime::fromString(p_json[DirConfig::c_createdTime].toString(),
- Qt::ISODate),
- QDateTime::fromString(p_json[DirConfig::c_modifiedTime].toString(),
- Qt::ISODate),
- p_json[DirConfig::c_attachmentFolder].toString(),
- attachments);
- }
- QJsonObject VNoteFile::toConfigJson() const
- {
- QJsonObject item;
- item[DirConfig::c_name] = m_name;
- item[DirConfig::c_createdTime] = m_createdTimeUtc.toString(Qt::ISODate);
- item[DirConfig::c_modifiedTime] = m_modifiedTimeUtc.toString(Qt::ISODate);
- item[DirConfig::c_attachmentFolder] = m_attachmentFolder;
- // Attachments.
- QJsonArray attachmentJson;
- for (int i = 0; i < m_attachments.size(); ++i) {
- const VAttachment &item = m_attachments[i];
- QJsonObject attachmentItem;
- attachmentItem[DirConfig::c_name] = item.m_name;
- attachmentJson.append(attachmentItem);
- }
- item[DirConfig::c_attachments] = attachmentJson;
- return item;
- }
- bool VNoteFile::deleteFile(QString *p_errMsg)
- {
- Q_ASSERT(!m_opened);
- Q_ASSERT(parent());
- bool ret = true;
- // Delete local images if it is Markdown.
- if (m_docType == DocType::Markdown) {
- if (!deleteInternalImages()) {
- ret = false;
- VUtils::addErrMsg(p_errMsg, tr("Fail to delete images of this note."));
- }
- }
- // Delete attachments.
- if (!deleteAttachments()) {
- ret = false;
- VUtils::addErrMsg(p_errMsg, tr("Fail to delete attachments of this note."));
- }
- // Delete the file.
- QString filePath = fetchPath();
- if (VUtils::deleteFile(getNotebook(), filePath, false)) {
- qDebug() << "deleted" << m_name << filePath;
- } else {
- ret = false;
- VUtils::addErrMsg(p_errMsg, tr("Fail to delete the note file."));
- qWarning() << "fail to delete" << m_name << filePath;
- }
- return ret;
- }
- bool VNoteFile::deleteInternalImages()
- {
- Q_ASSERT(parent() && m_docType == DocType::Markdown);
- QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(this,
- ImageLink::LocalRelativeInternal);
- int deleted = 0;
- for (int i = 0; i < images.size(); ++i) {
- if (VUtils::deleteFile(getNotebook(), images[i].m_path, false)) {
- ++deleted;
- }
- }
- qDebug() << "delete" << deleted << "images for" << m_name << fetchPath();
- return deleted == images.size();
- }
- bool VNoteFile::addAttachment(const QString &p_file)
- {
- if (p_file.isEmpty() || !QFileInfo::exists(p_file)) {
- return false;
- }
- QString folderPath = fetchAttachmentFolderPath();
- QString name = VUtils::fileNameFromPath(p_file);
- Q_ASSERT(!name.isEmpty());
- name = VUtils::getFileNameWithSequence(folderPath, name);
- QString destPath = QDir(folderPath).filePath(name);
- if (!VUtils::copyFile(p_file, destPath, false)) {
- return false;
- }
- m_attachments.push_back(VAttachment(name));
- if (!getDirectory()->updateFileConfig(this)) {
- qWarning() << "fail to update config of file" << m_name
- << "in directory" << fetchBasePath();
- return false;
- }
- return true;
- }
- QString VNoteFile::fetchAttachmentFolderPath()
- {
- QString folderPath = QDir(fetchBasePath()).filePath(getNotebook()->getAttachmentFolder());
- if (m_attachmentFolder.isEmpty()) {
- m_attachmentFolder = VUtils::getRandomFileName(folderPath);
- }
- folderPath = QDir(folderPath).filePath(m_attachmentFolder);
- if (!QFileInfo::exists(folderPath)) {
- QDir dir;
- if (!dir.mkpath(folderPath)) {
- qWarning() << "fail to create attachment folder of notebook" << m_name << folderPath;
- }
- }
- return folderPath;
- }
- bool VNoteFile::deleteAttachments(bool p_omitMissing)
- {
- if (m_attachments.isEmpty()) {
- return true;
- }
- QVector<QString> attas;
- for (int i = 0; i < m_attachments.size(); ++i) {
- attas.push_back(m_attachments[i].m_name);
- }
- return deleteAttachments(attas, p_omitMissing);
- }
- bool VNoteFile::deleteAttachments(const QVector<QString> &p_names,
- bool p_omitMissing)
- {
- if (p_names.isEmpty()) {
- return true;
- }
- QDir dir(fetchAttachmentFolderPath());
- bool ret = true;
- for (int i = 0; i < p_names.size(); ++i) {
- int idx = findAttachment(p_names[i]);
- if (idx == -1) {
- ret = false;
- continue;
- }
- m_attachments.remove(idx);
- QString filePath = dir.filePath(p_names[i]);
- if (p_omitMissing
- && !QFileInfo::exists(filePath)) {
- // The attachment file does not exist. We skip it to avoid error.
- continue;
- }
- if (!VUtils::deleteFile(getNotebook(), filePath, false)) {
- ret = false;
- qWarning() << "fail to delete attachment" << p_names[i]
- << "for note" << m_name;
- }
- }
- // Delete the attachment folder if m_attachments is empty now.
- if (m_attachments.isEmpty()) {
- dir.cdUp();
- if (!dir.rmdir(m_attachmentFolder)) {
- ret = false;
- qWarning() << "fail to delete attachment folder" << m_attachmentFolder
- << "for note" << m_name;
- }
- }
- if (!getDirectory()->updateFileConfig(this)) {
- ret = false;
- qWarning() << "fail to update config of file" << m_name
- << "in directory" << fetchBasePath();
- }
- return ret;
- }
- int VNoteFile::findAttachment(const QString &p_name, bool p_caseSensitive)
- {
- const QString name = p_caseSensitive ? p_name : p_name.toLower();
- for (int i = 0; i < m_attachments.size(); ++i) {
- QString attaName = p_caseSensitive ? m_attachments[i].m_name
- : m_attachments[i].m_name.toLower();
- if (name == attaName) {
- return i;
- }
- }
- return -1;
- }
- bool VNoteFile::sortAttachments(const QVector<int> &p_sortedIdx)
- {
- V_ASSERT(m_opened);
- V_ASSERT(p_sortedIdx.size() == m_attachments.size());
- auto ori = m_attachments;
- for (int i = 0; i < p_sortedIdx.size(); ++i) {
- m_attachments[i] = ori[p_sortedIdx[i]];
- }
- bool ret = true;
- if (!getDirectory()->updateFileConfig(this)) {
- qWarning() << "fail to reorder attachments in config" << p_sortedIdx;
- m_attachments = ori;
- ret = false;
- }
- return ret;
- }
- bool VNoteFile::renameAttachment(const QString &p_oldName, const QString &p_newName)
- {
- int idx = findAttachment(p_oldName);
- if (idx == -1) {
- return false;
- }
- QDir dir(fetchAttachmentFolderPath());
- if (!dir.rename(p_oldName, p_newName)) {
- qWarning() << "fail to rename attachment file" << p_oldName << p_newName;
- return false;
- }
- m_attachments[idx].m_name = p_newName;
- if (!getDirectory()->updateFileConfig(this)) {
- qWarning() << "fail to rename attachment in config" << p_oldName << p_newName;
- m_attachments[idx].m_name = p_oldName;
- dir.rename(p_newName, p_oldName);
- return false;
- }
- return true;
- }
- QVector<QString> VNoteFile::checkAttachments()
- {
- QVector<QString> missing;
- QDir dir(fetchAttachmentFolderPath());
- for (auto const & atta : m_attachments) {
- QString file = dir.filePath(atta.m_name);
- if (!QFileInfo::exists(file)) {
- missing.push_back(atta.m_name);
- }
- }
- return missing;
- }
- bool VNoteFile::deleteFile(VNoteFile *p_file, QString *p_errMsg)
- {
- Q_ASSERT(!p_file->isOpened());
- bool ret = true;
- QString name = p_file->getName();
- QString path = p_file->fetchPath();
- if (!p_file->deleteFile(p_errMsg)) {
- qWarning() << "fail to delete file" << name << path;
- ret = false;
- }
- VDirectory *dir = p_file->getDirectory();
- Q_ASSERT(dir);
- if (!dir->removeFile(p_file)) {
- qWarning() << "fail to remove file from directory" << name << path;
- VUtils::addErrMsg(p_errMsg, tr("Fail to remove the note from the folder configuration."));
- ret = false;
- }
- delete p_file;
- return ret;
- }
- bool VNoteFile::copyFile(VDirectory *p_destDir,
- const QString &p_destName,
- VNoteFile *p_file,
- bool p_isCut,
- VNoteFile **p_targetFile,
- QString *p_errMsg)
- {
- bool ret = true;
- *p_targetFile = NULL;
- int nrImageCopied = 0;
- bool attachmentFolderCopied = false;
- QString srcPath = QDir::cleanPath(p_file->fetchPath());
- QString destPath = QDir::cleanPath(QDir(p_destDir->fetchPath()).filePath(p_destName));
- if (VUtils::equalPath(srcPath, destPath)) {
- *p_targetFile = p_file;
- return false;
- }
- if (!p_destDir->isOpened()) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to open target folder."));
- return false;
- }
- QString opStr = p_isCut ? tr("cut") : tr("copy");
- VDirectory *srcDir = p_file->getDirectory();
- DocType docType = p_file->getDocType();
- Q_ASSERT(srcDir->isOpened());
- Q_ASSERT(docType == VUtils::docTypeFromName(p_destName));
- // Images to be copied.
- QVector<ImageLink> images;
- if (docType == DocType::Markdown) {
- images = VUtils::fetchImagesFromMarkdownFile(p_file,
- ImageLink::LocalRelativeInternal);
- }
- // Attachments to be copied.
- QString attaFolder = p_file->getAttachmentFolder();
- QString attaFolderPath;
- if (!attaFolder.isEmpty()) {
- attaFolderPath = p_file->fetchAttachmentFolderPath();
- }
- // Copy the note file.
- if (!VUtils::copyFile(srcPath, destPath, p_isCut)) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to %1 the note file.").arg(opStr));
- qWarning() << "fail to" << opStr << "the note file" << srcPath << "to" << destPath;
- return false;
- }
- // Add file to VDirectory.
- VNoteFile *destFile = NULL;
- if (p_isCut) {
- srcDir->removeFile(p_file);
- p_file->setName(p_destName);
- if (p_destDir->addFile(p_file, -1)) {
- destFile = p_file;
- } else {
- destFile = NULL;
- }
- } else {
- destFile = p_destDir->addFile(p_destName, -1);
- }
- if (!destFile) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to add the note to target folder's configuration."));
- return false;
- }
- // Copy images.
- QDir parentDir(destFile->fetchBasePath());
- for (int i = 0; i < images.size(); ++i) {
- const ImageLink &link = images[i];
- if (!QFileInfo::exists(link.m_path)) {
- VUtils::addErrMsg(p_errMsg, tr("Source image %1 does not exist.")
- .arg(link.m_path));
- ret = false;
- continue;
- }
- QString imageFolder = VUtils::directoryNameFromPath(VUtils::basePathFromPath(link.m_path));
- QString destImagePath = QDir(parentDir.filePath(imageFolder)).filePath(VUtils::fileNameFromPath(link.m_path));
- if (VUtils::equalPath(link.m_path, destImagePath)) {
- VUtils::addErrMsg(p_errMsg, tr("Skip image with the same source and target path %1.")
- .arg(link.m_path));
- ret = false;
- continue;
- }
- if (!VUtils::copyFile(link.m_path, destImagePath, p_isCut)) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to %1 image %2 to %3. "
- "Please manually %1 it and modify the note.")
- .arg(opStr).arg(link.m_path).arg(destImagePath));
- ret = false;
- } else {
- ++nrImageCopied;
- qDebug() << opStr << "image" << link.m_path << "to" << destImagePath;
- }
- }
- // Copy attachment folder.
- if (!attaFolderPath.isEmpty()) {
- QDir dir(destFile->fetchBasePath());
- QString folderPath = dir.filePath(destFile->getNotebook()->getAttachmentFolder());
- attaFolder = VUtils::getFileNameWithSequence(folderPath, attaFolder);
- folderPath = QDir(folderPath).filePath(attaFolder);
- // Copy attaFolderPath to folderPath.
- if (!VUtils::copyDirectory(attaFolderPath, folderPath, p_isCut)) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to %1 attachments folder %2 to %3. "
- "Please manually maintain it.")
- .arg(opStr).arg(attaFolderPath).arg(folderPath));
- QVector<VAttachment> emptyAttas;
- destFile->setAttachments(emptyAttas);
- ret = false;
- } else {
- attachmentFolderCopied = true;
- destFile->setAttachmentFolder(attaFolder);
- if (!p_isCut) {
- destFile->setAttachments(p_file->getAttachments());
- }
- }
- if (!p_destDir->updateFileConfig(destFile)) {
- VUtils::addErrMsg(p_errMsg, tr("Fail to update configuration of note %1.")
- .arg(destFile->fetchPath()));
- ret = false;
- }
- }
- qDebug() << "copyFile:" << p_file << "to" << destFile
- << "copied_images:" << nrImageCopied
- << "copied_attachments:" << attachmentFolderCopied;
- *p_targetFile = destFile;
- return ret;
- }
|