Subversion Repositories Scribus

Rev

Rev 24743 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
23992 craig 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
7
/***************************************************************************
8
                                                         -------------------
9
        begin                : Wed Aug 19 2020
10
        copyright            : (C) 2020 by Craig Bradney
11
        email                : cbradney@scribus.info
12
 ***************************************************************************/
13
#include "markdownim.h"
14
 
15
#include <QApplication>
16
#include <QByteArray>
17
#include <QTextBlock>
18
#include <QTextBlockFormat>
19
#include <QTextCharFormat>
20
#include <QTextDocument>
21
#include <QTextFrameFormat>
23996 craig 22
#include <QTextList>
23992 craig 23
#include <QTextListFormat>
24
 
25
#include "prefsmanager.h"
26
#include "scribus.h"
27
#include "scribusdoc.h"
28
#include "styles/charstyle.h"
29
#include "styles/paragraphstyle.h"
30
 
31
QString FileFormatName()
32
{
33
        return QObject::tr("MarkDown Document");
34
}
35
 
36
QStringList FileExtensions()
37
{
38
        return QStringList("md");
39
}
40
 
24743 jghali 41
void GetText2(const QString& filename, const QString& /*encoding*/, bool textOnly, bool prefix, bool append, PageItem *textItem)
23992 craig 42
{
43
        MarkDownIm* markdownim = new MarkDownIm(filename, textItem, textOnly, prefix, append);
44
        delete markdownim;
45
}
46
 
47
MarkDownIm::MarkDownIm(const QString& fileName, PageItem *textItem, bool textOnly, bool prefix, bool append)
24743 jghali 48
          : m_Doc(textItem->doc()),
49
                m_item(textItem),
50
                m_prefixName(prefix),
51
                m_append(append),
52
                m_textOnly(textOnly)
23992 craig 53
{
54
        QFile f(fileName);
55
        if (!f.open(QIODevice::ReadOnly))
56
                return;
57
 
58
        QByteArray data = f.readAll();
59
        f.close();
60
 
61
        m_importedText.setMarkdown(data, QTextDocument::MarkdownDialectGitHub);
62
        if (!append)
63
        {
64
                QString defaultParagraphStyle = CommonStrings::DefaultParagraphStyle;
65
                ParagraphStyle newStyle;
66
                newStyle.setDefaultStyle(false);
67
                newStyle.setParent(defaultParagraphStyle);
68
                m_item->itemText.clear();
69
                m_item->itemText.setDefaultStyle(newStyle);
70
        }
71
        parseMarkDown();
72
        m_item->itemText.trim();
73
        m_item->itemText.invalidateLayout();
74
}
75
 
