diff options
Diffstat (limited to '')
-rw-r--r-- | starmath/inc/visitors.hxx | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/starmath/inc/visitors.hxx b/starmath/inc/visitors.hxx new file mode 100644 index 000000000..27c4e374e --- /dev/null +++ b/starmath/inc/visitors.hxx @@ -0,0 +1,486 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/** Visitors are an easy way to automating operations with nodes. + * + * The available visitors are: + * SmVisitor base class + * SmDefaultingVisitor default visitor + * SmDrawingVisitor draws formula + * SmCaretPosGraphBuildingVisitor position of the node inside starmath code + * SmCloningVisitor duplicate nodes + * SmNodeToTextVisitor create code from nodes + * + */ + +#pragma once + +#include <sal/config.h> +#include <sal/log.hxx> + +#include "node.hxx" +#include "caret.hxx" + +/** Base class for visitors that visits a tree of SmNodes + * @remarks all methods have been left abstract to ensure that implementers + * don't forget to implement one. + */ +class SmVisitor +{ +public: + virtual void Visit( SmTableNode* pNode ) = 0; + virtual void Visit( SmBraceNode* pNode ) = 0; + virtual void Visit( SmBracebodyNode* pNode ) = 0; + virtual void Visit( SmOperNode* pNode ) = 0; + virtual void Visit( SmAlignNode* pNode ) = 0; + virtual void Visit( SmAttributeNode* pNode ) = 0; + virtual void Visit( SmFontNode* pNode ) = 0; + virtual void Visit( SmUnHorNode* pNode ) = 0; + virtual void Visit( SmBinHorNode* pNode ) = 0; + virtual void Visit( SmBinVerNode* pNode ) = 0; + virtual void Visit( SmBinDiagonalNode* pNode ) = 0; + virtual void Visit( SmSubSupNode* pNode ) = 0; + virtual void Visit( SmMatrixNode* pNode ) = 0; + virtual void Visit( SmPlaceNode* pNode ) = 0; + virtual void Visit( SmTextNode* pNode ) = 0; + virtual void Visit( SmSpecialNode* pNode ) = 0; + virtual void Visit( SmGlyphSpecialNode* pNode ) = 0; + virtual void Visit( SmMathSymbolNode* pNode ) = 0; + virtual void Visit( SmBlankNode* pNode ) = 0; + virtual void Visit( SmErrorNode* pNode ) = 0; + virtual void Visit( SmLineNode* pNode ) = 0; + virtual void Visit( SmExpressionNode* pNode ) = 0; + virtual void Visit( SmPolyLineNode* pNode ) = 0; + virtual void Visit( SmRootNode* pNode ) = 0; + virtual void Visit( SmRootSymbolNode* pNode ) = 0; + virtual void Visit( SmRectangleNode* pNode ) = 0; + virtual void Visit( SmVerticalBraceNode* pNode ) = 0; + +protected: + ~SmVisitor() {} +}; + +// SmDefaultingVisitor + + +/** Visitor that uses DefaultVisit for handling visits by default + * + * This abstract baseclass is useful for visitors where many methods share the same + * implementation. + */ +class SmDefaultingVisitor : public SmVisitor +{ +public: + void Visit( SmTableNode* pNode ) override; + void Visit( SmBraceNode* pNode ) override; + void Visit( SmBracebodyNode* pNode ) override; + void Visit( SmOperNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + void Visit( SmAttributeNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmBinVerNode* pNode ) override; + void Visit( SmBinDiagonalNode* pNode ) override; + void Visit( SmSubSupNode* pNode ) override; + void Visit( SmMatrixNode* pNode ) override; + void Visit( SmPlaceNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmSpecialNode* pNode ) override; + void Visit( SmGlyphSpecialNode* pNode ) override; + void Visit( SmMathSymbolNode* pNode ) override; + void Visit( SmBlankNode* pNode ) override; + void Visit( SmErrorNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmPolyLineNode* pNode ) override; + void Visit( SmRootNode* pNode ) override; + void Visit( SmRootSymbolNode* pNode ) override; + void Visit( SmRectangleNode* pNode ) override; + void Visit( SmVerticalBraceNode* pNode ) override; +protected: + ~SmDefaultingVisitor() {} + + /** Method invoked by Visit methods by default */ + virtual void DefaultVisit( SmNode* pNode ) = 0; +}; + +// SmCaretDrawingVisitor + +/** Visitor for drawing a caret position */ +class SmCaretDrawingVisitor final : public SmDefaultingVisitor +{ +public: + /** Given position and device this constructor will draw the caret */ + SmCaretDrawingVisitor( OutputDevice& rDevice, SmCaretPos position, Point offset, bool caretVisible ); + virtual ~SmCaretDrawingVisitor() {} + void Visit( SmTextNode* pNode ) override; + using SmDefaultingVisitor::Visit; +private: + OutputDevice &mrDev; + SmCaretPos maPos; + /** Offset to draw from */ + Point maOffset; + bool mbCaretVisible; + + /** Default method for drawing pNodes */ + void DefaultVisit( SmNode* pNode ) override; +}; + +// SmCaretPos2LineVisitor + +/** Visitor getting a line from a caret position */ +class SmCaretPos2LineVisitor final : public SmDefaultingVisitor +{ +public: + /** Given position and device this constructor will compute a line for the caret */ + SmCaretPos2LineVisitor( OutputDevice *pDevice, SmCaretPos position ) + : mpDev( pDevice ) + , maPos( position ) + { + SAL_WARN_IF( !position.IsValid(), "starmath", "Cannot draw invalid position!" ); + + maPos.pSelectedNode->Accept( this ); + } + virtual ~SmCaretPos2LineVisitor() {} + void Visit( SmTextNode* pNode ) override; + using SmDefaultingVisitor::Visit; + const SmCaretLine& GetResult( ) const { + return maLine; + } +private: + SmCaretLine maLine; + VclPtr<OutputDevice> mpDev; + SmCaretPos maPos; + + /** Default method for computing lines for pNodes */ + void DefaultVisit( SmNode* pNode ) override; +}; + +// SmDrawingVisitor + +/** Visitor for drawing SmNodes to OutputDevice */ +class SmDrawingVisitor final : public SmVisitor +{ +public: + /** Create an instance of SmDrawingVisitor, and use it to draw a formula + * @param rDevice Device to draw on + * @param position Offset on device to draw the formula + * @param pTree Formula tree to draw + * @remarks This constructor will do the drawing, no need to anything more. + */ + SmDrawingVisitor( OutputDevice &rDevice, Point position, SmNode* pTree ) + : mrDev( rDevice ) + , maPosition( position ) + { + pTree->Accept( this ); + } + virtual ~SmDrawingVisitor() {} + void Visit( SmTableNode* pNode ) override; + void Visit( SmBraceNode* pNode ) override; + void Visit( SmBracebodyNode* pNode ) override; + void Visit( SmOperNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + void Visit( SmAttributeNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmBinVerNode* pNode ) override; + void Visit( SmBinDiagonalNode* pNode ) override; + void Visit( SmSubSupNode* pNode ) override; + void Visit( SmMatrixNode* pNode ) override; + void Visit( SmPlaceNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmSpecialNode* pNode ) override; + void Visit( SmGlyphSpecialNode* pNode ) override; + void Visit( SmMathSymbolNode* pNode ) override; + void Visit( SmBlankNode* pNode ) override; + void Visit( SmErrorNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmPolyLineNode* pNode ) override; + void Visit( SmRootNode* pNode ) override; + void Visit( SmRootSymbolNode* pNode ) override; + void Visit( SmRectangleNode* pNode ) override; + void Visit( SmVerticalBraceNode* pNode ) override; +private: + /** Draw the children of a pNode + * This the default method, use by most pNodes + */ + void DrawChildren( SmStructureNode* pNode ); + + /** Draw an SmTextNode or a subclass of this */ + void DrawTextNode( SmTextNode* pNode ); + /** Draw an SmSpecialNode or a subclass of this */ + void DrawSpecialNode( SmSpecialNode* pNode ); + /** OutputDevice to draw on */ + OutputDevice& mrDev; + /** Position to draw on the mrDev + * @remarks This variable is used to pass parameters in DrawChildren( ), this means + that after a call to DrawChildren( ) the contents of this method is undefined + so if needed cache it locally on the stack. + */ + Point maPosition; +}; + +// SmSetSelectionVisitor + +/** Set Selection Visitor + * Sets the IsSelected( ) property on all SmNodes of the tree + */ +class SmSetSelectionVisitor final : public SmDefaultingVisitor +{ +public: + SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pNode); + virtual ~SmSetSelectionVisitor() {} + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + using SmDefaultingVisitor::Visit; + /** Set IsSelected on all pNodes of pSubTree */ + static void SetSelectedOnAll( SmNode* pSubTree, bool IsSelected = true ); +private: + /** Visit a selectable pNode + * Can be used to handle pNodes that can be selected, that doesn't have more SmCaretPos' + * than 0 and 1 inside them. SmTextNode should be handle separately! + * Also note that pNodes such as SmBinVerNode cannot be selected, don't this method for + * it. + */ + void DefaultVisit( SmNode* pNode ) override; + void VisitCompositionNode( SmStructureNode* pNode ); + /** Caret position where the selection starts */ + SmCaretPos maStartPos; + /** Caret position where the selection ends */ + SmCaretPos maEndPos; + /** The current state of this visitor + * This property changes when the visitor meets either maStartPos + * or maEndPos. This means that anything visited in between will be + * selected. + */ + bool mbSelecting; +}; + + +// SmCaretPosGraphBuildingVisitor + + +/** A visitor for building a SmCaretPosGraph + * + * Visit invariant: + * Each pNode, except SmExpressionNode, SmBinHorNode and a few others, constitutes an entry + * in a line. Consider the line entry "H", this entry creates one carat position, here + * denoted by | in "H|". + * + * Parameter variables: + * The following variables are used to transfer parameters into calls and results out + * of calls. + * pRightMost : SmCaretPosGraphEntry* + * + * Prior to a Visit call: + * pRightMost: A pointer to right most position in front of the current line entry. + * + * After a Visit call: + * pRightMost: A pointer to the right most position in the called line entry, if no there's + * no caret positions in called line entry don't change this variable. + */ +class SmCaretPosGraphBuildingVisitor final : public SmVisitor +{ +public: + /** Builds a caret position graph for pRootNode */ + explicit SmCaretPosGraphBuildingVisitor( SmNode* pRootNode ); + virtual ~SmCaretPosGraphBuildingVisitor(); + void Visit( SmTableNode* pNode ) override; + void Visit( SmBraceNode* pNode ) override; + void Visit( SmBracebodyNode* pNode ) override; + void Visit( SmOperNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + void Visit( SmAttributeNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmBinVerNode* pNode ) override; + void Visit( SmBinDiagonalNode* pNode ) override; + void Visit( SmSubSupNode* pNode ) override; + void Visit( SmMatrixNode* pNode ) override; + void Visit( SmPlaceNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmSpecialNode* pNode ) override; + void Visit( SmGlyphSpecialNode* pNode ) override; + void Visit( SmMathSymbolNode* pNode ) override; + void Visit( SmBlankNode* pNode ) override; + void Visit( SmErrorNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmPolyLineNode* pNode ) override; + void Visit( SmRootNode* pNode ) override; + void Visit( SmRootSymbolNode* pNode ) override; + void Visit( SmRectangleNode* pNode ) override; + void Visit( SmVerticalBraceNode* pNode ) override; + SmCaretPosGraph* takeGraph() + { + return mpGraph.release(); + } +private: + SmCaretPosGraphEntry* mpRightMost; + std::unique_ptr<SmCaretPosGraph> mpGraph; +}; + +// SmCloningVisitor + +/** Visitor for cloning a pNode + * + * This visitor creates deep clones. + */ +class SmCloningVisitor final : public SmVisitor +{ +public: + SmCloningVisitor() + : mpResult(nullptr) + {} + virtual ~SmCloningVisitor() {} + void Visit( SmTableNode* pNode ) override; + void Visit( SmBraceNode* pNode ) override; + void Visit( SmBracebodyNode* pNode ) override; + void Visit( SmOperNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + void Visit( SmAttributeNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmBinVerNode* pNode ) override; + void Visit( SmBinDiagonalNode* pNode ) override; + void Visit( SmSubSupNode* pNode ) override; + void Visit( SmMatrixNode* pNode ) override; + void Visit( SmPlaceNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmSpecialNode* pNode ) override; + void Visit( SmGlyphSpecialNode* pNode ) override; + void Visit( SmMathSymbolNode* pNode ) override; + void Visit( SmBlankNode* pNode ) override; + void Visit( SmErrorNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmPolyLineNode* pNode ) override; + void Visit( SmRootNode* pNode ) override; + void Visit( SmRootSymbolNode* pNode ) override; + void Visit( SmRectangleNode* pNode ) override; + void Visit( SmVerticalBraceNode* pNode ) override; + /** Clone a pNode */ + SmNode* Clone( SmNode* pNode ); +private: + SmNode* mpResult; + /** Clone children of pSource and give them to pTarget */ + void CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget ); + /** Clone attributes on a pNode */ + static void CloneNodeAttr( SmNode const * pSource, SmNode* pTarget ); +}; + + +// SmSelectionDrawingVisitor + +class SmSelectionDrawingVisitor final : public SmDefaultingVisitor +{ +public: + /** Draws a selection on rDevice for the selection on pTree */ + SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset ); + virtual ~SmSelectionDrawingVisitor() {} + void Visit( SmTextNode* pNode ) override; + using SmDefaultingVisitor::Visit; +private: + /** Reference to drawing device */ + OutputDevice& mrDev; + /** True if aSelectionArea have been initialized */ + bool mbHasSelectionArea; + /** The current area that is selected */ + tools::Rectangle maSelectionArea; + /** Extend the area that must be selected */ + void ExtendSelectionArea(const tools::Rectangle& rArea); + /** Default visiting method */ + void DefaultVisit( SmNode* pNode ) override; + /** Visit the children of a given pNode */ + void VisitChildren( SmNode* pNode ); +}; + +// SmNodeToTextVisitor + +/** Extract command text from pNodes */ +class SmNodeToTextVisitor final : public SmVisitor +{ +public: + SmNodeToTextVisitor( SmNode* pNode, OUString &rText ); + virtual ~SmNodeToTextVisitor() {} + + void Visit( SmTableNode* pNode ) override; + void Visit( SmBraceNode* pNode ) override; + void Visit( SmBracebodyNode* pNode ) override; + void Visit( SmOperNode* pNode ) override; + void Visit( SmAlignNode* pNode ) override; + void Visit( SmAttributeNode* pNode ) override; + void Visit( SmFontNode* pNode ) override; + void Visit( SmUnHorNode* pNode ) override; + void Visit( SmBinHorNode* pNode ) override; + void Visit( SmBinVerNode* pNode ) override; + void Visit( SmBinDiagonalNode* pNode ) override; + void Visit( SmSubSupNode* pNode ) override; + void Visit( SmMatrixNode* pNode ) override; + void Visit( SmPlaceNode* pNode ) override; + void Visit( SmTextNode* pNode ) override; + void Visit( SmSpecialNode* pNode ) override; + void Visit( SmGlyphSpecialNode* pNode ) override; + void Visit( SmMathSymbolNode* pNode ) override; + void Visit( SmBlankNode* pNode ) override; + void Visit( SmErrorNode* pNode ) override; + void Visit( SmLineNode* pNode ) override; + void Visit( SmExpressionNode* pNode ) override; + void Visit( SmPolyLineNode* pNode ) override; + void Visit( SmRootNode* pNode ) override; + void Visit( SmRootSymbolNode* pNode ) override; + void Visit( SmRectangleNode* pNode ) override; + void Visit( SmVerticalBraceNode* pNode ) override; +private: + + /** + * Extract text from a pNode that constitutes a line. + * @param pNode + * @return + */ + void LineToText( SmNode* pNode ) { + Separate( ); + if( pNode ) pNode->Accept( this ); + Separate( ); + } + + /** + * Appends rText to the OUStringBuffer ( maCmdText ). + * @param rText + * @return + */ + void Append( std::u16string_view rText ) { + maCmdText.append( rText ); + } + + /** + * Append a blank for separation, if needed. + * It is needed if last char is not ' '. + * @return + */ + void Separate( ){ + if( !maCmdText.isEmpty() && maCmdText[ maCmdText.getLength() - 1 ] != ' ' ) + maCmdText.append(' '); + } + + /** Output text generated from the pNodes */ + OUStringBuffer maCmdText; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |