xlsxrichstring.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // xlsxrichstring.cpp
  2. #include <QtGlobal>
  3. #include <QDebug>
  4. #include <QTextDocument>
  5. #include <QTextFragment>
  6. #include "xlsxrichstring.h"
  7. #include "xlsxrichstring_p.h"
  8. #include "xlsxformat_p.h"
  9. QT_BEGIN_NAMESPACE_XLSX
  10. RichStringPrivate::RichStringPrivate()
  11. :_dirty(true)
  12. {
  13. }
  14. RichStringPrivate::RichStringPrivate(const RichStringPrivate &other)
  15. :QSharedData(other), fragmentTexts(other.fragmentTexts)
  16. ,fragmentFormats(other.fragmentFormats)
  17. , _idKey(other.idKey()), _dirty(other._dirty)
  18. {
  19. }
  20. RichStringPrivate::~RichStringPrivate()
  21. {
  22. }
  23. /*!
  24. \class RichString
  25. \inmodule QtXlsx
  26. \brief This class add support for the rich text string of the cell.
  27. */
  28. /*!
  29. Constructs a null string.
  30. */
  31. RichString::RichString()
  32. :d(new RichStringPrivate)
  33. {
  34. }
  35. /*!
  36. Constructs a plain string with the given \a text.
  37. */
  38. RichString::RichString(const QString& text)
  39. :d(new RichStringPrivate)
  40. {
  41. addFragment(text, Format());
  42. }
  43. /*!
  44. Constructs a copy of \a other.
  45. */
  46. RichString::RichString(const RichString &other)
  47. :d(other.d)
  48. {
  49. }
  50. /*!
  51. Destructs the string.
  52. */
  53. RichString::~RichString()
  54. {
  55. }
  56. /*!
  57. Assigns \a other to this string and returns a reference to this string
  58. */
  59. RichString &RichString::operator =(const RichString &other)
  60. {
  61. this->d = other.d;
  62. return *this;
  63. }
  64. /*!
  65. Returns the rich string as a QVariant
  66. */
  67. RichString::operator QVariant() const
  68. {
  69. const auto& cref
  70. #if QT_VERSION >= 0x060000 // Qt 6.0 or over
  71. = QMetaType::fromType<RichString>();
  72. #else
  73. = qMetaTypeId<RichString>() ;
  74. #endif
  75. return QVariant(cref, this);
  76. }
  77. /*!
  78. Returns true if this is rich text string.
  79. */
  80. bool RichString::isRichString() const
  81. {
  82. if (fragmentCount() > 1) //Is this enough??
  83. return true;
  84. return false;
  85. }
  86. /*!
  87. Returns true is this is an Null string.
  88. */
  89. bool RichString::isNull() const
  90. {
  91. return d->fragmentTexts.size() == 0;
  92. }
  93. /*!
  94. Returns true is this is an empty string.
  95. */
  96. bool RichString::isEmtpy() const
  97. {
  98. for (const auto& str : d->fragmentTexts) {
  99. if (!str.isEmpty())
  100. return false;
  101. }
  102. return true;
  103. }
  104. /*!
  105. Converts to plain text string.
  106. */
  107. QString RichString::toPlainString() const
  108. {
  109. if (isEmtpy())
  110. return QString();
  111. if (d->fragmentTexts.size() == 1)
  112. return d->fragmentTexts[0];
  113. return d->fragmentTexts.join(QString());
  114. }
  115. /*!
  116. Converts to html string
  117. */
  118. QString RichString::toHtml() const
  119. {
  120. //: Todo
  121. return QString();
  122. }
  123. /*!
  124. Replaces the entire contents of the document
  125. with the given HTML-formatted text in the \a text string
  126. */
  127. void RichString::setHtml(const QString &text)
  128. {
  129. QTextDocument doc;
  130. doc.setHtml(text);
  131. QTextBlock block = doc.firstBlock();
  132. QTextBlock::iterator it;
  133. for (it = block.begin(); !(it.atEnd()); ++it) {
  134. QTextFragment textFragment = it.fragment();
  135. if (textFragment.isValid()) {
  136. Format fmt;
  137. fmt.setFont(textFragment.charFormat().font());
  138. fmt.setFontColor(textFragment.charFormat().foreground().color());
  139. addFragment(textFragment.text(), fmt);
  140. }
  141. }
  142. }
  143. /*!
  144. Returns fragment count.
  145. */
  146. int RichString::fragmentCount() const
  147. {
  148. return d->fragmentTexts.size();
  149. }
  150. /*!
  151. Appends a fragment with the given \a text and \a format.
  152. */
  153. void RichString::addFragment(const QString &text, const Format &format)
  154. {
  155. d->fragmentTexts.append(text);
  156. d->fragmentFormats.append(format);
  157. d->_dirty = true;
  158. }
  159. /*!
  160. Returns fragment text at the position \a index.
  161. */
  162. QString RichString::fragmentText(int index) const
  163. {
  164. if (index < 0 || index >= fragmentCount())
  165. return QString();
  166. return d->fragmentTexts[index];
  167. }
  168. /*!
  169. Returns fragment format at the position \a index.
  170. */
  171. Format RichString::fragmentFormat(int index) const
  172. {
  173. if (index < 0 || index >= fragmentCount())
  174. return Format();
  175. return d->fragmentFormats[index];
  176. }
  177. /*!
  178. * \internal
  179. */
  180. QByteArray RichStringPrivate::idKey() const
  181. {
  182. if (_dirty) {
  183. RichStringPrivate *rs = const_cast<RichStringPrivate *>(this);
  184. QByteArray bytes;
  185. if (fragmentTexts.size() == 1) {
  186. bytes = fragmentTexts[0].toUtf8();
  187. } else {
  188. //Generate a hash value base on QByteArray ?
  189. bytes.append("@@QtXlsxRichString=");
  190. for (int i=0; i<fragmentTexts.size(); ++i) {
  191. bytes.append("@Text");
  192. bytes.append(fragmentTexts[i].toUtf8());
  193. bytes.append("@Format");
  194. if (fragmentFormats[i].hasFontData())
  195. bytes.append(fragmentFormats[i].fontKey());
  196. }
  197. }
  198. rs->_idKey = bytes;
  199. rs->_dirty = false;
  200. }
  201. return _idKey;
  202. }
  203. /*!
  204. Returns true if this string \a rs1 is equal to string \a rs2;
  205. otherwise returns false.
  206. */
  207. bool operator==(const RichString &rs1, const RichString &rs2)
  208. {
  209. if (rs1.fragmentCount() != rs2.fragmentCount())
  210. return false;
  211. return rs1.d->idKey() == rs2.d->idKey();
  212. }
  213. /*!
  214. Returns true if this string \a rs1 is not equal to string \a rs2;
  215. otherwise returns false.
  216. */
  217. bool operator!=(const RichString &rs1, const RichString &rs2)
  218. {
  219. if (rs1.fragmentCount() != rs2.fragmentCount())
  220. return true;
  221. return rs1.d->idKey() != rs2.d->idKey();
  222. }
  223. /*!
  224. * \internal
  225. */
  226. bool operator<(const RichString &rs1, const RichString &rs2)
  227. {
  228. return rs1.d->idKey() < rs2.d->idKey();
  229. }
  230. /*!
  231. \overload
  232. Returns true if this string \a rs1 is equal to string \a rs2;
  233. otherwise returns false.
  234. */
  235. bool operator ==(const RichString &rs1, const QString &rs2)
  236. {
  237. if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
  238. return true;
  239. return false;
  240. }
  241. /*!
  242. \overload
  243. Returns true if this string \a rs1 is not equal to string \a rs2;
  244. otherwise returns false.
  245. */
  246. bool operator !=(const RichString &rs1, const QString &rs2)
  247. {
  248. if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
  249. return false;
  250. return true;
  251. }
  252. /*!
  253. \overload
  254. Returns true if this string \a rs1 is equal to string \a rs2;
  255. otherwise returns false.
  256. */
  257. bool operator ==(const QString &rs1, const RichString &rs2)
  258. {
  259. return rs2 == rs1;
  260. }
  261. /*!
  262. \overload
  263. Returns true if this string \a rs1 is not equal to string \a rs2;
  264. otherwise returns false.
  265. */
  266. bool operator !=(const QString &rs1, const RichString &rs2)
  267. {
  268. return rs2 != rs1;
  269. }
  270. uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
  271. {
  272. #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
  273. return qHash(rs.d->idKey(), seed);
  274. #else
  275. Q_UNUSED(seed);
  276. return qHash(rs.d->idKey());
  277. #endif
  278. }
  279. #ifndef QT_NO_DEBUG_STREAM
  280. QDebug operator<<(QDebug dbg, const RichString &rs)
  281. {
  282. dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")";
  283. return dbg.space();
  284. }
  285. #endif
  286. QT_END_NAMESPACE_XLSX