image related fixes

- Support previewing cross-line image link;
- Do not consider image title when generating image name and use current
time at the front to make it easy to sort.
This commit is contained in:
Le Tan 2018-10-14 11:59:25 +08:00
parent 94fd430c06
commit 1b95b636e7
4 changed files with 69 additions and 47 deletions

View File

@ -43,7 +43,7 @@ extern VConfigManager *g_config;
QVector<QPair<QString, QString>> VUtils::s_availableLanguages; QVector<QPair<QString, QString>> VUtils::s_availableLanguages;
const QString VUtils::c_imageLinkRegExp = QString("\\!\\[([^\\]]*)\\]" const QString VUtils::c_imageLinkRegExp = QString("\\!\\[([^\\[\\]]*)\\]"
"\\(\\s*" "\\(\\s*"
"([^\\)\"'\\s]+)" "([^\\)\"'\\s]+)"
"(\\s*(\"[^\"\\)\\n]*\")|('[^'\\)\\n]*'))?" "(\\s*(\"[^\"\\)\\n]*\")|('[^'\\)\\n]*'))?"
@ -158,33 +158,30 @@ QString VUtils::generateImageFileName(const QString &path,
const QString &title, const QString &title,
const QString &format) const QString &format)
{ {
QRegExp regExp("\\W"); const QChar sep('_');
QString baseName(title.toLower());
// Remove non-character chars. QString baseName(g_config->getImageNamePrefix());
baseName.remove(regExp); if (!baseName.isEmpty()
&& !(baseName.size() == 1 && baseName[0] == sep)) {
// Constrain the length of the name. baseName += sep;
baseName.truncate(10);
baseName.prepend(g_config->getImageNamePrefix());
if (!baseName.isEmpty()) {
baseName.append('_');
} }
// Add current time and random number to make the name be most likely unique // Add current time at fixed length.
baseName += QString::number(QDateTime::currentDateTime().toTime_t()) baseName += QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz");
+ '_'
+ QString::number(qrand());
QDir dir(path); // Add random number to make the name be most likely unique.
QString imageName = baseName + "." + format.toLower(); baseName += (sep + QString::number(qrand()));
QString suffix;
if (!format.isEmpty()) {
suffix = "." + format.toLower();
}
QString imageName(baseName + suffix);
int index = 1; int index = 1;
QDir dir(path);
while (fileExists(dir, imageName, true)) { while (fileExists(dir, imageName, true)) {
imageName = QString("%1_%2.%3").arg(baseName).arg(index++) imageName = QString("%1_%2%3").arg(baseName).arg(index++).arg(suffix);
.arg(format.toLower());
} }
return imageName; return imageName;
@ -1016,11 +1013,12 @@ QString VUtils::getRandomFileName(const QString &p_directory)
{ {
Q_ASSERT(!p_directory.isEmpty()); Q_ASSERT(!p_directory.isEmpty());
QString name; QString baseName(QDateTime::currentDateTime().toString("yyyyMMddHHmmsszzz"));
QDir dir(p_directory); QDir dir(p_directory);
QString name;
do { do {
name = QString::number(QDateTime::currentDateTimeUtc().toTime_t()); name = baseName + '_' + QString::number(qrand());
name = name + '_' + QString::number(qrand());
} while (fileExists(dir, name, true)); } while (fileExists(dir, name, true));
return name; return name;
@ -1826,3 +1824,8 @@ QTemporaryFile *VUtils::createTemporaryFile(QString p_suffix)
+ xx + xx
+ p_suffix); + p_suffix);
} }
QString VUtils::purifyImageTitle(QString p_title)
{
return p_title.remove(QRegExp("[\\r\\n\\[\\]]"));
}

View File

@ -390,6 +390,8 @@ public:
static QTemporaryFile *createTemporaryFile(QString p_suffix); static QTemporaryFile *createTemporaryFile(QString p_suffix);
static QString purifyImageTitle(QString p_title);
// Regular expression for image link. // Regular expression for image link.
// ![image title]( http://github.com/tamlok/vnote.jpg "alt text" =200x100) // ![image title]( http://github.com/tamlok/vnote.jpg "alt text" =200x100)
// Captured texts (need to be trimmed): // Captured texts (need to be trimmed):

View File

@ -2055,7 +2055,7 @@ void VMdEditor::replaceTextWithLocalImages(QString &p_text)
continue; continue;
} }
QString imageTitle = regExp.cap(1).trimmed(); QString imageTitle = VUtils::purifyImageTitle(regExp.cap(1).trimmed());
QString imageUrl = regExp.cap(2).trimmed(); QString imageUrl = regExp.cap(2).trimmed();
const int maxUrlLength = 100; const int maxUrlLength = 100;

