Rev 24743 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
/***************************************************************************
-------------------
begin : Wed Aug 19 2020
copyright : (C) 2020 by Craig Bradney
email : cbradney@scribus.info
***************************************************************************/
#include "markdownim.h"
#include <QApplication>
#include <QByteArray>
#include <QTextBlock>
#include <QTextBlockFormat>
#include <QTextCharFormat>
#include <QTextDocument>
#include <QTextFrameFormat>
#include <QTextList>
#include <QTextListFormat>
#include "prefsmanager.h"
#include "scribus.h"
#include "scribusdoc.h"
#include "styles/charstyle.h"
#include "styles/paragraphstyle.h"
QString FileFormatName()
{
return QObject::tr("MarkDown Document");
}
QStringList FileExtensions()
{
return QStringList("md");
}
void GetText2(const QString& filename, const QString& /*encoding*/, bool textOnly, bool prefix, bool append, PageItem *textItem)
{
MarkDownIm* markdownim = new MarkDownIm(filename, textItem, textOnly, prefix, append);
delete markdownim;
}
MarkDownIm::MarkDownIm(const QString& fileName, PageItem *textItem, bool textOnly, bool prefix, bool append)
: m_Doc(textItem->doc()),
m_item(textItem),
m_prefixName(prefix),
m_append(append),
m_textOnly(textOnly)
{
QFile f(fileName);
if (!f.open(QIODevice::ReadOnly))
return;
QByteArray data = f.readAll();
f.close();
m_importedText.setMarkdown(data, QTextDocument::MarkdownDialectGitHub);
if (!append)
{
QString defaultParagraphStyle = CommonStrings::DefaultParagraphStyle;
ParagraphStyle newStyle;
newStyle.setDefaultStyle(false);
newStyle.setParent(defaultParagraphStyle);
m_item->itemText.clear();
m_item->itemText.setDefaultStyle(newStyle);
}
parseMarkDown();
m_item->itemText.trim();
m_item->itemText.invalidateLayout();
}
void MarkDownIm::parseMarkDown()
{
struct styleStruct
{
int start { 0 };
int length { 0 };
QString styleName;
};
QList<styleStruct> styleApplicationList;
StyleSet<ParagraphStyle> newParaStyleSet;
StyleSet<CharStyle> newCharStyleSet;
defaultParagraphStyle.setParent(CommonStrings::DefaultParagraphStyle);
defaultParagraphStyle.charStyle().setParent(CommonStrings::DefaultCharacterStyle);
defaultParagraphStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
m_item->itemText.clear();
m_item->itemText.setDefaultStyle(defaultParagraphStyle);
int listStyleCount = 1;
int listCounter = 1;
int blockCount = m_importedText.blockCount();
QString listStyleName;
for (int i = 0; i < blockCount; i++)
{
QTextBlock curblk = m_importedText.findBlockByNumber(i);
if (!curblk.isValid())
continue;
QTextBlockFormat tbf = curblk.blockFormat();
styleApplicationList.clear();
currentParagraphStyle = defaultParagraphStyle;
if (!m_textOnly)
{
//Headings, find and then create styles
int headingLevel = curblk.blockFormat().headingLevel();
if (headingLevel > 0)
{
QString headingStyleName = QString("Heading %1").arg(headingLevel);
if (m_prefixName)
headingStyleName = m_item->itemName() + "_" + headingStyleName;
if (!newParaStyleSet.contains(headingStyleName))
{
ParagraphStyle newParaStyle;
newParaStyle.setParent(CommonStrings::DefaultParagraphStyle);
newParaStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
newParaStyle.setContext(m_item->itemText.defaultStyle().context());
newParaStyle.charStyle().setFontSize(20 * (7 - headingLevel) + newParaStyle.charStyle().fontSize());
newParaStyle.setName(headingStyleName);
const auto* newParaStylePtr = newParaStyleSet.create(newParaStyle);
currentParagraphStyle.setContext(newParaStylePtr->context());
currentParagraphStyle = *newParaStylePtr;
}
else
{
const auto& headingStyle = newParaStyleSet.get(headingStyleName);
currentParagraphStyle.setContext(headingStyle.context());
currentParagraphStyle = headingStyle;
}
}
//List items
if (curblk.textList() != nullptr)
{
QTextListFormat tlf = curblk.textList()->format();
if (listCounter == 1)
{
listStyleName = QString("List %1").arg(listStyleCount);
if (tlf.style() == QTextListFormat::ListDecimal)
listStyleName.prepend("Numbered ");
if (m_prefixName)
listStyleName = m_item->itemName() + "_" + listStyleName;
if (!newParaStyleSet.contains(listStyleName))
{
listStyleCount++;
ParagraphStyle newParaStyle;
newParaStyle.setParent(CommonStrings::DefaultParagraphStyle);
newParaStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
newParaStyle.setContext(m_item->itemText.defaultStyle().context());
switch (tlf.style())
{
case QTextListFormat::ListDisc:
newParaStyle.setBulletStr(QChar(0x2022));
newParaStyle.setHasBullet(true);
break;
case QTextListFormat::ListCircle:
newParaStyle.setBulletStr(QChar(0x2022));
newParaStyle.setHasBullet(true);
break;
case QTextListFormat::ListSquare:
newParaStyle.setBulletStr(QChar(0x25A0));
newParaStyle.setHasBullet(true);
break;
case QTextListFormat::ListDecimal:
newParaStyle.setHasNum(true);
break;
case QTextListFormat::ListLowerAlpha:
case QTextListFormat::ListUpperAlpha:
case QTextListFormat::ListLowerRoman:
case QTextListFormat::ListUpperRoman:
case QTextListFormat::ListStyleUndefined:
break;
}
newParaStyle.setName(listStyleName);
const auto* newParaStylePtr = newParaStyleSet.create(newParaStyle);
currentParagraphStyle.setContext(newParaStylePtr->context());
currentParagraphStyle = *newParaStylePtr;
}
}
else
{
const auto& listStyle = newParaStyleSet.get(listStyleName);
currentParagraphStyle.setContext(listStyle.context());
currentParagraphStyle = listStyle;
}
if (listCounter++ == curblk.textList()->count())
listCounter = 1;
}
//Process all fragments of the text block to find different formats within. Create a structure
//of where and what style was applied
//Strikethrough
//Bold
//Italic
for (QTextBlock::iterator it = curblk.begin(); !(it.atEnd()); ++it)
{
QTextFragment currentFragment = it.fragment();
if (!currentFragment.isValid())
continue;
if (!currentFragment.charFormat().isValid())
continue;
QTextCharFormat cf = currentFragment.charFormat();
bool charFormatFound = false;
CharStyle cs;
cs.setParent(CommonStrings::DefaultCharacterStyle);
cs.setContext(m_item->itemText.defaultStyle().context());
QString styleName;
if (m_prefixName)
styleName = m_item->itemName() + "_";
//Strikethrough
if (cf.fontStrikeOut())
{
StyleFlag s(cs.effects());
charFormatFound = true;
styleName += "Strikethrough";
cs.setName(styleName);
s |= ScStyle_Strikethrough;
cs.setFeatures(s.featureList());
}
//Bold and Italic
bool isBold = cf.fontWeight() == QFont::Bold;
bool isItalic = cf.fontItalic();
if ((isBold && headingLevel == 0) || isItalic)
{
charFormatFound = true;
if (isBold)
styleName += "Bold";
if (isItalic)
styleName += "Italic";
cs.setName(styleName);
QString family(m_item->itemText.charStyle(m_item->itemText.length()).font().family());
if (!family.isEmpty())
{
QStringList slist = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.fontMap[family];
if (isBold && isItalic && slist.contains("Bold Italic"))
cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Bold Italic"]);
if (isBold && !isItalic && slist.contains("Bold"))
cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Bold"]);
if (!isBold && isItalic && slist.contains("Italic"))
cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Italic"]);
// if (!isBold && !isItalic && slist.contains("Regular"))
// cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Regular"]);
}
}
//If we found a character formatted then record the generated character style
if (charFormatFound)
{
newCharStyleSet.create(cs);
styleStruct ss;
ss.start = currentFragment.position();
ss.length = currentFragment.length();
ss.styleName = cs.name();
styleApplicationList.append(ss);
}
}
}
//Insert our text and a paragraph separator
m_item->itemText.insertChars(m_item->itemText.length(), curblk.text());
m_item->itemText.insertChars(m_item->itemText.length(), SpecialChars::PARSEP);
//If we are not just inserting the text, apply a paragraph style and the character styles based on the positions we recorded earlier
if (!m_textOnly)
{
ParagraphStyle paraStyle;
paraStyle.setParent(currentParagraphStyle.name());
m_item->itemText.applyStyle(m_item->itemText.length() - 1, paraStyle);
for (int i = 0; i < styleApplicationList.size(); ++i)
{
CharStyle charStyle;
charStyle.setParent(styleApplicationList.at(i).styleName);
m_item->itemText.applyCharStyle(styleApplicationList.at(i).start, styleApplicationList.at(i).length, charStyle);
}
}
}
if (!m_textOnly)
{
m_Doc->redefineStyles(newParaStyleSet, false);
m_Doc->redefineCharStyles(newCharStyleSet, false);
}
}