xlsxrichstring.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /****************************************************************************
  2. ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
  3. ** All right reserved.
  4. **
  5. ** Permission is hereby granted, free of charge, to any person obtaining
  6. ** a copy of this software and associated documentation files (the
  7. ** "Software"), to deal in the Software without restriction, including
  8. ** without limitation the rights to use, copy, modify, merge, publish,
  9. ** distribute, sublicense, and/or sell copies of the Software, and to
  10. ** permit persons to whom the Software is furnished to do so, subject to
  11. ** the following conditions:
  12. **
  13. ** The above copyright notice and this permission notice shall be
  14. ** included in all copies or substantial portions of the Software.
  15. **
  16. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. **
  24. ****************************************************************************/
  25. #include "xlsxrichstring.h"
  26. #include "xlsxrichstring_p.h"
  27. #include "xlsxformat_p.h"
  28. #include <QDebug>
  29. #include <QTextDocument>
  30. #include <QTextFragment>
  31. QT_BEGIN_NAMESPACE_XLSX
  32. RichStringPrivate::RichStringPrivate()
  33. :_dirty(true)
  34. {
  35. }
  36. RichStringPrivate::RichStringPrivate(const RichStringPrivate &other)
  37. :QSharedData(other), fragmentTexts(other.fragmentTexts)
  38. ,fragmentFormats(other.fragmentFormats)
  39. , _idKey(other.idKey()), _dirty(other._dirty)
  40. {
  41. }
  42. RichStringPrivate::~RichStringPrivate()
  43. {
  44. }
  45. /*!
  46. \class RichString
  47. \inmodule QtXlsx
  48. \brief This class add support for the rich text string of the cell.
  49. */
  50. /*!
  51. Constructs a null string.
  52. */
  53. RichString::RichString()
  54. :d(new RichStringPrivate)
  55. {
  56. }
  57. /*!
  58. Constructs a plain string with the given \a text.
  59. */
  60. RichString::RichString(const QString text)
  61. :d(new RichStringPrivate)
  62. {
  63. addFragment(text, Format());
  64. }
  65. /*!
  66. Constructs a copy of \a other.
  67. */
  68. RichString::RichString(const RichString &other)
  69. :d(other.d)
  70. {
  71. }
  72. /*!
  73. Destructs the string.
  74. */
  75. RichString::~RichString()
  76. {
  77. }
  78. /*!
  79. Assigns \a other to this string and returns a reference to this string
  80. */
  81. RichString &RichString::operator =(const RichString &other)
  82. {
  83. this->d = other.d;
  84. return *this;
  85. }
  86. /*!
  87. Returns the rich string as a QVariant
  88. */
  89. RichString::operator QVariant() const
  90. {
  91. return QVariant(qMetaTypeId<RichString>(), this);
  92. }
  93. /*!
  94. Returns true if this is rich text string.
  95. */
  96. bool RichString::isRichString() const
  97. {
  98. if (fragmentCount() > 1) //Is this enough??
  99. return true;
  100. return false;
  101. }
  102. /*!
  103. Returns true is this is an Null string.
  104. */
  105. bool RichString::isNull() const
  106. {
  107. return d->fragmentTexts.size() == 0;
  108. }
  109. /*!
  110. Returns true is this is an empty string.
  111. */
  112. bool RichString::isEmtpy() const
  113. {
  114. foreach (const QString str, d->fragmentTexts) {
  115. if (!str.isEmpty())
  116. return false;
  117. }
  118. return true;
  119. }
  120. /*!
  121. Converts to plain text string.
  122. */
  123. QString RichString::toPlainString() const
  124. {
  125. if (isEmtpy())
  126. return QString();
  127. if (d->fragmentTexts.size() == 1)
  128. return d->fragmentTexts[0];
  129. return d->fragmentTexts.join(QString());
  130. }
  131. /*!
  132. Converts to html string
  133. */
  134. QString RichString::toHtml() const
  135. {
  136. //: Todo
  137. return QString();
  138. }
  139. /*!
  140. Replaces the entire contents of the document
  141. with the given HTML-formatted text in the \a text string
  142. */
  143. void RichString::setHtml(const QString &text)
  144. {
  145. QTextDocument doc;
  146. doc.setHtml(text);
  147. QTextBlock block = doc.firstBlock();
  148. QTextBlock::iterator it;
  149. for (it = block.begin(); !(it.atEnd()); ++it) {
  150. QTextFragment textFragment = it.fragment();
  151. if (textFragment.isValid()) {
  152. Format fmt;
  153. fmt.setFont(textFragment.charFormat().font());
  154. fmt.setFontColor(textFragment.charFormat().foreground().color());
  155. addFragment(textFragment.text(), fmt);
  156. }
  157. }
  158. }
  159. /*!
  160. Returns fragment count.
  161. */
  162. int RichString::fragmentCount() const
  163. {
  164. return d->fragmentTexts.size();
  165. }
  166. /*!
  167. Appends a fragment with the given \a text and \a format.
  168. */
  169. void RichString::addFragment(const QString &text, const Format &format)
  170. {
  171. d->fragmentTexts.append(text);
  172. d->fragmentFormats.append(format);
  173. d->_dirty = true;
  174. }
  175. /*!
  176. Returns fragment text at the position \a index.
  177. */
  178. QString RichString::fragmentText(int index) const
  179. {
  180. if (index < 0 || index >= fragmentCount())
  181. return QString();
  182. return d->fragmentTexts[index];
  183. }
  184. /*!
  185. Returns fragment format at the position \a index.
  186. */
  187. Format RichString::fragmentFormat(int index) const
  188. {
  189. if (index < 0 || index >= fragmentCount())
  190. return Format();
  191. return d->fragmentFormats[index];
  192. }
  193. /*!
  194. * \internal
  195. */
  196. QByteArray RichStringPrivate::idKey() const
  197. {
  198. if (_dirty) {
  199. RichStringPrivate *rs = const_cast<RichStringPrivate *>(this);
  200. QByteArray bytes;
  201. if (fragmentTexts.size() == 1) {
  202. bytes = fragmentTexts[0].toUtf8();
  203. } else {
  204. //Generate a hash value base on QByteArray ?
  205. bytes.append("@@QtXlsxRichString=");
  206. for (int i=0; i<fragmentTexts.size(); ++i) {
  207. bytes.append("@Text");
  208. bytes.append(fragmentTexts[i].toUtf8());
  209. bytes.append("@Format");
  210. if (fragmentFormats[i].hasFontData())
  211. bytes.append(fragmentFormats[i].fontKey());
  212. }
  213. }
  214. rs->_idKey = bytes;
  215. rs->_dirty = false;
  216. }
  217. return _idKey;
  218. }
  219. /*!
  220. Returns true if this string \a rs1 is equal to string \a rs2;
  221. otherwise returns false.
  222. */
  223. bool operator==(const RichString &rs1, const RichString &rs2)
  224. {
  225. if (rs1.fragmentCount() != rs2.fragmentCount())
  226. return false;
  227. return rs1.d->idKey() == rs2.d->idKey();
  228. }
  229. /*!
  230. Returns true if this string \a rs1 is not equal to string \a rs2;
  231. otherwise returns false.
  232. */
  233. bool operator!=(const RichString &rs1, const RichString &rs2)
  234. {
  235. if (rs1.fragmentCount() != rs2.fragmentCount())
  236. return true;
  237. return rs1.d->idKey() != rs2.d->idKey();
  238. }
  239. /*!
  240. * \internal
  241. */
  242. bool operator<(const RichString &rs1, const RichString &rs2)
  243. {
  244. return rs1.d->idKey() < rs2.d->idKey();
  245. }
  246. /*!
  247. \overload
  248. Returns true if this string \a rs1 is equal to string \a rs2;
  249. otherwise returns false.
  250. */
  251. bool operator ==(const RichString &rs1, const QString &rs2)
  252. {
  253. if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
  254. return true;
  255. return false;
  256. }
  257. /*!
  258. \overload
  259. Returns true if this string \a rs1 is not equal to string \a rs2;
  260. otherwise returns false.
  261. */
  262. bool operator !=(const RichString &rs1, const QString &rs2)
  263. {
  264. if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
  265. return false;
  266. return true;
  267. }
  268. /*!
  269. \overload
  270. Returns true if this string \a rs1 is equal to string \a rs2;
  271. otherwise returns false.
  272. */
  273. bool operator ==(const QString &rs1, const RichString &rs2)
  274. {
  275. return rs2 == rs1;
  276. }
  277. /*!
  278. \overload
  279. Returns true if this string \a rs1 is not equal to string \a rs2;
  280. otherwise returns false.
  281. */
  282. bool operator !=(const QString &rs1, const RichString &rs2)
  283. {
  284. return rs2 != rs1;
  285. }
  286. uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
  287. {
  288. return qHash(rs.d->idKey(), seed);
  289. }
  290. #ifndef QT_NO_DEBUG_STREAM
  291. QDebug operator<<(QDebug dbg, const RichString &rs)
  292. {
  293. dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")";
  294. return dbg.space();
  295. }
  296. #endif
  297. QT_END_NAMESPACE_XLSX