View File

@ -136,41 +136,58 @@ void VPreviewManager::fetchImageLinksFromRegions(QVector<VElementRegion> p_image
for (int i = 0; i < p_imageRegions.size(); ++i) { for (int i = 0; i < p_imageRegions.size(); ++i) {
const VElementRegion &reg = p_imageRegions[i]; const VElementRegion &reg = p_imageRegions[i];
QTextBlock block = doc->findBlock(reg.m_startPos); QTextBlock firstBlock = doc->findBlock(reg.m_startPos);
if (!block.isValid()) { if (!firstBlock.isValid()) {
continue; continue;
} }
int blockStart = block.position(); // Image link may cross multiple regions.
int blockEnd = blockStart + block.length() - 1; QTextBlock lastBlock = doc->findBlock(reg.m_endPos - 1);
QString text = block.text(); if (!lastBlock.isValid()) {
// Since the image links update signal is emitted after a timer, during which
// the content may be changed.
if (reg.m_endPos > blockEnd) {
continue; continue;
} }
ImageLinkInfo info(reg.m_startPos, int firstBlockStart = firstBlock.position();
int lastBlockStart = lastBlock.position();
int lastBlockEnd = lastBlockStart + lastBlock.length() - 1;
QString text;
if (firstBlock.blockNumber() == lastBlock.blockNumber()) {
text = firstBlock.text().mid(reg.m_startPos - firstBlockStart,
reg.m_endPos - reg.m_startPos);
} else {
text = firstBlock.text().mid(reg.m_startPos - firstBlockStart);
QTextBlock block = firstBlock.next();
while (block.isValid() && block.blockNumber() < lastBlock.blockNumber()) {
text += "\n" + block.text();
block = block.next();
}
text += "\n" + lastBlock.text().left(reg.m_endPos - lastBlockStart);
}
// Preview the image at the last block.
ImageLinkInfo info(qMax(reg.m_startPos, lastBlockStart),
reg.m_endPos, reg.m_endPos,
blockStart, lastBlockStart,
block.blockNumber(), lastBlock.blockNumber(),
calculateBlockMargin(block, m_editor->tabStopWidthW())); calculateBlockMargin(firstBlock, m_editor->tabStopWidthW()));
if ((reg.m_startPos == blockStart if ((reg.m_startPos == firstBlockStart
|| isAllSpaces(text, 0, reg.m_startPos - blockStart)) || isAllSpaces(firstBlock.text(), 0, reg.m_startPos - firstBlockStart))
&& (reg.m_endPos == blockEnd && (reg.m_endPos == lastBlockEnd
|| isAllSpaces(text, reg.m_endPos - blockStart, blockEnd - blockStart))) { || isAllSpaces(lastBlock.text(),
reg.m_endPos - lastBlockStart,
lastBlockEnd - lastBlockStart))) {
// Image block. // Image block.
info.m_isBlock = true; info.m_isBlock = true;
fetchImageInfoToPreview(text, info);
} else { } else {
// Inline image. // Inline image.
info.m_isBlock = false; info.m_isBlock = false;
fetchImageInfoToPreview(text.mid(reg.m_startPos - blockStart,
reg.m_endPos - reg.m_startPos),
info);
} }
fetchImageInfoToPreview(text, info);
if (info.m_linkUrl.isEmpty() || info.m_linkShortUrl.isEmpty()) { if (info.m_linkUrl.isEmpty() || info.m_linkShortUrl.isEmpty()) {
continue; continue;
} }