21 #include "markupdirector.h" 22 #include "markupdirector_p.h" 24 #include "abstractmarkupbuilder.h" 26 #include <QtCore/QFlags> 27 #include <QtCore/QMap> 28 #include <QtCore/QStack> 29 #include <QtCore/QString> 30 #include <QtGui/QBrush> 31 #include <QtGui/QColor> 32 #include <QtGui/QTextCharFormat> 33 #include <QtGui/QTextCursor> 34 #include <QtGui/QTextDocument> 35 #include <QtGui/QTextDocumentFragment> 36 #include <QtGui/QTextFrame> 37 #include <QtGui/QTextList> 38 #include <QtGui/QTextTable> 43 : d_ptr(new MarkupDirectorPrivate(this)), m_builder(builder)
52 while (!start.
atEnd() && start != end) {
55 auto table = qobject_cast<
QTextTable *>(frame);
63 Q_ASSERT(block.isValid());
101 auto format = table->
format();
105 auto tableWidth = format.width();
109 sWidth = QStringLiteral(
"%1%");
110 sWidth = sWidth.
arg(tableWidth.rawValue());
112 sWidth = QStringLiteral(
"%1");
113 sWidth = sWidth.
arg(tableWidth.rawValue());
118 auto headerRowCount = format.headerRowCount();
122 for (
auto row = 0; row < table->
rows(); ++row) {
136 for (
auto column = 0; column < table->
columns(); ++column) {
138 auto tableCell = table->
cellAt(row, column);
141 auto rowSpan = tableCell.rowSpan();
142 if ((rowSpan > 1) || (columnSpan > 1)) {
143 if (alreadyProcessedCells.
contains(tableCell)) {
147 alreadyProcessedCells.
append(tableCell);
151 auto cellWidth = colLengths.at(column);
156 sCellWidth = QStringLiteral(
"%1%");
157 sCellWidth = sCellWidth.
arg(cellWidth.rawValue());
159 sCellWidth = QStringLiteral(
"%1");
160 sCellWidth = sCellWidth.
arg(cellWidth.rawValue());
164 if (row < headerRowCount) {
172 if (row < headerRowCount) {
194 std::pair<QTextFrame::iterator, QTextBlock>
201 while (block.isValid() && block.textList()) {
208 block = block.next();
209 if (block.isValid()) {
210 auto obj = block.document()->objectForFormat(block.blockFormat());
212 if (group && group != list) {
228 auto blockAlignment = blockFormat.
alignment();
234 if (!frameIt.
atEnd())
239 auto it = block.
begin();
246 if (!frameIt.
atEnd())
267 while (!it.atEnd()) {
276 if (!frameIt.
atEnd())
355 auto paraClosed =
false;
366 }
else if (paraClosed) {
400 std::pair<QTextFrame::iterator, QTextBlock>
406 auto lastBlock = _block;
408 auto obj = block.document()->objectForFormat(block.blockFormat());
412 return {lastIt, lastBlock};
416 return {lastIt, lastBlock};
418 while (block.isValid()) {
422 block = block.next();
426 obj = block.document()->objectForFormat(block.blockFormat());
432 if (group == blockGroup || !nextGroup) {
438 return {lastIt, lastBlock};
441 std::pair<QTextFrame::iterator, QTextBlock>
446 auto list = qobject_cast<
QTextList *>(blockGroup);
464 if (fragmentFormat.isImageFormat()) {
496 if (d->m_openElements.isEmpty())
502 auto remainingSize = elementsToClose.size();
503 while (!elementsToClose.isEmpty()) {
504 auto tag = d->m_openElements.last();
505 if (elementsToClose.contains(tag)) {
544 d->m_openElements.removeLast();
545 elementsToClose.remove(tag);
547 previousSize = remainingSize;
548 remainingSize = elementsToClose.size();
550 if (previousSize == remainingSize) {
558 elementsToClose.insert(d->m_openElements.last());
568 if (!fragment.isValid())
574 Q_FOREACH (
int tag, elementsToOpenList) {
590 d->m_openFontPointSize = fragmentFormat.font().pointSize();
593 d->m_openFontFamily = fragmentFormat.fontFamilies().toStringList().first();
598 d->m_openBackground = fragmentFormat.background();
602 d->m_openForeground = fragmentFormat.foreground();
606 auto anchorNames = fragmentFormat.anchorNames();
607 if (!anchorNames.isEmpty()) {
608 while (!anchorNames.isEmpty()) {
609 auto n = anchorNames.last();
610 anchorNames.removeLast();
611 if (anchorNames.isEmpty()) {
625 d->m_openAnchorHref = fragmentFormat.anchorHref();
637 d->m_openElements.append(tag);
638 d->m_elementsToOpen.remove(tag);
649 auto elementsToClose =
QSet<int>(d->m_openElements.begin(), d->m_openElements.end());
650 return elementsToClose.
unite(d->m_elementsToOpen);
655 if (!fragment.isValid())
656 return closedElements;
658 auto fragmentFormat = fragment.charFormat();
660 auto fontWeight = fragmentFormat.fontWeight();
661 auto fontItalic = fragmentFormat.fontItalic();
662 auto fontUnderline = fragmentFormat.fontUnderline();
663 auto fontStrikeout = fragmentFormat.fontStrikeOut();
665 auto fontForeground = fragmentFormat.foreground();
666 auto fontBackground = fragmentFormat.background();
668 const QStringList fontFamilies = fragmentFormat.fontFamilies().toStringList();
670 auto fontPointSize = fragmentFormat.font().pointSize();
671 auto anchorHref = fragmentFormat.anchorHref();
673 auto vAlign = fragmentFormat.verticalAlignment();
678 && (d->m_openElements.contains(
StrikeOut)
679 || d->m_elementsToOpen.contains(
StrikeOut))) {
684 && (d->m_openElements.contains(
Underline)
685 || d->m_elementsToOpen.contains(
Underline))
686 && !(d->m_openElements.contains(
Anchor)
687 || d->m_elementsToOpen.contains(
Anchor))) {
692 && (d->m_openElements.contains(
Emph)
693 || d->m_elementsToOpen.contains(
Emph))) {
698 && (d->m_openElements.contains(
Strong)
699 || d->m_elementsToOpen.contains(
Strong))) {
705 && (d->m_openFontPointSize != fontPointSize)) {
711 && (d->m_openFontFamily != fontFamily)) {
716 && (d->m_openBackground != fontBackground))
718 && (d->m_backgroundToOpen != fontBackground))) {
723 && (d->m_openForeground != fontForeground))
725 && (d->m_foregroundToOpen != fontForeground))) {
729 if ((d->m_openElements.contains(
Anchor)
730 && (d->m_openAnchorHref != anchorHref))
731 || (d->m_elementsToOpen.contains(
Anchor)
732 && (d->m_anchorHrefToOpen != anchorHref))) {
737 && (d->m_openElements.contains(
SubScript)
738 || d->m_elementsToOpen.contains(
SubScript))) {
747 return closedElements;
754 if (!fragment.isValid()) {
757 auto fragmentFormat = fragment.charFormat();
759 auto fontWeight = fragmentFormat.fontWeight();
760 auto fontItalic = fragmentFormat.fontItalic();
761 auto fontUnderline = fragmentFormat.fontUnderline();
762 auto fontStrikeout = fragmentFormat.fontStrikeOut();
764 auto fontForeground = fragmentFormat.foreground();
765 auto fontBackground = fragmentFormat.background();
767 const QStringList fontFamilies = fragmentFormat.fontFamilies().toStringList();
769 auto fontPointSize = fragmentFormat.font().pointSize();
770 auto anchorHref = fragmentFormat.anchorHref();
772 auto vAlign = fragmentFormat.verticalAlignment();
776 if (superscript && !(d->m_openElements.contains(
SuperScript))) {
780 if (subscript && !(d->m_openElements.contains(
SubScript))) {
784 if (!anchorHref.isEmpty() && !(d->m_openElements.contains(
Anchor))
785 && (d->m_openAnchorHref != anchorHref)) {
786 d->m_elementsToOpen.insert(
Anchor);
787 d->m_anchorHrefToOpen = anchorHref;
794 && (fontForeground != d->m_openForeground)
795 && !((d->m_openElements.contains(
797 || d->m_elementsToOpen.contains(
Anchor)))) {
799 d->m_foregroundToOpen = fontForeground;
804 && (fontBackground != d->m_openBackground)) {
806 d->m_backgroundToOpen = fontBackground;
809 if (!fontFamily.isEmpty() && !(d->m_openElements.contains(
SpanFontFamily))
810 && (fontFamily != d->m_openFontFamily)) {
812 d->m_fontFamilyToOpen = fontFamily;
818 && (fontPointSize != d->m_openFontPointSize)) {
820 d->m_fontPointSizeToOpen = fontPointSize;
828 d->m_elementsToOpen.insert(
Strong);
831 if (fontItalic && !(d->m_openElements.contains(
Emph))) {
832 d->m_elementsToOpen.insert(
Emph);
835 if (fontUnderline && !(d->m_openElements.contains(
Underline))
836 && !(d->m_openElements.contains(
Anchor)
837 || d->m_elementsToOpen.contains(
843 if (fontStrikeout && !(d->m_openElements.contains(
StrikeOut))) {
847 if (d->m_elementsToOpen.size() <= 1) {
848 return QList<int>(d->m_elementsToOpen.begin(), d->m_elementsToOpen.end());
863 while (openingOrder.
size() != 0) {
876 Q_FOREACH (
int tag, elementsToClose) {
877 if (openingOrder.
remove(tag)) {
878 sortedOpenedElements.
prepend(tag);
885 Q_FOREACH (
int tag, openingOrder) {
886 sortedOpenedElements.
prepend(tag);
891 return sortedOpenedElements;
std::pair< QTextFrame::iterator, QTextBlock > skipBlockGroup(QTextFrame::iterator it, const QTextBlock &_block, QTextBlockGroup *blockGroup)
Instructs a builder object to create markup output.
virtual QTextBlock::iterator processImage(QTextBlock::iterator it, const QTextImageFormat &imageFormat, QTextDocument *doc)
virtual ~MarkupDirector()
iterator begin() const const
virtual std::pair< QTextFrame::iterator, QTextBlock > processList(QTextFrame::iterator it, const QTextBlock &block, QTextList *textList)
QTextListFormat format() const const
virtual QTextFrame::iterator processBlockContents(QTextFrame::iterator it, const QTextBlock &block)
virtual void endTableRow()=0
The Cutelee namespace holds all public Cutelee API.
QTextFrame::iterator end() const const
qsizetype size() const const
virtual QTextFrame::iterator processBlock(QTextFrame::iterator it, const QTextBlock &block)
virtual void beginFontFamily(const QString &family)=0
virtual void addNewline()=0
QTextFrame * currentFrame() const const
Category category(char32_t ucs4)
virtual void beginBackground(const QBrush &brush)=0
virtual void processOpeningElements(QTextBlock::iterator it)
virtual void endFontFamily()=0
virtual void beginFontPointSize(int size)=0
virtual std::pair< QTextFrame::iterator, QTextBlock > processBlockGroup(QTextFrame::iterator it, const QTextBlock &block, QTextBlockGroup *textBlockGroup)
iterator insert(const T &value)
QTextObject * objectForFormat(const QTextFormat &f) const const
virtual QTextFrame::iterator processObject(QTextFrame::iterator it, const QTextBlock &block, QTextObject *textObject)
iterator begin() const const
QString text() const const
BlockTrailingHorizontalRulerWidth
QTextTableFormat format() const const
virtual QSet< int > getElementsToClose(QTextBlock::iterator it) const
QTextCharFormat charFormat() const const
QTextBlock currentBlock() const const
virtual void beginSubscript()=0
virtual void appendLiteralText(const QString &text)=0
virtual void endBackground()=0
virtual void beginStrikeout()=0
virtual void processCustomFragment(const QTextFragment &fragment, QTextDocument const *doc)
QTextFrame * rootFrame() const const
virtual QTextBlock::iterator processCharTextObject(QTextBlock::iterator it, const QTextFragment &fragment, QTextObject *textObject)
QTextFrame::iterator begin() const const
QTextFragment fragment() const const
int columnSpan() const const
bool isValid() const const
An underline tag is open.
virtual void insertImage(const QString &url, qreal width, qreal height)=0
virtual void beginTableRow()=0
virtual void endSuperscript()=0
virtual void beginUnderline()=0
virtual void endTableHeaderCell()=0
virtual void processClosingElements(QTextBlock::iterator it)
qreal height() const const
void processDocumentContents(QTextFrame::iterator begin, QTextFrame::iterator end)
virtual void endParagraph()=0
virtual void endTableCell()=0
virtual void beginSuperscript()=0
QList< int > sortOpeningOrder(QSet< int > openingTags, QTextBlock::iterator it) const
iterator end() const const
virtual void beginAnchor(const QString &href={}, const QString &name={})=0
int columns() const const
const QTextDocument * document() const const
virtual void beginListItem()=0
A font family altering span tag is open.
virtual void processTableCell(const QTextTableCell &tableCell, QTextTable *table)
virtual void beginList(QTextListFormat::Style style)=0
virtual void endAnchor()=0
Style style() const const
bool contains(const AT &value) const const
MarkupDirector(AbstractMarkupBuilder *builder)
virtual void processDocument(QTextDocument *doc)
void prepend(parameter_type value)
A superscript tag is open.
virtual QTextFrame::iterator processTable(QTextFrame::iterator it, QTextTable *table)
virtual void beginForeground(const QBrush &brush)=0
qreal width() const const
A foreground altering span tag is open.
bool remove(const T &value)
virtual void beginParagraph(Qt::Alignment a=Qt::AlignLeft, qreal top=0.0, qreal bottom=0.0, qreal left=0.0, qreal right=0.0)=0
QSet< T > & unite(const QSet< T > &other)
virtual void beginTableHeaderCell(const QString &width, int colSpan, int rowSpan)=0
QTextDocument * document() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QList< QTextLength > columnWidthConstraints() const const
void append(QList< T > &&value)
virtual void endTable()=0
QTextBlockFormat blockFormat() const const
const QChar at(qsizetype position) const const
QTextList * textList() const const
virtual void beginTable(qreal cellpadding, qreal cellspacing, const QString &width)=0
virtual void endListItem()=0
AbstractMarkupBuilder * m_builder
virtual void beginEmph()=0
virtual QTextFrame::iterator processFrame(QTextFrame::iterator it, QTextFrame *frame)
virtual void insertHorizontalRule(int width=-1)=0
QTextImageFormat toImageFormat() const const
virtual void endUnderline()=0
virtual void endStrong()=0
virtual QTextBlock::iterator processFragment(QTextBlock::iterator it, const QTextFragment &fragment, QTextDocument const *doc)
virtual void endFontPointSize()=0
virtual void beginTableCell(const QString &width, int colSpan, int rowSpan)=0
A background altering span tag is open.
QString arg(Args &&... args) const const
virtual void endStrikeout()=0
virtual void endSubscript()=0
Qt::Alignment alignment() const const
QTextTableCell cellAt(const QTextCursor &cursor) const const
Interface for creating marked-up text output.
virtual void beginStrong()=0
virtual void endForeground()=0
A font size altering span tag is open.
virtual QList< int > getElementsToOpen(QTextBlock::iterator it)
QString name() const const