File indexing completed on 2024-05-19 05:21:46

0001 /*
0002   SPDX-FileCopyrightText: 2019-2021 Montel Laurent <montel@kde.org>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 
0006 */
0007 #pragma once
0008 
0009 #include "abstractmarkupbuilder.h"
0010 #include "kpimtextedit_export.h"
0011 #include <QTextDocument>
0012 #include <QTextFrame>
0013 class QTextTable;
0014 class QTextTableCell;
0015 class QTextList;
0016 class QTextCharFormat;
0017 
0018 namespace KPIMTextEdit
0019 {
0020 class MarkupDirectorPrivate;
0021 class AbstractMarkupBuilder;
0022 
0023 /// @headerfile markupdirector.h grantlee/markupdirector.h
0024 
0025 /**
0026   @brief Instructs a builder object to create markup output
0027 
0028   The **%MarkupDirector** is used with an implementation of
0029   AbstractMarkupBuilder to create a marked up document output.
0030 
0031   Usage can be quite simple.
0032 
0033   @code
0034     auto doc = editor->document(); // editor is a QTextEdit
0035 
0036     auto builder = new HTMLBuilder();
0037     auto md = new MarkupDirector(builder);
0038     md->processDocument(doc);
0039     browser->setHtml(builder->getResult()); // browser is a QTextBrowser.
0040   @endcode
0041 
0042   Or with a different builder:
0043 
0044   @code
0045     auto builder = new PlainTextMarkupBuilder();
0046     auto md = new MarkupDirector(builder);
0047     md->processDocument(doc);
0048     browser->setPlainText(builder->getResult());
0049   @endcode
0050 
0051   The **%MarkupDirector** also provides API for processing just part of a
0052   QTextDocument, such as a QTextFrame or a QTextBlock. The appropriate method
0053   may then be called with an invalid iterator as appropriate.
0054 
0055   @code
0056     // ... Do some processing to get a QTextFrame.
0057     auto frame = getFrame();
0058 
0059     auto builder = new PlainTextMarkupBuilder();
0060     auto md = new MarkupDirector(builder);
0061 
0062     // Create output from only the frame.
0063     md->processFrame(QTextFrame::iterator(), frame);
0064     browser->setPlainText(builder->getResult());
0065   @endcode
0066 
0067   The behaviour of the **%MarkupDirector** can be customized by subclassing.
0068   Support for custom types can also be added by implementing the @ref
0069   processCustomFragment method.
0070 
0071   @see @ref custom_qtextobject
0072 
0073   @author Stephen Kelly <steveire@gmail.com>
0074 */
0075 class KPIMTEXTEDIT_EXPORT MarkupDirector
0076 {
0077 public:
0078     /**
0079     Constructor
0080   */
0081     explicit MarkupDirector(KPIMTextEdit::AbstractMarkupBuilder *builder);
0082 
0083     /**
0084     Destructor
0085   */
0086     virtual ~MarkupDirector();
0087 
0088     /**
0089     Constructs the output by directing the builder to create the markup.
0090   */
0091     virtual void processDocument(QTextDocument *doc);
0092 
0093     /**
0094     Directs the builder to create output for the single @p frame. If calling
0095     this method directly, an invalid QTextFrame::iterator may be used.
0096   */
0097     [[nodiscard]] virtual QTextFrame::iterator processFrame(QTextFrame::iterator it, QTextFrame *frame);
0098 
0099     /**
0100     Directs the builder to create output for the single @p block. If calling
0101     this method directly, an invalid QTextFrame::iterator may be used.
0102 
0103     This method does not process the contents of the @p block, but uses the
0104     @ref processBlockContents method to do so.
0105   */
0106     [[nodiscard]] virtual QTextFrame::iterator processBlock(QTextFrame::iterator it, const QTextBlock &block);
0107 
0108     /**
0109     Directs the builder to create output for the single @p textObject. If
0110     calling this method directly, an invalid QTextFrame::iterator may be used.
0111 
0112     The block @p block is the container of the @p textObject.
0113   */
0114     [[nodiscard]] virtual QTextFrame::iterator processObject(QTextFrame::iterator it, const QTextBlock &block, QTextObject *textObject);
0115 
0116     /**
0117     Directs the builder to create output for the single @p textBlockGroup. If
0118     calling this method directly, an invalid QTextFrame::iterator may be used.
0119 
0120     The block @p block is the first block in the @p textBlockGroup.
0121   */
0122     [[nodiscard]] virtual QPair<QTextFrame::iterator, QTextBlock>
0123     processBlockGroup(const QTextFrame::iterator &it, const QTextBlock &block, QTextBlockGroup *textBlockGroup);
0124 
0125     /**
0126     Directs the builder to create output for the single @p textList. If
0127     calling this method directly, an invalid QTextFrame::iterator may be used.
0128 
0129     The block @p block is the first block in the @p textList.
0130   */
0131     [[nodiscard]] virtual QPair<QTextFrame::iterator, QTextBlock> processList(QTextFrame::iterator it, const QTextBlock &block, QTextList *textList);
0132 
0133     /**
0134     Directs the builder to create output for the contents of the single @p
0135     block. If calling this method directly, an invalid QTextFrame::iterator
0136     may be used.
0137   */
0138     virtual QTextFrame::iterator processBlockContents(QTextFrame::iterator it, const QTextBlock &block);
0139 
0140     /**
0141     Hook for instructing the builder to create output for the @p fragemnt with
0142     a custom type. @p doc is the document the fragment is in.
0143   */
0144     virtual void processCustomFragment(const QTextFragment &fragment, QTextDocument const *doc);
0145 
0146     /**
0147     Directs the builder to create output for the contents of the single @p
0148     fragment. If calling this method directly, an invalid QTextBlock::iterator
0149     may be used. @p doc is the document the fragment is in.
0150   */
0151     [[nodiscard]] virtual QTextBlock::iterator processFragment(QTextBlock::iterator it, const QTextFragment &fragment, QTextDocument const *doc);
0152 
0153     /**
0154     Directs the builder to create output for the contents of the single @p
0155     textObject. The @p textObject is represented in the QTextDocument with the
0156     QTextFragment @p fragment.
0157 
0158     If calling this method directly, an invalid QTextBlock::iterator may be
0159     used.
0160   */
0161     [[nodiscard]] virtual QTextBlock::iterator processCharTextObject(QTextBlock::iterator it, const QTextFragment &fragment, QTextObject *textObject);
0162 
0163     /**
0164     Directs the builder to create output for the image represented by the @p
0165     imageFormat.
0166 
0167     If calling this method directly, an invalid QTextBlock::iterator may be
0168     used. @p doc is the document the fragment is in.
0169   */
0170     [[nodiscard]] virtual QTextBlock::iterator processImage(QTextBlock::iterator it, const QTextImageFormat &imageFormat, QTextDocument const *doc);
0171 
0172     /**
0173     Directs the builder to create output for the contents of the single @p
0174     table.
0175 
0176     If calling this method directly, an invalid QTextFrame::iterator may be
0177     used.
0178   */
0179     [[nodiscard]] virtual QTextFrame::iterator processTable(QTextFrame::iterator it, QTextTable *table);
0180 
0181     /**
0182     Directs the builder to create output for the contents of the single @p
0183     tableCell. The tableCell is in the @p table.
0184   */
0185     virtual void processTableCell(const QTextTableCell &tableCell, QTextTable *table);
0186 
0187 protected:
0188     /**
0189     Processes the document between @p begin and @p end
0190   */
0191     void processDocumentContents(QTextFrame::iterator begin, const QTextFrame::iterator &end);
0192 
0193     /**
0194     Iterates the iterator @p it to the first block after @p blockGroup. @p
0195     _block is any block in the @p blockGroup.
0196 
0197     The return pair is the iterator pointing after the end of @p blockGroup
0198     and the first block after @p blockGroup.
0199   */
0200     [[nodiscard]] QPair<QTextFrame::iterator, QTextBlock> skipBlockGroup(QTextFrame::iterator it, const QTextBlock &_block, QTextBlockGroup *blockGroup);
0201 
0202     /**
0203     Returns a list of tags contained in @p openingTags sorted so they can be
0204     opened in order and will be closed in the correct order.
0205 
0206     @p openingTags should be a set of tags opened at the fragment pointed to
0207     by @p it.
0208   */
0209     [[nodiscard]] QList<int> sortOpeningOrder(QSet<int> openingTags, QTextBlock::iterator it) const;
0210 
0211     /**
0212     Directs the builder to close the appropriate tags at the position of @p
0213     it.
0214   */
0215     virtual void processClosingElements(const QTextBlock::iterator &it);
0216 
0217     /**
0218     Directs the builder to open the appropriate tags at the position of @p it.
0219   */
0220     virtual void processOpeningElements(const QTextBlock::iterator &it);
0221 
0222     /**
0223     Returns the tags that should be closed at the position of @p it.
0224   */
0225     [[nodiscard]] virtual QSet<int> getElementsToClose(const QTextBlock::iterator &it) const;
0226 
0227     /**
0228     Returns the tags that should be opened at the position of @p it.
0229   */
0230     [[nodiscard]] virtual QList<int> getElementsToOpen(const QTextBlock::iterator &it);
0231 
0232     /**
0233     Flags for the tags that may be open.
0234   */
0235     enum OpenElementValues {
0236         None = 0x0, /// No tags are open
0237         SuperScript = 0x01, /// A superscript tag is open
0238         SubScript = 0x02, /// A subscript tag is open
0239         Anchor = 0x04, /// An anchor tag is open
0240         SpanForeground = 0x08, /// A foreground altering span tag is open.
0241         SpanBackground = 0x10, /// A background altering span tag is open.
0242         SpanFontFamily = 0x20, /// A font family altering span tag is open.
0243         SpanFontPointSize = 0x40, /// A font size altering span tag is open.
0244         Strong = 0x80, /// A strong tag is open.
0245         Emph = 0x100, /// A emphasis tag is open.
0246         Underline = 0x200, /// An underline tag is open.
0247         StrikeOut = 0x400 /// A strikeout tag is open.
0248     };
0249 
0250 protected:
0251 #ifndef Q_QDOC
0252     MarkupDirectorPrivate *const d_ptr;
0253 #endif
0254 
0255     /**
0256     The builder this MarkupDirector is operating on. This is available when
0257     subclassing to customize behaviour.
0258   */
0259     KPIMTextEdit::AbstractMarkupBuilder *const m_builder;
0260 
0261 #ifndef Q_QDOC
0262 private:
0263     Q_DECLARE_PRIVATE(MarkupDirector)
0264 #endif
0265 };
0266 }