File indexing completed on 2025-06-29 03:31:10
0001 // xlsxrichstring.cpp 0002 0003 #include <QtGlobal> 0004 #include <QDebug> 0005 #include <QTextDocument> 0006 #include <QTextFragment> 0007 0008 #include "xlsxrichstring.h" 0009 #include "xlsxrichstring_p.h" 0010 #include "xlsxformat_p.h" 0011 0012 QT_BEGIN_NAMESPACE_XLSX 0013 0014 RichStringPrivate::RichStringPrivate() 0015 :_dirty(true) 0016 { 0017 0018 } 0019 0020 RichStringPrivate::RichStringPrivate(const RichStringPrivate &other) 0021 :QSharedData(other), fragmentTexts(other.fragmentTexts) 0022 ,fragmentFormats(other.fragmentFormats) 0023 , _idKey(other.idKey()), _dirty(other._dirty) 0024 { 0025 0026 } 0027 0028 RichStringPrivate::~RichStringPrivate() 0029 { 0030 0031 } 0032 0033 /*! 0034 \class RichString 0035 \inmodule QtXlsx 0036 \brief This class add support for the rich text string of the cell. 0037 */ 0038 0039 /*! 0040 Constructs a null string. 0041 */ 0042 RichString::RichString() 0043 :d(new RichStringPrivate) 0044 { 0045 } 0046 0047 /*! 0048 Constructs a plain string with the given \a text. 0049 */ 0050 RichString::RichString(const QString& text) 0051 :d(new RichStringPrivate) 0052 { 0053 addFragment(text, Format()); 0054 } 0055 0056 /*! 0057 Constructs a copy of \a other. 0058 */ 0059 RichString::RichString(const RichString &other) 0060 :d(other.d) 0061 { 0062 0063 } 0064 0065 /*! 0066 Destructs the string. 0067 */ 0068 RichString::~RichString() 0069 { 0070 0071 } 0072 0073 /*! 0074 Assigns \a other to this string and returns a reference to this string 0075 */ 0076 RichString &RichString::operator =(const RichString &other) 0077 { 0078 this->d = other.d; 0079 return *this; 0080 } 0081 0082 /*! 0083 Returns the rich string as a QVariant 0084 */ 0085 RichString::operator QVariant() const 0086 { 0087 const auto& cref 0088 #if QT_VERSION >= 0x060000 // Qt 6.0 or over 0089 = QMetaType::fromType<RichString>(); 0090 #else 0091 = qMetaTypeId<RichString>() ; 0092 #endif 0093 return QVariant(cref, this); 0094 } 0095 0096 /*! 0097 Returns true if this is rich text string. 0098 */ 0099 bool RichString::isRichString() const 0100 { 0101 if (fragmentCount() > 1) //Is this enough?? 0102 return true; 0103 return false; 0104 } 0105 0106 /*! 0107 Returns true is this is an Null string. 0108 */ 0109 bool RichString::isNull() const 0110 { 0111 return d->fragmentTexts.size() == 0; 0112 } 0113 0114 /*! 0115 Returns true is this is an empty string. 0116 */ 0117 bool RichString::isEmtpy() const 0118 { 0119 for (const auto& str : d->fragmentTexts) { 0120 if (!str.isEmpty()) 0121 return false; 0122 } 0123 0124 return true; 0125 } 0126 0127 /*! 0128 Converts to plain text string. 0129 */ 0130 QString RichString::toPlainString() const 0131 { 0132 if (isEmtpy()) 0133 return QString(); 0134 if (d->fragmentTexts.size() == 1) 0135 return d->fragmentTexts[0]; 0136 0137 return d->fragmentTexts.join(QString()); 0138 } 0139 0140 /*! 0141 Converts to html string 0142 */ 0143 QString RichString::toHtml() const 0144 { 0145 //: Todo 0146 return QString(); 0147 } 0148 0149 /*! 0150 Replaces the entire contents of the document 0151 with the given HTML-formatted text in the \a text string 0152 */ 0153 void RichString::setHtml(const QString &text) 0154 { 0155 QTextDocument doc; 0156 doc.setHtml(text); 0157 QTextBlock block = doc.firstBlock(); 0158 QTextBlock::iterator it; 0159 for (it = block.begin(); !(it.atEnd()); ++it) { 0160 QTextFragment textFragment = it.fragment(); 0161 if (textFragment.isValid()) { 0162 Format fmt; 0163 fmt.setFont(textFragment.charFormat().font()); 0164 fmt.setFontColor(textFragment.charFormat().foreground().color()); 0165 addFragment(textFragment.text(), fmt); 0166 } 0167 } 0168 } 0169 0170 /*! 0171 Returns fragment count. 0172 */ 0173 int RichString::fragmentCount() const 0174 { 0175 return d->fragmentTexts.size(); 0176 } 0177 0178 /*! 0179 Appends a fragment with the given \a text and \a format. 0180 */ 0181 void RichString::addFragment(const QString &text, const Format &format) 0182 { 0183 d->fragmentTexts.append(text); 0184 d->fragmentFormats.append(format); 0185 d->_dirty = true; 0186 } 0187 0188 /*! 0189 Returns fragment text at the position \a index. 0190 */ 0191 QString RichString::fragmentText(int index) const 0192 { 0193 if (index < 0 || index >= fragmentCount()) 0194 return QString(); 0195 0196 return d->fragmentTexts[index]; 0197 } 0198 0199 /*! 0200 Returns fragment format at the position \a index. 0201 */ 0202 Format RichString::fragmentFormat(int index) const 0203 { 0204 if (index < 0 || index >= fragmentCount()) 0205 return Format(); 0206 0207 return d->fragmentFormats[index]; 0208 } 0209 0210 /*! 0211 * \internal 0212 */ 0213 QByteArray RichStringPrivate::idKey() const 0214 { 0215 if (_dirty) { 0216 RichStringPrivate *rs = const_cast<RichStringPrivate *>(this); 0217 QByteArray bytes; 0218 if (fragmentTexts.size() == 1) { 0219 bytes = fragmentTexts[0].toUtf8(); 0220 } else { 0221 //Generate a hash value base on QByteArray ? 0222 bytes.append("@@QtXlsxRichString="); 0223 for (int i=0; i<fragmentTexts.size(); ++i) { 0224 bytes.append("@Text"); 0225 bytes.append(fragmentTexts[i].toUtf8()); 0226 bytes.append("@Format"); 0227 if (fragmentFormats[i].hasFontData()) 0228 bytes.append(fragmentFormats[i].fontKey()); 0229 } 0230 } 0231 rs->_idKey = bytes; 0232 rs->_dirty = false; 0233 } 0234 0235 return _idKey; 0236 } 0237 0238 /*! 0239 Returns true if this string \a rs1 is equal to string \a rs2; 0240 otherwise returns false. 0241 */ 0242 bool operator==(const RichString &rs1, const RichString &rs2) 0243 { 0244 if (rs1.fragmentCount() != rs2.fragmentCount()) 0245 return false; 0246 0247 return rs1.d->idKey() == rs2.d->idKey(); 0248 } 0249 0250 /*! 0251 Returns true if this string \a rs1 is not equal to string \a rs2; 0252 otherwise returns false. 0253 */ 0254 bool operator!=(const RichString &rs1, const RichString &rs2) 0255 { 0256 if (rs1.fragmentCount() != rs2.fragmentCount()) 0257 return true; 0258 0259 return rs1.d->idKey() != rs2.d->idKey(); 0260 } 0261 0262 /*! 0263 * \internal 0264 */ 0265 bool operator<(const RichString &rs1, const RichString &rs2) 0266 { 0267 return rs1.d->idKey() < rs2.d->idKey(); 0268 } 0269 0270 /*! 0271 \overload 0272 Returns true if this string \a rs1 is equal to string \a rs2; 0273 otherwise returns false. 0274 */ 0275 bool operator ==(const RichString &rs1, const QString &rs2) 0276 { 0277 if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0 0278 return true; 0279 0280 return false; 0281 } 0282 0283 /*! 0284 \overload 0285 Returns true if this string \a rs1 is not equal to string \a rs2; 0286 otherwise returns false. 0287 */ 0288 bool operator !=(const RichString &rs1, const QString &rs2) 0289 { 0290 if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0 0291 return false; 0292 0293 return true; 0294 } 0295 0296 /*! 0297 \overload 0298 Returns true if this string \a rs1 is equal to string \a rs2; 0299 otherwise returns false. 0300 */ 0301 bool operator ==(const QString &rs1, const RichString &rs2) 0302 { 0303 return rs2 == rs1; 0304 } 0305 0306 /*! 0307 \overload 0308 Returns true if this string \a rs1 is not equal to string \a rs2; 0309 otherwise returns false. 0310 */ 0311 bool operator !=(const QString &rs1, const RichString &rs2) 0312 { 0313 return rs2 != rs1; 0314 } 0315 0316 uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW 0317 { 0318 return qHash(rs.d->idKey(), seed); 0319 } 0320 0321 #ifndef QT_NO_DEBUG_STREAM 0322 QDebug operator<<(QDebug dbg, const RichString &rs) 0323 { 0324 dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")"; 0325 return dbg.space(); 0326 } 0327 #endif 0328 0329 QT_END_NAMESPACE_XLSX