andre@1: /**************************************************************************** andre@1: ** Copyright (c) 2013-2014 Debao Zhang andre@1: ** All right reserved. andre@1: ** andre@1: ** Permission is hereby granted, free of charge, to any person obtaining andre@1: ** a copy of this software and associated documentation files (the andre@1: ** "Software"), to deal in the Software without restriction, including andre@1: ** without limitation the rights to use, copy, modify, merge, publish, andre@1: ** distribute, sublicense, and/or sell copies of the Software, and to andre@1: ** permit persons to whom the Software is furnished to do so, subject to andre@1: ** the following conditions: andre@1: ** andre@1: ** The above copyright notice and this permission notice shall be andre@1: ** included in all copies or substantial portions of the Software. andre@1: ** andre@1: ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, andre@1: ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF andre@1: ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND andre@1: ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE andre@1: ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION andre@1: ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION andre@1: ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. andre@1: ** andre@1: ****************************************************************************/ andre@1: #include "xlsxrichstring.h" andre@1: #include "xlsxrichstring_p.h" andre@1: #include "xlsxformat_p.h" andre@1: #include andre@1: #include andre@1: #include andre@1: andre@1: QT_BEGIN_NAMESPACE_XLSX andre@1: andre@1: RichStringPrivate::RichStringPrivate() andre@1: :_dirty(true) andre@1: { andre@1: andre@1: } andre@1: andre@1: RichStringPrivate::RichStringPrivate(const RichStringPrivate &other) andre@1: :QSharedData(other), fragmentTexts(other.fragmentTexts) andre@1: ,fragmentFormats(other.fragmentFormats) andre@1: , _idKey(other.idKey()), _dirty(other._dirty) andre@1: { andre@1: andre@1: } andre@1: andre@1: RichStringPrivate::~RichStringPrivate() andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: \class RichString andre@1: \inmodule QtXlsx andre@1: \brief This class add support for the rich text string of the cell. andre@1: */ andre@1: andre@1: /*! andre@1: Constructs a null string. andre@1: */ andre@1: RichString::RichString() andre@1: :d(new RichStringPrivate) andre@1: { andre@1: } andre@1: andre@1: /*! andre@1: Constructs a plain string with the given \a text. andre@1: */ andre@1: RichString::RichString(const QString text) andre@1: :d(new RichStringPrivate) andre@1: { andre@1: addFragment(text, Format()); andre@1: } andre@1: andre@1: /*! andre@1: Constructs a copy of \a other. andre@1: */ andre@1: RichString::RichString(const RichString &other) andre@1: :d(other.d) andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: Destructs the string. andre@1: */ andre@1: RichString::~RichString() andre@1: { andre@1: andre@1: } andre@1: andre@1: /*! andre@1: Assigns \a other to this string and returns a reference to this string andre@1: */ andre@1: RichString &RichString::operator =(const RichString &other) andre@1: { andre@1: this->d = other.d; andre@1: return *this; andre@1: } andre@1: andre@1: /*! andre@1: Returns the rich string as a QVariant andre@1: */ andre@1: RichString::operator QVariant() const andre@1: { andre@1: return QVariant(qMetaTypeId(), this); andre@1: } andre@1: andre@1: /*! andre@1: Returns true if this is rich text string. andre@1: */ andre@1: bool RichString::isRichString() const andre@1: { andre@1: if (fragmentCount() > 1) //Is this enough?? andre@1: return true; andre@1: return false; andre@1: } andre@1: andre@1: /*! andre@1: Returns true is this is an Null string. andre@1: */ andre@1: bool RichString::isNull() const andre@1: { andre@1: return d->fragmentTexts.size() == 0; andre@1: } andre@1: andre@1: /*! andre@1: Returns true is this is an empty string. andre@1: */ andre@1: bool RichString::isEmtpy() const andre@1: { andre@1: foreach (const QString str, d->fragmentTexts) { andre@1: if (!str.isEmpty()) andre@1: return false; andre@1: } andre@1: andre@1: return true; andre@1: } andre@1: andre@1: /*! andre@1: Converts to plain text string. andre@1: */ andre@1: QString RichString::toPlainString() const andre@1: { andre@1: if (isEmtpy()) andre@1: return QString(); andre@1: if (d->fragmentTexts.size() == 1) andre@1: return d->fragmentTexts[0]; andre@1: andre@1: return d->fragmentTexts.join(QString()); andre@1: } andre@1: andre@1: /*! andre@1: Converts to html string andre@1: */ andre@1: QString RichString::toHtml() const andre@1: { andre@1: //: Todo andre@1: return QString(); andre@1: } andre@1: andre@1: /*! andre@1: Replaces the entire contents of the document andre@1: with the given HTML-formatted text in the \a text string andre@1: */ andre@1: void RichString::setHtml(const QString &text) andre@1: { andre@1: QTextDocument doc; andre@1: doc.setHtml(text); andre@1: QTextBlock block = doc.firstBlock(); andre@1: QTextBlock::iterator it; andre@1: for (it = block.begin(); !(it.atEnd()); ++it) { andre@1: QTextFragment textFragment = it.fragment(); andre@1: if (textFragment.isValid()) { andre@1: Format fmt; andre@1: fmt.setFont(textFragment.charFormat().font()); andre@1: fmt.setFontColor(textFragment.charFormat().foreground().color()); andre@1: addFragment(textFragment.text(), fmt); andre@1: } andre@1: } andre@1: } andre@1: andre@1: /*! andre@1: Returns fragment count. andre@1: */ andre@1: int RichString::fragmentCount() const andre@1: { andre@1: return d->fragmentTexts.size(); andre@1: } andre@1: andre@1: /*! andre@1: Appends a fragment with the given \a text and \a format. andre@1: */ andre@1: void RichString::addFragment(const QString &text, const Format &format) andre@1: { andre@1: d->fragmentTexts.append(text); andre@1: d->fragmentFormats.append(format); andre@1: d->_dirty = true; andre@1: } andre@1: andre@1: /*! andre@1: Returns fragment text at the position \a index. andre@1: */ andre@1: QString RichString::fragmentText(int index) const andre@1: { andre@1: if (index < 0 || index >= fragmentCount()) andre@1: return QString(); andre@1: andre@1: return d->fragmentTexts[index]; andre@1: } andre@1: andre@1: /*! andre@1: Returns fragment format at the position \a index. andre@1: */ andre@1: Format RichString::fragmentFormat(int index) const andre@1: { andre@1: if (index < 0 || index >= fragmentCount()) andre@1: return Format(); andre@1: andre@1: return d->fragmentFormats[index]; andre@1: } andre@1: andre@1: /*! andre@1: * \internal andre@1: */ andre@1: QByteArray RichStringPrivate::idKey() const andre@1: { andre@1: if (_dirty) { andre@1: RichStringPrivate *rs = const_cast(this); andre@1: QByteArray bytes; andre@1: if (fragmentTexts.size() == 1) { andre@1: bytes = fragmentTexts[0].toUtf8(); andre@1: } else { andre@1: //Generate a hash value base on QByteArray ? andre@1: bytes.append("@@QtXlsxRichString="); andre@1: for (int i=0; i_idKey = bytes; andre@1: rs->_dirty = false; andre@1: } andre@1: andre@1: return _idKey; andre@1: } andre@1: andre@1: /*! andre@1: Returns true if this string \a rs1 is equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator==(const RichString &rs1, const RichString &rs2) andre@1: { andre@1: if (rs1.fragmentCount() != rs2.fragmentCount()) andre@1: return false; andre@1: andre@1: return rs1.d->idKey() == rs2.d->idKey(); andre@1: } andre@1: andre@1: /*! andre@1: Returns true if this string \a rs1 is not equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator!=(const RichString &rs1, const RichString &rs2) andre@1: { andre@1: if (rs1.fragmentCount() != rs2.fragmentCount()) andre@1: return true; andre@1: andre@1: return rs1.d->idKey() != rs2.d->idKey(); andre@1: } andre@1: andre@1: /*! andre@1: * \internal andre@1: */ andre@1: bool operator<(const RichString &rs1, const RichString &rs2) andre@1: { andre@1: return rs1.d->idKey() < rs2.d->idKey(); andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Returns true if this string \a rs1 is equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator ==(const RichString &rs1, const QString &rs2) andre@1: { andre@1: if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0 andre@1: return true; andre@1: andre@1: return false; andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Returns true if this string \a rs1 is not equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator !=(const RichString &rs1, const QString &rs2) andre@1: { andre@1: if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0 andre@1: return false; andre@1: andre@1: return true; andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Returns true if this string \a rs1 is equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator ==(const QString &rs1, const RichString &rs2) andre@1: { andre@1: return rs2 == rs1; andre@1: } andre@1: andre@1: /*! andre@1: \overload andre@1: Returns true if this string \a rs1 is not equal to string \a rs2; andre@1: otherwise returns false. andre@1: */ andre@1: bool operator !=(const QString &rs1, const RichString &rs2) andre@1: { andre@1: return rs2 != rs1; andre@1: } andre@1: andre@1: uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW andre@1: { andre@1: return qHash(rs.d->idKey(), seed); andre@1: } andre@1: andre@1: #ifndef QT_NO_DEBUG_STREAM andre@1: QDebug operator<<(QDebug dbg, const RichString &rs) andre@1: { andre@1: dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")"; andre@1: return dbg.space(); andre@1: } andre@1: #endif andre@1: andre@1: QT_END_NAMESPACE_XLSX