vstyleparser.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #include "vstyleparser.h"
  2. #include <QFont>
  3. #include <QFontDatabase>
  4. #include <QPalette>
  5. #include <QTextEdit>
  6. #include <QColor>
  7. #include <QBrush>
  8. #include <QVector>
  9. #include <QtDebug>
  10. #include <QStringList>
  11. VStyleParser::VStyleParser()
  12. {
  13. markdownStyles = NULL;
  14. }
  15. VStyleParser::~VStyleParser()
  16. {
  17. if (markdownStyles) {
  18. pmh_free_style_collection(markdownStyles);
  19. }
  20. }
  21. QColor VStyleParser::QColorFromPmhAttr(pmh_attr_argb_color *attr) const
  22. {
  23. return QColor(attr->red, attr->green, attr->blue, attr->alpha);
  24. }
  25. QBrush VStyleParser::QBrushFromPmhAttr(pmh_attr_argb_color *attr) const
  26. {
  27. return QBrush(QColorFromPmhAttr(attr));
  28. }
  29. void markdownStyleErrorCB(char *errMsg, int lineNr, void *context)
  30. {
  31. (void)context;
  32. qWarning() << "parser error:" << errMsg << lineNr;
  33. }
  34. QTextCharFormat VStyleParser::QTextCharFormatFromAttrs(pmh_style_attribute *attrs,
  35. const QFont &baseFont) const
  36. {
  37. QTextCharFormat format;
  38. while (attrs) {
  39. switch (attrs->type) {
  40. case pmh_attr_type_foreground_color:
  41. format.setForeground(QBrushFromPmhAttr(attrs->value->argb_color));
  42. break;
  43. case pmh_attr_type_background_color:
  44. format.setBackground(QBrushFromPmhAttr(attrs->value->argb_color));
  45. break;
  46. case pmh_attr_type_font_size_pt:
  47. {
  48. pmh_attr_font_size *fontSize = attrs->value->font_size;
  49. int ptSize = fontSize->size_pt;
  50. if (fontSize->is_relative) {
  51. int basePtSize = baseFont.pointSize();
  52. if (basePtSize == -1) {
  53. // In pixel. Use default font configuration.
  54. basePtSize = 11;
  55. }
  56. ptSize += basePtSize;
  57. }
  58. if (ptSize > 0) {
  59. format.setFontPointSize(ptSize);
  60. }
  61. break;
  62. }
  63. case pmh_attr_type_font_family:
  64. {
  65. QString familyList(attrs->value->font_family);
  66. QString finalFamily = filterAvailableFontFamily(familyList);
  67. if (!finalFamily.isEmpty()) {
  68. format.setFontFamily(finalFamily);
  69. }
  70. break;
  71. }
  72. case pmh_attr_type_font_style:
  73. {
  74. pmh_attr_font_styles *fontStyle = attrs->value->font_styles;
  75. if (fontStyle->italic) {
  76. format.setFontItalic(true);
  77. }
  78. if (fontStyle->bold) {
  79. format.setFontWeight(QFont::Bold);
  80. }
  81. if (fontStyle->underlined) {
  82. format.setFontUnderline(true);
  83. }
  84. break;
  85. }
  86. default:
  87. qWarning() << "unimplemented format attr type:" << attrs->type;
  88. break;
  89. }
  90. attrs = attrs->next;
  91. }
  92. return format;
  93. }
  94. void VStyleParser::parseMarkdownStyle(const QString &styleStr)
  95. {
  96. if (markdownStyles) {
  97. pmh_free_style_collection(markdownStyles);
  98. }
  99. markdownStyles = pmh_parse_styles(styleStr.toLocal8Bit().data(),
  100. &markdownStyleErrorCB, this);
  101. }
  102. QVector<HighlightingStyle> VStyleParser::fetchMarkdownStyles(const QFont &baseFont) const
  103. {
  104. QVector<HighlightingStyle> styles;
  105. for (int i = 0; i < pmh_NUM_LANG_TYPES; ++i) {
  106. pmh_style_attribute *attr = markdownStyles->element_styles[i];
  107. if (!attr) {
  108. continue;
  109. }
  110. HighlightingStyle style;
  111. style.type = attr->lang_element_type;
  112. style.format = QTextCharFormatFromAttrs(attr, baseFont);
  113. styles.append(style);
  114. }
  115. return styles;
  116. }
  117. QMap<QString, QTextCharFormat> VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const
  118. {
  119. QMap<QString, QTextCharFormat> styles;
  120. pmh_style_attribute *attrs = markdownStyles->element_styles[pmh_VERBATIM];
  121. // First set up the base format.
  122. QTextCharFormat baseFormat = QTextCharFormatFromAttrs(attrs, p_baseFont);
  123. while (attrs) {
  124. switch (attrs->type) {
  125. case pmh_attr_type_other:
  126. {
  127. QString attrName(attrs->name);
  128. QString attrValue(attrs->value->string);
  129. QTextCharFormat format;
  130. format.setFontFamily(baseFormat.fontFamily());
  131. QStringList items = attrValue.split(',', QString::SkipEmptyParts);
  132. for (auto const &item : items) {
  133. QString val = item.trimmed().toLower();
  134. if (val == "bold") {
  135. format.setFontWeight(QFont::Bold);
  136. } else if (val == "italic") {
  137. format.setFontItalic(true);
  138. } else if (val == "underlined") {
  139. format.setFontUnderline(true);
  140. } else {
  141. // Treat it as the color RGB value string without '#'.
  142. QColor color("#" + val);
  143. if (color.isValid()) {
  144. format.setForeground(QBrush(color));
  145. }
  146. }
  147. }
  148. if (format.isValid()) {
  149. styles[attrName] = format;
  150. }
  151. break;
  152. }
  153. default:
  154. // We just only handle custom attribute here.
  155. break;
  156. }
  157. attrs = attrs->next;
  158. }
  159. return styles;
  160. }
  161. void VStyleParser::fetchMarkdownEditorStyles(QPalette &palette, QFont &font,
  162. QMap<QString, QMap<QString, QString>> &styles) const
  163. {
  164. QString ruleKey;
  165. // editor
  166. pmh_style_attribute *editorStyles = markdownStyles->editor_styles;
  167. while (editorStyles) {
  168. switch (editorStyles->type) {
  169. case pmh_attr_type_foreground_color:
  170. palette.setColor(QPalette::Text,
  171. QColorFromPmhAttr(editorStyles->value->argb_color));
  172. break;
  173. case pmh_attr_type_background_color:
  174. palette.setColor(QPalette::Base,
  175. QColorFromPmhAttr(editorStyles->value->argb_color));
  176. break;
  177. case pmh_attr_type_font_family:
  178. {
  179. QString familyList(editorStyles->value->font_family);
  180. QString finalFamily = filterAvailableFontFamily(familyList);
  181. if (!finalFamily.isEmpty()) {
  182. font.setFamily(finalFamily);
  183. }
  184. break;
  185. }
  186. default:
  187. qWarning() << "unimplemented editor attr type:" << editorStyles->type;
  188. }
  189. editorStyles = editorStyles->next;
  190. }
  191. // editor-current-line
  192. pmh_style_attribute *curLineStyles = markdownStyles->editor_current_line_styles;
  193. ruleKey = "editor-current-line";
  194. while (curLineStyles) {
  195. switch (curLineStyles->type) {
  196. case pmh_attr_type_background_color:
  197. {
  198. QString attrName(curLineStyles->name);
  199. QString value = QColorFromPmhAttr(curLineStyles->value->argb_color).name();
  200. styles[ruleKey][attrName] = value;
  201. break;
  202. }
  203. case pmh_attr_type_other:
  204. {
  205. QString attrName(curLineStyles->name);
  206. QString value(curLineStyles->value->string);
  207. styles[ruleKey][attrName] = value;
  208. break;
  209. }
  210. default:
  211. qWarning() << "unimplemented current line attr type:" << curLineStyles->type;
  212. }
  213. curLineStyles = curLineStyles->next;
  214. }
  215. // editor-selection
  216. pmh_style_attribute *selStyles = markdownStyles->editor_selection_styles;
  217. while (selStyles) {
  218. switch (selStyles->type) {
  219. case pmh_attr_type_foreground_color:
  220. palette.setColor(QPalette::HighlightedText,
  221. QColorFromPmhAttr(selStyles->value->argb_color));
  222. break;
  223. case pmh_attr_type_background_color:
  224. palette.setColor(QPalette::Highlight,
  225. QColorFromPmhAttr(selStyles->value->argb_color));
  226. break;
  227. default:
  228. qWarning() << "unimplemented selection attr type:" << selStyles->type;
  229. }
  230. selStyles = selStyles->next;
  231. }
  232. }
  233. // @familyList is a comma separated string
  234. QString VStyleParser::filterAvailableFontFamily(const QString &familyList) const
  235. {
  236. QStringList families = familyList.split(',', QString::SkipEmptyParts);
  237. QStringList availFamilies = QFontDatabase().families();
  238. qDebug() << "family:" << familyList;
  239. for (int i = 0; i < families.size(); ++i) {
  240. QString family = families[i].trimmed().toLower();
  241. for (int j = 0; j < availFamilies.size(); ++j) {
  242. QString availFamily = availFamilies[j];
  243. availFamily.remove(QRegExp("\\[.*\\]"));
  244. if (family == availFamily.trimmed().toLower()) {
  245. qDebug() << "matched family:" << availFamilies[j];
  246. return availFamilies[j];
  247. }
  248. }
  249. }
  250. return QString();
  251. }