/* -*- 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 #include #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; }; // SmCaretLinesVisitor: ancestor of caret rectangle enumeration and drawing visitors class SmCaretLinesVisitor : public SmDefaultingVisitor { public: SmCaretLinesVisitor(OutputDevice& rDevice, SmCaretPos position, Point offset); virtual ~SmCaretLinesVisitor() = default; void Visit(SmTextNode* pNode) override; using SmDefaultingVisitor::Visit; protected: void DoIt(); OutputDevice& getDev() { return mrDev; } virtual void ProcessCaretLine(Point from, Point to) = 0; virtual void ProcessUnderline(Point from, Point to) = 0; /** Default method for drawing pNodes */ void DefaultVisit(SmNode* pNode) override; private: OutputDevice& mrDev; SmCaretPos maPos; /** Offset to draw from */ Point maOffset; }; // SmCaretRectanglesVisitor: obtains the set of rectangles to sent to lok class SmCaretRectanglesVisitor final : public SmCaretLinesVisitor { public: SmCaretRectanglesVisitor(OutputDevice& rDevice, SmCaretPos position); const tools::Rectangle& getCaret() const { return maCaret; } protected: virtual void ProcessCaretLine(Point from, Point to) override; virtual void ProcessUnderline(Point from, Point to) override; private: tools::Rectangle maCaret; }; // SmCaretDrawingVisitor /** Visitor for drawing a caret position */ class SmCaretDrawingVisitor final : public SmCaretLinesVisitor { public: /** Given position and device this constructor will draw the caret */ SmCaretDrawingVisitor( OutputDevice& rDevice, SmCaretPos position, Point offset, bool caretVisible ); protected: virtual void ProcessCaretLine(Point from, Point to) override; virtual void ProcessUnderline(Point from, Point to) override; private: bool mbCaretVisible; }; // 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 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 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 ); }; // SmSelectionRectanglesVisitor: collect selection class SmSelectionRectanglesVisitor : public SmDefaultingVisitor { public: SmSelectionRectanglesVisitor(OutputDevice& rDevice, SmNode* pTree); virtual ~SmSelectionRectanglesVisitor() = default; void Visit( SmTextNode* pNode ) override; using SmDefaultingVisitor::Visit; const tools::Rectangle& GetSelection() { return maSelectionArea; } private: /** Reference to drawing device */ OutputDevice& mrDev; /** The current area that is selected */ tools::Rectangle maSelectionArea; /** Extend the area that must be selected */ void ExtendSelectionArea(const tools::Rectangle& rArea) { maSelectionArea.Union(rArea); } /** Default visiting method */ void DefaultVisit( SmNode* pNode ) override; /** Visit the children of a given pNode */ void VisitChildren( SmNode* pNode ); }; // SmSelectionDrawingVisitor class SmSelectionDrawingVisitor final : public SmSelectionRectanglesVisitor { public: /** Draws a selection on rDevice for the selection on pTree */ SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset ); }; // 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: */