diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index bd1e420a..0c3a87f8 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -17,14 +17,14 @@ #include #include -#include "vconfigmanager.h" +#include "vfile.h" extern VConfigManager vconfig; const QVector> VUtils::c_availableLanguages = {QPair("en_US", "Englisth(US)"), QPair("zh_CN", "Chinese")}; -const QString VUtils::c_imageLinkRegExp = QString("\\!\\[([^\\]]*)\\]\\(([^\\)\"]+)\\s*(\".*\")?\\s*\\)"); +const QString VUtils::c_imageLinkRegExp = QString("\\!\\[([^\\]]*)\\]\\(([^\\)\"]+)\\s*(\"(\\\\.|[^\"\\)])*\")?\\s*\\)"); VUtils::VUtils() { @@ -113,71 +113,120 @@ void VUtils::processStyle(QString &style, const QVector } } -bool VUtils::isMarkdown(const QString &name) +bool VUtils::isMarkdown(const QString &p_fileName) { const QVector mdPostfix({"md", "markdown", "mkd"}); - QStringList list = name.split('.', QString::SkipEmptyParts); - if (list.isEmpty()) { - return false; - } - const QString &postfix = list.last(); + QFileInfo info(p_fileName); + QString suffix = info.suffix(); + for (int i = 0; i < mdPostfix.size(); ++i) { - if (postfix == mdPostfix[i]) { + if (suffix == mdPostfix[i]) { return true; } } + return false; } -QString VUtils::fileNameFromPath(const QString &path) +QString VUtils::fileNameFromPath(const QString &p_path) { - if (path.isEmpty()) { - return path; + if (p_path.isEmpty()) { + return p_path; } - return QFileInfo(QDir::cleanPath(path)).fileName(); + + return QFileInfo(QDir::cleanPath(p_path)).fileName(); } -QString VUtils::basePathFromPath(const QString &path) +QString VUtils::basePathFromPath(const QString &p_path) { - return QFileInfo(path).path(); + if (p_path.isEmpty()) { + return p_path; + } + + return QFileInfo(QDir::cleanPath(p_path)).path(); } -// Collect image links like ![](images/xx.jpg) -QVector VUtils::imagesFromMarkdownFile(const QString &filePath) +QVector VUtils::fetchImagesFromMarkdownFile(VFile *p_file, + ImageLink::ImageLinkType p_type) { - Q_ASSERT(isMarkdown(filePath)); - QVector images; - if (filePath.isEmpty()) { + V_ASSERT(p_file->getDocType() == DocType::Markdown); + QVector images; + + bool isOpened = p_file->isOpened(); + if (!isOpened && !p_file->open()) { return images; } - QString basePath = basePathFromPath(filePath); - QString text = readFileFromDisk(filePath); - QRegExp regExp("\\!\\[[^\\]]*\\]\\((images/[^/\\)]+)\\)"); - int pos = 0; + const QString &text = p_file->getContent(); + if (text.isEmpty()) { + if (!isOpened) { + p_file->close(); + } + + return images; + } + + QRegExp regExp(c_imageLinkRegExp); + QString basePath = p_file->retriveBasePath(); + int pos = 0; while (pos < text.size() && (pos = regExp.indexIn(text, pos)) != -1) { - Q_ASSERT(regExp.captureCount() == 1); - qDebug() << regExp.capturedTexts()[0] << regExp.capturedTexts()[1]; - images.append(QDir(basePath).filePath(regExp.capturedTexts()[1])); + QString imageUrl = regExp.capturedTexts()[2].trimmed(); + + ImageLink link; + QFileInfo info(basePath, imageUrl); + if (info.exists()) { + if (info.isNativePath()) { + // Local file. + link.m_path = QDir::cleanPath(info.absoluteFilePath()); + + if (QDir::isRelativePath(imageUrl)) { + link.m_type = p_file->isInternalImageFolder(VUtils::basePathFromPath(link.m_path)) ? + ImageLink::LocalRelativeInternal : ImageLink::LocalRelativeExternal; + } else { + link.m_type = ImageLink::LocalAbsolute; + } + } else { + link.m_type = ImageLink::Resource; + link.m_path = imageUrl; + } + } else { + QUrl url(imageUrl); + link.m_path = url.toString(); + link.m_type = ImageLink::Remote; + } + + if (link.m_type & p_type) { + images.push_back(link); + qDebug() << "fetch one image:" << link.m_type << link.m_path; + } + pos += regExp.matchedLength(); } + + if (!isOpened) { + p_file->close(); + } + return images; } -void VUtils::makeDirectory(const QString &path) +bool VUtils::makePath(const QString &p_path) { - if (path.isEmpty()) { - return; + if (p_path.isEmpty()) { + return true; } - // mkdir will return false if it already exists - QString basePath = basePathFromPath(path); - QString dirName = directoryNameFromPath(path); - QDir dir(basePath); - if (dir.mkdir(dirName)) { - qDebug() << "mkdir" << path; + bool ret = true; + QDir dir; + if (dir.mkpath(p_path)) { + qDebug() << "make path" << p_path; + } else { + qWarning() << "fail to make path" << p_path; + ret = false; } + + return ret; } ClipboardOpType VUtils::opTypeInClipboard() diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 46f93ab6..ea6b967c 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -11,6 +11,7 @@ #include "vconstants.h" class QKeyEvent; +class VFile; #if !defined(V_ASSERT) #define V_ASSERT(cond) ((!(cond)) ? qt_assert(#cond, __FILE__, __LINE__) : qt_noop()) @@ -22,6 +23,22 @@ enum class MessageBoxType Danger = 1 }; +struct ImageLink +{ + enum ImageLinkType + { + LocalRelativeInternal = 0x1, + LocalRelativeExternal = 0x2, + LocalAbsolute = 0x4, + Resource = 0x8, + Remote = 0x10, + All = 0xffff + }; + + QString m_path; + ImageLinkType m_type; +}; + class VUtils { public: @@ -36,12 +53,29 @@ public: static QString generateCopiedFileName(const QString &p_dirPath, const QString &p_fileName); static QString generateCopiedDirName(const QString &p_parentDirPath, const QString &p_dirName); static void processStyle(QString &style, const QVector > &varMap); - static bool isMarkdown(const QString &fileName); - static inline QString directoryNameFromPath(const QString& path); - static QString fileNameFromPath(const QString &path); - static QString basePathFromPath(const QString &path); - static QVector imagesFromMarkdownFile(const QString &filePath); - static void makeDirectory(const QString &path); + static bool isMarkdown(const QString &p_fileName); + + // Return the last directory name of @p_path. + static inline QString directoryNameFromPath(const QString& p_path); + + // Return the file name of @p_path. + // /home/tamlok/abc, /home/tamlok/abc/ will both return abc. + static QString fileNameFromPath(const QString &p_path); + + // Return the base path of @p_path. + // /home/tamlok/abc, /home/tamlok/abc/ will both return /home/tamlok. + static QString basePathFromPath(const QString &p_path); + + // Fetch all the image links (including those in code blocks) in markdown file p_file. + // @p_type to filter the links returned. + // Need to open p_file and will close it if it is originally closed. + static QVector fetchImagesFromMarkdownFile(VFile *p_file, + ImageLink::ImageLinkType p_type = ImageLink::All); + + // Create directories along the @p_path. + // @p_path could be /home/tamlok/abc, /home/tamlok/abc/. + static bool makePath(const QString &p_path); + static ClipboardOpType opTypeInClipboard(); static bool copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut); static bool copyDirectory(const QString &p_srcDirPath, const QString &p_destDirPath, bool p_isCut); @@ -59,11 +93,12 @@ public: static QString getLocale(); // Regular expression for image link. - // ![image title]( http://github.com/tamlok/vnote.jpg "alt text" ) + // ![image title]( http://github.com/tamlok/vnote.jpg "alt \" text" ) // Captured texts (need to be trimmed): // 1. Image Alt Text (Title); // 2. Image URL; // 3. Image Optional Title with double quotes; + // 4. Unused; static const QString c_imageLinkRegExp; private: @@ -71,9 +106,9 @@ private: static const QVector> c_availableLanguages; }; -inline QString VUtils::directoryNameFromPath(const QString &path) +inline QString VUtils::directoryNameFromPath(const QString &p_path) { - return fileNameFromPath(path); + return fileNameFromPath(p_path); } #endif // VUTILS_H diff --git a/src/vdirectory.cpp b/src/vdirectory.cpp index 09dd097f..64f4c37f 100644 --- a/src/vdirectory.cpp +++ b/src/vdirectory.cpp @@ -7,6 +7,8 @@ #include "vfile.h" #include "utils/vutils.h" +extern VConfigManager vconfig; + VDirectory::VDirectory(VNotebook *p_notebook, const QString &p_name, QObject *p_parent) : QObject(p_parent), m_notebook(p_notebook), m_name(p_name), m_opened(false), @@ -472,9 +474,10 @@ VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName, DocType docType = p_srcFile->getDocType(); DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html; - QVector images; + QVector images; if (docType == DocType::Markdown) { - images = VUtils::imagesFromMarkdownFile(srcPath); + images = VUtils::fetchImagesFromMarkdownFile(p_srcFile, + ImageLink::LocalRelativeInternal); } // Copy the file @@ -505,35 +508,71 @@ VFile *VDirectory::copyFile(VDirectory *p_destDir, const QString &p_destName, destFile->convert(docType, newDocType); } - // We need to copy images when it is still markdown + // We need to copy internal images when it is still markdown. if (!images.isEmpty()) { if (newDocType == DocType::Markdown) { - QString dirPath = destFile->retriveImagePath(); - VUtils::makeDirectory(dirPath); + QString parentPath = destFile->retriveBasePath(); int nrPasted = 0; for (int i = 0; i < images.size(); ++i) { - if (!QFile(images[i]).exists()) { + const ImageLink &link = images[i]; + if (!QFileInfo::exists(link.m_path)) { continue; } - QString destImagePath = QDir(dirPath).filePath(VUtils::fileNameFromPath(images[i])); - // Copy or Cut the images accordingly. - if (VUtils::copyFile(images[i], destImagePath, p_cut)) { - nrPasted++; + QString errStr; + bool ret = true; + + QString imageFolder = VUtils::directoryNameFromPath(VUtils::basePathFromPath(link.m_path)); + QString destImagePath = QDir(parentPath).filePath(imageFolder); + ret = VUtils::makePath(destImagePath); + if (!ret) { + errStr = tr("Fail to create image folder %2.") + .arg(vconfig.c_dataTextStyle).arg(destImagePath); } else { + destImagePath = QDir(destImagePath).filePath(VUtils::fileNameFromPath(link.m_path)); + + // Copy or Cut the images accordingly. + if (destImagePath == link.m_path) { + ret = false; + } else { + ret = VUtils::copyFile(link.m_path, destImagePath, p_cut); + } + + if (ret) { + qDebug() << (p_cut ? "Cut" : "Copy") << "image" + << link.m_path << "->" << destImagePath; + + nrPasted++; + } else { + errStr = tr("Please check if there already exists a file %2 " + "and then manually copy it and modify the note accordingly.") + .arg(vconfig.c_dataTextStyle).arg(destImagePath); + } + } + + if (!ret) { VUtils::showMessage(QMessageBox::Warning, tr("Warning"), - tr("Fail to copy image %1.").arg(images[i]), - tr("Please check if there already exists a file with the same name and then manually copy it."), - QMessageBox::Ok, QMessageBox::Ok, NULL); + tr("Fail to copy image %2 while " + "%5 note %4.") + .arg(vconfig.c_dataTextStyle).arg(link.m_path) + .arg(vconfig.c_dataTextStyle).arg(srcPath) + .arg(p_cut ? tr("moving") : tr("copying")), + errStr, QMessageBox::Ok, QMessageBox::Ok, NULL); } } - qDebug() << "pasted" << nrPasted << "images sucessfully"; + + qDebug() << "pasted" << nrPasted << "images"; } else { - // Delete the images + // Delete the images. + int deleted = 0; for (int i = 0; i < images.size(); ++i) { - QFile file(images[i]); - file.remove(); + QFile file(images[i].m_path); + if (file.remove()) { + ++deleted; + } } + + qDebug() << "delete" << deleted << "images since it is not Markdown any more for" << srcPath; } } diff --git a/src/vdirectory.h b/src/vdirectory.h index a6ccb220..4375a7b1 100644 --- a/src/vdirectory.h +++ b/src/vdirectory.h @@ -38,10 +38,12 @@ public: VDirectory *addSubDirectory(const QString &p_name, int p_index); void deleteFile(VFile *p_file); bool rename(const QString &p_name); + // Copy @p_srcFile to @p_destDir, setting new name to @p_destName. // @p_cut: copy or cut. Returns the dest VFile. static VFile *copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_srcFile, bool p_cut); + static VDirectory *copyDirectory(VDirectory *p_destDir, const QString &p_destName, VDirectory *p_srcDir, bool p_cut); diff --git a/src/vfile.cpp b/src/vfile.cpp index 1e853e61..3e0cc1ed 100644 --- a/src/vfile.cpp +++ b/src/vfile.cpp @@ -45,9 +45,9 @@ void VFile::close() void VFile::deleteDiskFile() { - Q_ASSERT(parent()); + V_ASSERT(parent()); - // Delete local images in ./images if it is Markdown + // Delete local images if it is Markdown. if (m_docType == DocType::Markdown) { deleteLocalImages(); } @@ -97,17 +97,19 @@ void VFile::setModified(bool p_modified) void VFile::deleteLocalImages() { - Q_ASSERT(m_docType == DocType::Markdown); - QString filePath = retrivePath(); - QVector images = VUtils::imagesFromMarkdownFile(filePath); + V_ASSERT(m_docType == DocType::Markdown); + + QVector images = VUtils::fetchImagesFromMarkdownFile(this, + ImageLink::LocalRelativeInternal); int deleted = 0; for (int i = 0; i < images.size(); ++i) { - QFile file(images[i]); + QFile file(images[i].m_path); if (file.remove()) { ++deleted; } } - qDebug() << "delete" << deleted << "images for" << filePath; + + qDebug() << "delete" << deleted << "images for" << retrivePath(); } void VFile::setName(const QString &p_name) @@ -151,6 +153,11 @@ QString VFile::getNotebookName() const return getDirectory()->getNotebookName(); } +const VNotebook *VFile::getNotebook() const +{ + return getDirectory()->getNotebook(); +} + VNotebook *VFile::getNotebook() { return getDirectory()->getNotebook(); @@ -175,7 +182,7 @@ QString VFile::retriveBasePath() const QString VFile::retriveImagePath() const { - return QDir(retriveBasePath()).filePath("images"); + return QDir(retriveBasePath()).filePath(getNotebook()->getImageFolder()); } void VFile::setContent(const QString &p_content) @@ -202,3 +209,8 @@ FileType VFile::getType() const { return m_type; } + +bool VFile::isInternalImageFolder(const QString &p_path) const +{ + return VUtils::basePathFromPath(p_path) == getDirectory()->retrivePath(); +} diff --git a/src/vfile.h b/src/vfile.h index 58cb93f2..280cab0e 100644 --- a/src/vfile.h +++ b/src/vfile.h @@ -28,6 +28,7 @@ public: DocType getDocType() const; const QString &getContent() const; virtual void setContent(const QString &p_content); + virtual const VNotebook *getNotebook() const; virtual VNotebook *getNotebook(); virtual QString getNotebookName() const; virtual QString retrivePath() const; @@ -39,13 +40,19 @@ public: bool isOpened() const; FileType getType() const; + // Whether the directory @p_path is an internal image folder of this file. + // It is true only when the folder is in the same directory as the parent + // directory of this file. + virtual bool isInternalImageFolder(const QString &p_path) const; + public slots: void setModified(bool p_modified); protected: // Delete the file and corresponding images void deleteDiskFile(); - // Delete local images in ./images of DocType::Markdown + + // Delete local images of DocType::Markdown. void deleteLocalImages(); QString m_name; diff --git a/src/vimagepreviewer.cpp b/src/vimagepreviewer.cpp index db612679..6aa1b618 100644 --- a/src/vimagepreviewer.cpp +++ b/src/vimagepreviewer.cpp @@ -195,7 +195,7 @@ QString VImagePreviewer::fetchImagePathToPreview(const QString &p_text) if (info.exists()) { if (info.isNativePath()) { // Local file. - imagePath = info.absoluteFilePath(); + imagePath = QDir::cleanPath(info.absoluteFilePath()); } else { imagePath = imageUrl; } diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 3101ebea..837e6bd1 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -90,7 +90,7 @@ void VMdEdit::saveFile() void VMdEdit::reloadFile() { const QString &content = m_file->getContent(); - Q_ASSERT(content.indexOf(QChar::ObjectReplacementCharacter) == -1); + V_ASSERT(content.indexOf(QChar::ObjectReplacementCharacter) == -1); setPlainText(content); setModified(false); } @@ -171,61 +171,74 @@ void VMdEdit::insertFromMimeData(const QMimeData *source) VEdit::insertFromMimeData(source); } -void VMdEdit::imageInserted(const QString &p_name) +void VMdEdit::imageInserted(const QString &p_path) { - m_insertedImages.append(p_name); + ImageLink link; + link.m_path = p_path; + link.m_type = ImageLink::LocalRelativeInternal; + + m_insertedImages.append(link); } void VMdEdit::initInitImages() { - m_initImages = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); + m_initImages = VUtils::fetchImagesFromMarkdownFile(m_file, + ImageLink::LocalRelativeInternal); } void VMdEdit::clearUnusedImages() { - QVector images = VUtils::imagesFromMarkdownFile(m_file->retrivePath()); + QVector images = VUtils::fetchImagesFromMarkdownFile(m_file, + ImageLink::LocalRelativeInternal); if (!m_insertedImages.isEmpty()) { - QVector imageNames(images.size()); - for (int i = 0; i < imageNames.size(); ++i) { - imageNames[i] = VUtils::fileNameFromPath(images[i]); - } - - QDir dir = QDir(m_file->retriveImagePath()); for (int i = 0; i < m_insertedImages.size(); ++i) { - QString name = m_insertedImages[i]; + const ImageLink &link = m_insertedImages[i]; + + V_ASSERT(link.m_type == ImageLink::LocalRelativeInternal); + int j; - for (j = 0; j < imageNames.size(); ++j) { - if (name == imageNames[j]) { + for (j = 0; j < images.size(); ++j) { + if (link.m_path == images[j].m_path) { break; } } - // Delete it - if (j == imageNames.size()) { - QString imagePath = dir.filePath(name); - QFile(imagePath).remove(); - qDebug() << "delete inserted image" << imagePath; + // This inserted image is no longer in the file. + if (j == images.size()) { + if (!QFile(link.m_path).remove()) { + qWarning() << "fail to delete unused inserted image" << link.m_path; + } else { + qDebug() << "delete unused inserted image" << link.m_path; + } } } + m_insertedImages.clear(); } for (int i = 0; i < m_initImages.size(); ++i) { - QString imagePath = m_initImages[i]; + const ImageLink &link = m_initImages[i]; + + V_ASSERT(link.m_type == ImageLink::LocalRelativeInternal); + int j; for (j = 0; j < images.size(); ++j) { - if (imagePath == images[j]) { + if (link.m_path == images[j].m_path) { break; } } - // Delete it + // Original local relative image is no longer in the file. if (j == images.size()) { - QFile(imagePath).remove(); - qDebug() << "delete existing image" << imagePath; + if (!QFile(link.m_path).remove()) { + qWarning() << "fail to delete unused original image" << link.m_path; + } else { + qDebug() << "delete unused original image" << link.m_path; + } } } + m_initImages.clear(); } diff --git a/src/vmdedit.h b/src/vmdedit.h index 7358acaf..f5c61f1b 100644 --- a/src/vmdedit.h +++ b/src/vmdedit.h @@ -10,6 +10,7 @@ #include "vtoc.h" #include "veditoperations.h" #include "vconfigmanager.h" +#include "utils/vutils.h" class HGMarkdownHighlighter; class VCodeBlockHighlightHelper; @@ -27,8 +28,9 @@ public: void saveFile() Q_DECL_OVERRIDE; void reloadFile() Q_DECL_OVERRIDE; - // An image has been inserted. - void imageInserted(const QString &p_name); + // An image has been inserted. The image is relative. + // @p_path is the absolute path of the inserted image. + void imageInserted(const QString &p_path); // Scroll to m_headers[p_headerIndex]. void scrollToHeader(int p_headerIndex); @@ -67,8 +69,13 @@ private: HGMarkdownHighlighter *m_mdHighlighter; VCodeBlockHighlightHelper *m_cbHighlighter; VImagePreviewer *m_imagePreviewer; - QVector m_insertedImages; - QVector m_initImages; + + // Image links inserted while editing. + QVector m_insertedImages; + + // Image links right at the beginning of the edit. + QVector m_initImages; + QVector m_headers; }; diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index 6b94596f..1316926a 100644 --- a/src/vmdeditoperations.cpp +++ b/src/vmdeditoperations.cpp @@ -55,49 +55,80 @@ void VMdEditOperations::insertImageFromQImage(const QString &title, const QStrin const QImage &image) { QString fileName = VUtils::generateImageFileName(path, title); - qDebug() << "insert image" << path << title << fileName; QString filePath = QDir(path).filePath(fileName); - Q_ASSERT(!QFile(filePath).exists()); - VUtils::makeDirectory(path); - bool ret = image.save(filePath); + V_ASSERT(!QFile(filePath).exists()); + + QString errStr; + bool ret = VUtils::makePath(path); if (!ret) { - QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Fail to save image %1.").arg(filePath), - QMessageBox::Ok, (QWidget *)m_editor); - msgBox.exec(); + errStr = tr("Fail to create image folder %2.") + .arg(vconfig.c_dataTextStyle).arg(path); + } else { + ret = image.save(filePath); + if (!ret) { + errStr = tr("Fail to save image %2.") + .arg(vconfig.c_dataTextStyle).arg(filePath); + } + } + + if (!ret) { + VUtils::showMessage(QMessageBox::Warning, tr("Warning"), + tr("Fail to insert image %2.").arg(vconfig.c_dataTextStyle).arg(title), + errStr, + QMessageBox::Ok, + QMessageBox::Ok, + (QWidget *)m_editor); return; } - QString md = QString("![%1](images/%2)").arg(title).arg(fileName); + QString md = QString("![%1](%2/%3)").arg(title).arg(VUtils::directoryNameFromPath(path)).arg(fileName); insertTextAtCurPos(md); + qDebug() << "insert image" << title << filePath; + VMdEdit *mdEditor = dynamic_cast(m_editor); Q_ASSERT(mdEditor); - mdEditor->imageInserted(fileName); + mdEditor->imageInserted(filePath); } void VMdEditOperations::insertImageFromPath(const QString &title, const QString &path, const QString &oriImagePath) { QString fileName = VUtils::generateImageFileName(path, title, QFileInfo(oriImagePath).suffix()); - qDebug() << "insert image" << path << title << fileName << oriImagePath; QString filePath = QDir(path).filePath(fileName); - Q_ASSERT(!QFile(filePath).exists()); - VUtils::makeDirectory(path); - bool ret = QFile::copy(oriImagePath, filePath); + V_ASSERT(!QFile(filePath).exists()); + + QString errStr; + bool ret = VUtils::makePath(path); if (!ret) { - qWarning() << "fail to copy" << oriImagePath << "to" << filePath; - QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Fail to save image %1.").arg(filePath), - QMessageBox::Ok, (QWidget *)m_editor); - msgBox.exec(); + errStr = tr("Fail to create image folder %2.") + .arg(vconfig.c_dataTextStyle).arg(path); + } else { + ret = QFile::copy(oriImagePath, filePath); + if (!ret) { + errStr = tr("Fail to copy image %2.") + .arg(vconfig.c_dataTextStyle).arg(filePath); + } + } + + if (!ret) { + VUtils::showMessage(QMessageBox::Warning, tr("Warning"), + tr("Fail to insert image %2.").arg(vconfig.c_dataTextStyle).arg(title), + errStr, + QMessageBox::Ok, + QMessageBox::Ok, + (QWidget *)m_editor); return; } - QString md = QString("![%1](images/%2)").arg(title).arg(fileName); + QString md = QString("![%1](%2/%3)").arg(title).arg(VUtils::directoryNameFromPath(path)).arg(fileName); insertTextAtCurPos(md); + qDebug() << "insert image" << title << filePath; + VMdEdit *mdEditor = dynamic_cast(m_editor); Q_ASSERT(mdEditor); - mdEditor->imageInserted(fileName); + mdEditor->imageInserted(filePath); } bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl) diff --git a/src/vmdeditoperations.h b/src/vmdeditoperations.h index d83b1038..68530550 100644 --- a/src/vmdeditoperations.h +++ b/src/vmdeditoperations.h @@ -26,7 +26,12 @@ private slots: private: void insertImageFromPath(const QString &title, const QString &path, const QString &oriImagePath); + + // @title: title of the inserted image; + // @path: the image folder path to insert the image in; + // @image: the image to be inserted; void insertImageFromQImage(const QString &title, const QString &path, const QImage &image); + void setKeyState(KeyState p_state); // Key press handlers. diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index 9b52afbd..e16e7705 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -6,9 +6,12 @@ #include "vconfigmanager.h" #include "vfile.h" +const QString VNotebook::c_defaultImageFolder = "_v_images"; + VNotebook::VNotebook(const QString &name, const QString &path, QObject *parent) - : QObject(parent), m_name(name), m_path(path) + : QObject(parent), m_name(name), m_imageFolder(c_defaultImageFolder) { + m_path = QDir::cleanPath(path); m_rootDir = new VDirectory(this, VUtils::directoryNameFromPath(path)); } @@ -116,3 +119,8 @@ bool VNotebook::containsFile(const VFile *p_file) const { return m_rootDir->containsFile(p_file); } + +const QString &VNotebook::getImageFolder() const +{ + return m_imageFolder; +} diff --git a/src/vnotebook.h b/src/vnotebook.h index 51a8ddd4..0115d03e 100644 --- a/src/vnotebook.h +++ b/src/vnotebook.h @@ -30,12 +30,22 @@ public: QObject *p_parent = 0); static bool deleteNotebook(VNotebook *p_notebook, bool p_deleteFiles); + const QString &getImageFolder() const; + signals: void contentChanged(); private: QString m_name; QString m_path; + + // Folder name to store images. + // VNote will store images in this folder within the same directory of the note. + QString m_imageFolder; + + // Default folder name to store images of all the notes within this notebook. + static const QString c_defaultImageFolder; + // Parent is NULL for root directory VDirectory *m_rootDir; }; diff --git a/src/vorphanfile.cpp b/src/vorphanfile.cpp index bdc3b67d..ba6363aa 100644 --- a/src/vorphanfile.cpp +++ b/src/vorphanfile.cpp @@ -87,3 +87,8 @@ void VOrphanFile::setContent(const QString & /* p_content */) { V_ASSERT(false); } + +bool VOrphanFile::isInternalImageFolder(const QString &p_path) const +{ + return VUtils::basePathFromPath(p_path) == VUtils::basePathFromPath(m_path); +} diff --git a/src/vorphanfile.h b/src/vorphanfile.h index 87218ccb..7848880d 100644 --- a/src/vorphanfile.h +++ b/src/vorphanfile.h @@ -10,21 +10,22 @@ class VOrphanFile : public VFile Q_OBJECT public: VOrphanFile(const QString &p_path, QObject *p_parent); - bool open(); - QString retrivePath() const; - QString retriveRelativePath() const; - QString retriveBasePath() const; - VDirectory *getDirectory(); - const VDirectory *getDirectory() const; - QString getNotebookName() const; - VNotebook *getNotebook(); + bool open() Q_DECL_OVERRIDE; + QString retrivePath() const Q_DECL_OVERRIDE; + QString retriveRelativePath() const Q_DECL_OVERRIDE; + QString retriveBasePath() const Q_DECL_OVERRIDE; + VDirectory *getDirectory() Q_DECL_OVERRIDE; + const VDirectory *getDirectory() const Q_DECL_OVERRIDE; + QString getNotebookName() const Q_DECL_OVERRIDE; + VNotebook *getNotebook() Q_DECL_OVERRIDE; private: - bool save(); - void convert(DocType p_curType, DocType p_targetType); - void setName(const QString &p_name); - QString retriveImagePath() const; - void setContent(const QString &p_content); + bool save() Q_DECL_OVERRIDE; + void convert(DocType p_curType, DocType p_targetType) Q_DECL_OVERRIDE; + void setName(const QString &p_name) Q_DECL_OVERRIDE; + QString retriveImagePath() const Q_DECL_OVERRIDE; + void setContent(const QString &p_content) Q_DECL_OVERRIDE; + bool isInternalImageFolder(const QString &p_path) const Q_DECL_OVERRIDE; QString m_path; friend class VDirectory;