76
void MarkDownIm::parseMarkDown()
77
{
78
        struct styleStruct
79
        {
24743 jghali 80
                int start { 0 };
81
                int length { 0 };
23992 craig 82
                QString styleName;
83
        };
84
        QList<styleStruct> styleApplicationList;
85
 
86
        StyleSet<ParagraphStyle> newParaStyleSet;
87
        StyleSet<CharStyle> newCharStyleSet;
88
        defaultParagraphStyle.setParent(CommonStrings::DefaultParagraphStyle);
89
        defaultParagraphStyle.charStyle().setParent(CommonStrings::DefaultCharacterStyle);
90
        defaultParagraphStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
91
        m_item->itemText.clear();
92
        m_item->itemText.setDefaultStyle(defaultParagraphStyle);
93
 
24743 jghali 94
        int listStyleCount = 1;
95
        int listCounter = 1;
23992 craig 96
        int blockCount = m_importedText.blockCount();
23996 craig 97
        QString listStyleName;
23992 craig 98
        for (int i = 0; i < blockCount; i++)
99
        {
100
                QTextBlock curblk = m_importedText.findBlockByNumber(i);
101
                if (!curblk.isValid())
102
                        continue;
23996 craig 103
                QTextBlockFormat tbf = curblk.blockFormat();
23992 craig 104
                styleApplicationList.clear();
105
                currentParagraphStyle = defaultParagraphStyle;
106
                if (!m_textOnly)
107
                {
23996 craig 108
                        //Headings, find and then create styles
23992 craig 109
                        int headingLevel = curblk.blockFormat().headingLevel();
110
                        if (headingLevel > 0)
111
                        {
24743 jghali 112
                                QString headingStyleName = QString("Heading %1").arg(headingLevel);
24748 jghali 113
                                if (m_prefixName)
114
                                        headingStyleName = m_item->itemName() + "_" + headingStyleName;
23996 craig 115
                                if (!newParaStyleSet.contains(headingStyleName))
23992 craig 116
                                {
117
                                        ParagraphStyle newParaStyle;
118
                                        newParaStyle.setParent(CommonStrings::DefaultParagraphStyle);
119
                                        newParaStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
120
                                        newParaStyle.setContext(m_item->itemText.defaultStyle().context());
24743 jghali 121
                                        newParaStyle.charStyle().setFontSize(20 * (7 - headingLevel) + newParaStyle.charStyle().fontSize());
24748 jghali 122
                                        newParaStyle.setName(headingStyleName);
123
                                        const auto* newParaStylePtr = newParaStyleSet.create(newParaStyle);
124
                                        currentParagraphStyle.setContext(newParaStylePtr->context());
125
                                        currentParagraphStyle = *newParaStylePtr;
23992 craig 126
                                }
127
                                else
24748 jghali 128
                                {
129
                                        const auto& headingStyle = newParaStyleSet.get(headingStyleName);
130
                                        currentParagraphStyle.setContext(headingStyle.context());
131
                                        currentParagraphStyle = headingStyle;
132
                                }
23992 craig 133
                        }
134
 
23996 craig 135
                        //List items
24743 jghali 136
                        if (curblk.textList() != nullptr)
23996 craig 137
                        {
138
                                QTextListFormat tlf = curblk.textList()->format();
24743 jghali 139
                                if (listCounter == 1)
23996 craig 140
                                {
24743 jghali 141
                                        listStyleName = QString("List %1").arg(listStyleCount);
23996 craig 142
                                        if (tlf.style() == QTextListFormat::ListDecimal)
143
                                                listStyleName.prepend("Numbered ");
24748 jghali 144
                                        if (m_prefixName)
145
                                                listStyleName = m_item->itemName() + "_" + listStyleName;
23996 craig 146
                                        if (!newParaStyleSet.contains(listStyleName))
147
                                        {
148
                                                listStyleCount++;
149
                                                ParagraphStyle newParaStyle;
150
                                                newParaStyle.setParent(CommonStrings::DefaultParagraphStyle);
151
                                                newParaStyle.setLineSpacingMode(ParagraphStyle::AutomaticLineSpacing);
152
                                                newParaStyle.setContext(m_item->itemText.defaultStyle().context());
153
                                                switch (tlf.style())
154
                                                {
155
                                                        case QTextListFormat::ListDisc:
156
                                                                newParaStyle.setBulletStr(QChar(0x2022));
157
                                                                newParaStyle.setHasBullet(true);
158
                                                                break;
159
                                                        case QTextListFormat::ListCircle:
160
                                                                newParaStyle.setBulletStr(QChar(0x2022));
161
                                                                newParaStyle.setHasBullet(true);
162
                                                                break;
163
                                                        case QTextListFormat::ListSquare:
164
                                                                newParaStyle.setBulletStr(QChar(0x25A0));
165
                                                                newParaStyle.setHasBullet(true);
166
                                                                break;
167
                                                        case QTextListFormat::ListDecimal:
168
                                                                newParaStyle.setHasNum(true);
169
                                                                break;
170
                                                        case QTextListFormat::ListLowerAlpha:
171
                                                        case QTextListFormat::ListUpperAlpha:
172
                                                        case QTextListFormat::ListLowerRoman:
173
                                                        case QTextListFormat::ListUpperRoman:
174
                                                        case QTextListFormat::ListStyleUndefined:
175
                                                                break;
176
                                                }
24748 jghali 177
                                                newParaStyle.setName(listStyleName);
178
                                                const auto* newParaStylePtr = newParaStyleSet.create(newParaStyle);
179
                                                currentParagraphStyle.setContext(newParaStylePtr->context());
180
                                                currentParagraphStyle = *newParaStylePtr;
23996 craig 181
                                        }
182
                                }
183
                                else
24748 jghali 184
                                {
185
                                        const auto& listStyle = newParaStyleSet.get(listStyleName);
186
                                        currentParagraphStyle.setContext(listStyle.context());
187
                                        currentParagraphStyle = listStyle;
188
                                }
24743 jghali 189
                                if (listCounter++ == curblk.textList()->count())
190
                                        listCounter = 1;
23996 craig 191
                        }
192
                        //Process all fragments of the text block to find different formats within. Create a structure
193
                        //of where and what style was applied
194
                        //Strikethrough
195
                        //Bold
196
                        //Italic
23992 craig 197
                        for (QTextBlock::iterator it = curblk.begin(); !(it.atEnd()); ++it)
198
                        {
199
                                QTextFragment currentFragment = it.fragment();
24743 jghali 200
                                if (!currentFragment.isValid())
201
                                        continue;
202
 
203
                                if (!currentFragment.charFormat().isValid())
204
                                        continue;
205
 
206
                                QTextCharFormat cf = currentFragment.charFormat();
207
                                bool charFormatFound = false;
208
                                CharStyle cs;
209
                                cs.setParent(CommonStrings::DefaultCharacterStyle);
210
                                cs.setContext(m_item->itemText.defaultStyle().context());
211
                                QString styleName;
212
                                if (m_prefixName)
213
                                        styleName = m_item->itemName() + "_";
214
 
215
                                //Strikethrough
216
                                if (cf.fontStrikeOut())
23992 craig 217
                                {
24743 jghali 218
                                        StyleFlag s(cs.effects());
219
                                        charFormatFound = true;
220
                                        styleName += "Strikethrough";
221
                                        cs.setName(styleName);
222
                                        s |= ScStyle_Strikethrough;
223
                                        cs.setFeatures(s.featureList());
224
                                }
225
 
226
                                //Bold and Italic
227
                                bool isBold = cf.fontWeight() == QFont::Bold;
228
                                bool isItalic = cf.fontItalic();
229
                                if ((isBold && headingLevel == 0) || isItalic)
230
                                {
231
                                        charFormatFound = true;
232
                                        if (isBold)
233
                                                styleName += "Bold";
234
                                        if (isItalic)
235
                                                styleName += "Italic";
236
                                        cs.setName(styleName);
237
                                        QString family(m_item->itemText.charStyle(m_item->itemText.length()).font().family());
238
                                        if (!family.isEmpty())
23992 craig 239
                                        {
24743 jghali 240
                                                QStringList slist = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.fontMap[family];
241
                                                if (isBold && isItalic && slist.contains("Bold Italic"))
242
                                                        cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Bold Italic"]);
243
                                                if (isBold && !isItalic && slist.contains("Bold"))
244
                                                        cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Bold"]);
245
                                                if (!isBold && isItalic && slist.contains("Italic"))
246
                                                        cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Italic"]);
247
//                                              if (!isBold && !isItalic && slist.contains("Regular"))
248
//                                                      cs.setFont(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[family + " Regular"]);
23992 craig 249
                                        }
250
                                }
24743 jghali 251
 
252
                                //If we found a character formatted then record the generated character style
253
                                if (charFormatFound)
254
                                {
255
                                        newCharStyleSet.create(cs);
256
                                        styleStruct ss;
257
                                        ss.start = currentFragment.position();
258
                                        ss.length = currentFragment.length();
259
                                        ss.styleName = cs.name();
260
                                        styleApplicationList.append(ss);
261
                                }
23992 craig 262
                        }
263
                }
23996 craig 264
                //Insert our text and a paragraph separator
23992 craig 265
                m_item->itemText.insertChars(m_item->itemText.length(), curblk.text());
266
                m_item->itemText.insertChars(m_item->itemText.length(), SpecialChars::PARSEP);
23996 craig 267
                //If we are not just inserting the text, apply a paragraph style and the character styles based on the positions we recorded earlier
23992 craig 268
                if (!m_textOnly)
269
                {
23996 craig 270
                        ParagraphStyle paraStyle;
271
                        paraStyle.setParent(currentParagraphStyle.name());
23992 craig 272
                        m_item->itemText.applyStyle(m_item->itemText.length() - 1, paraStyle);
273
                        for (int i = 0; i < styleApplicationList.size(); ++i)
274
                        {
275
                                CharStyle charStyle;
276
                                charStyle.setParent(styleApplicationList.at(i).styleName);
277
                                m_item->itemText.applyCharStyle(styleApplicationList.at(i).start, styleApplicationList.at(i).length, charStyle);
278
                        }
279
                }
280
        }
281
        if (!m_textOnly)
282
        {
283
                m_Doc->redefineStyles(newParaStyleSet, false);
284
                m_Doc->redefineCharStyles(newCharStyleSet, false);
285
        }
286
}
287
 
288