/* This file is part of the KDE project Copyright (C) 2001 Andrea Rizzi Ulrich Kuettler This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SEQUENCEELEMENT_H #define SEQUENCEELEMENT_H #include #include #include "basicelement.h" class QKeyEvent; KFORMULA_NAMESPACE_BEGIN class SymbolTable; class ElementCreationStrategy; /** * The element that contains a number of children. * The children are aligned in one line. */ class SequenceElement : public BasicElement { SequenceElement& operator=( const SequenceElement& ) { return *this; } public: SequenceElement(BasicElement* parent = 0); ~SequenceElement(); SequenceElement( const SequenceElement& ); virtual SequenceElement* clone() { return new SequenceElement( *this ); } virtual bool accept( ElementVisitor* visitor ); /** * @returns whether its prohibited to change the sequence with this cursor. */ virtual bool readOnly( const FormulaCursor* ) const; /** * @returns true if the sequence contains only text. */ virtual bool isTextOnly() const { return textSequence; } /** * Sets the cursor and returns the element the point is in. * The handled flag shows whether the cursor has been set. * This is needed because only the innermost matching element * is allowed to set the cursor. */ virtual BasicElement* goToPos( FormulaCursor*, bool& handled, const LuPixelPoint& point, const LuPixelPoint& parentOrigin ); // drawing // // Drawing depends on a context which knows the required properties like // fonts, spaces and such. // It is essential to calculate elements size with the same context // before you draw. /** * Tells the sequence to have a smaller size than its parant. */ void setSizeReduction(const ContextStyle& context); /** * @returns true if there is no visible element in the sequence. * Please note that there might be phantom elements. */ bool isEmpty(); /** * Calculates our width and height and * our children's parentPosition. */ virtual void calcSizes( const ContextStyle& cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes& style ); /** * Draws the whole element including its children. * The `parentOrigin' is the point this element's parent starts. * We can use our parentPosition to get our own origin then. */ virtual void draw( QPainter& painter, const LuPixelRect& r, const ContextStyle& context, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes& style, const LuPixelPoint& parentOrigin ); /** * Dispatch this FontCommand to all our TextElement children. */ virtual void dispatchFontCommand( FontCommand* cmd ); virtual void drawEmptyRect( QPainter& painter, const ContextStyle& context, double factor, const LuPixelPoint& upperLeft ); virtual void calcCursorSize( const ContextStyle& context, FormulaCursor* cursor, bool smallCursor ); /** * If the cursor is inside a sequence it needs to be drawn. */ virtual void drawCursor( QPainter& painter, const ContextStyle& context, StyleAttributes& style, FormulaCursor* cursor, bool smallCursor, bool activeCursor ); // navigation // // The elements are responsible to handle cursor movement themselves. // To do this they need to know the direction the cursor moves and // the element it comes from. // // The cursor might be in normal or in selection mode. /** * Enters this element while moving to the left starting inside * the element `from'. Searches for a cursor position inside * this element or to the left of it. */ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from); /** * Enters this element while moving to the right starting inside * the element `from'. Searches for a cursor position inside * this element or to the right of it. */ virtual void moveRight(FormulaCursor* cursor, BasicElement* from); /** * Moves to the beginning of this word or if we are there already * to the beginning of the previous. */ virtual void moveWordLeft(FormulaCursor* cursor); /** * Moves to the end of this word or if we are there already * to the end of the next. */ virtual void moveWordRight(FormulaCursor* cursor); /** * Enters this element while moving up starting inside * the element `from'. Searches for a cursor position inside * this element or above it. */ virtual void moveUp(FormulaCursor* cursor, BasicElement* from); /** * Enters this element while moving down starting inside * the element `from'. Searches for a cursor position inside * this element or below it. */ virtual void moveDown(FormulaCursor* cursor, BasicElement* from); /** * Moves the cursor to the first position in this sequence. * (That is before the first child.) */ virtual void moveHome(FormulaCursor* cursor); /** * Moves the cursor to the last position in this sequence. * (That is behind the last child.) */ virtual void moveEnd(FormulaCursor* cursor); /** * Sets the cursor inside this element to its start position. * For most elements that is the main child. */ virtual void goInside(FormulaCursor* cursor); /** * Sets the cursor inside this element to its last position. * For most elements that is the main child. */ virtual void goInsideLast(FormulaCursor* cursor); // children /** * Inserts all new children at the cursor position. Places the * cursor according to the direction. The inserted elements will * be selected. * * The list will be emptied but stays the property of the caller. */ virtual void insert(FormulaCursor*, QPtrList&, Direction); /** * Removes all selected children and returns them. Places the * cursor to where the children have been. */ virtual void remove(FormulaCursor*, QPtrList&, Direction); /** * Moves the cursor to a normal place where new elements * might be inserted. */ virtual void normalize(FormulaCursor*, Direction); /** * Returns the child at the cursor. * Does not care about the selection. */ virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor); /** * Sets the cursor to select the child. The mark is placed before, * the position behind it. */ virtual void selectChild(FormulaCursor* cursor, BasicElement* child); /** * Moves the cursor away from the given child. The cursor is * guaranteed to be inside this element. */ virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child); /** * @returns the number of children we have. */ uint countChildren() const { return children.count(); } /** * @returns whether the child has the given number. */ bool isChildNumber( uint pos, BasicElement* child ) { return children.at( pos ) == child; } /** * Selects all children. The cursor is put behind, the mark before them. */ void selectAllChildren(FormulaCursor* cursor); bool onlyTextSelected( FormulaCursor* cursor ); /** * This is called by the container to get a command depending on * the current cursor position (this is how the element gets chosen) * and the request. * * @returns the command that performs the requested action with * the containers active cursor. */ virtual KCommand* buildCommand( Container*, Request* ); /** * Parses the input. It's the container which does create * new elements because it owns the undo stack. But only the * sequence knows what chars are allowed. */ virtual KCommand* input( Container* container, QChar ch ); virtual KCommand* input( Container* container, QKeyEvent* event ); /** * Parses the sequence and generates a new syntax tree. * Has to be called after each modification. */ virtual void parse(); /** * Stores the given childrens dom in the element. */ void getChildrenDom( QDomDocument& doc, QDomElement elem, uint from, uint to); /** * Stores the given childrens MathML dom in the element. */ void getChildrenMathMLDom( QDomDocument& doc, QDomNode& elem, uint from, uint to ); /** * Builds elements from the given node and its siblings and * puts them into the list. * Returns false if an error occures. */ bool buildChildrenFromDom(QPtrList& list, QDomNode n); /** * @returns the latex representation of the element and * of the element's children */ virtual QString toLatex(); virtual QString formulaString(); /** * @returns the child at position i. */ BasicElement* getChild(uint i) { return children.at(i); } const BasicElement* getChild(uint i) const; int childPos( BasicElement* child ) { return children.find( child ); } int childPos( const BasicElement* child ) const; class ChildIterator { public: ChildIterator( SequenceElement* sequence, int pos=0 ) : m_sequence( sequence ), m_pos( pos ) {} typedef BasicElement value_type; typedef BasicElement* pointer; typedef BasicElement& reference; // we simply expect the compared iterators to belong // to the same sequence. bool operator== ( const ChildIterator& it ) const { return /*m_sequence==it.m_sequence &&*/ m_pos==it.m_pos; } bool operator!= ( const ChildIterator& it ) const { return /*m_sequence!=it.m_sequence ||*/ m_pos!=it.m_pos; } const BasicElement& operator* () const { return *m_sequence->getChild( m_pos ); } BasicElement& operator* () { return *m_sequence->getChild( m_pos ); } BasicElement* operator->() const { return m_sequence->getChild( m_pos ); } ChildIterator& operator++ () { ++m_pos; return *this; } ChildIterator operator++ ( int ) { ChildIterator it( *this ); ++m_pos; return it; } ChildIterator& operator-- () { --m_pos; return *this; } ChildIterator operator-- ( int ) { ChildIterator it( *this ); --m_pos; return it; } ChildIterator& operator+= ( int j ) { m_pos+=j; return *this; } ChildIterator & operator-= ( int j ) { m_pos-=j; return *this; } private: SequenceElement* m_sequence; int m_pos; }; typedef ChildIterator iterator; iterator begin() { return ChildIterator( this, 0 ); } iterator end() { return ChildIterator( this, countChildren() ); } static void setCreationStrategy( ElementCreationStrategy* strategy ); virtual void setStyle(StyleElement *style); virtual int buildChildrenFromMathMLDom(QPtrList& list, QDomNode n); virtual int readContentFromMathMLDom(QDomNode& node); int buildMathMLChild( QDomNode node ); protected: //Save/load support /** * Returns the tag name of this element type. */ virtual QString getTagName() const { return "SEQUENCE"; } /** * Appends our attributes to the dom element. */ virtual void writeDom(QDomElement element); virtual QString getElementName() const { return "mrow"; } virtual void writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const; /** * Reads our attributes from the element. * Returns false if it failed. */ virtual bool readAttributesFromDom(QDomElement element); /** * Reads our content from the node. Sets the node to the next node * that needs to be read. * Returns false if it failed. */ virtual bool readContentFromDom(QDomNode& node); /** * Sets the childrens' positions after their size has been * calculated. * * @see #calcSizes */ virtual void setChildrenPositions(); /** * Creates a new element with the given type. * * @param type the desired type of the element */ virtual BasicElement* createElement(QString type, const QDomElement &element); /** * @returns the position where the child starts. * * @param context the context the child is in * @param child the child's number */ luPixel getChildPosition( const ContextStyle& context, uint child ); /** * @returns whether the child is the first element of its token. */ virtual bool isFirstOfToken( BasicElement* child ); /** * Insert a new child in the sequence * * @returns true if succesful, i.e. if index is in range, otherwise returns * false. The valid range is 0 to count(). The child is appended if index == count(). * * @param index position in the sequence to insert the child * @param child the child to insert in the sequence */ bool insert( uint index, BasicElement *child ); static ElementCreationStrategy* getCreationStrategy() { return creationStrategy; } /** * Space around sequence */ virtual luPt getSpaceBefore( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; } virtual luPt getSpaceAfter( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; } static ElementCreationStrategy* creationStrategy; private: /** * Removes the children at pos and appends it to the list. */ void removeChild(QPtrList& removedChildren, int pos); /** * Our children. Be sure to notify the rootElement before * you remove any. */ QPtrList children; /** * the syntax tree of the sequence */ ElementType* parseTree; /** * true if the sequence contains only text */ bool textSequence; bool singlePipe; //The key '|' produces one '|' not '| |', '||' produces '| |' StyleElement *style; }; /** * The sequence thats a name. Actually the purpose * is to be able to insert any element by keyboard. */ class NameSequence : public SequenceElement { typedef SequenceElement inherited; public: NameSequence( BasicElement* parent = 0 ); virtual NameSequence* clone() { return new NameSequence( *this ); } virtual bool accept( ElementVisitor* visitor ); /** * @returns true if the sequence contains only text. */ //virtual bool isTextOnly() const { return true; } /** * @returns the character that represents this element. Used for * parsing a sequence. * This is guaranteed to be QChar::null for all non-text elements. */ virtual QChar getCharacter() const { return '\\'; } /** * @returns the type of this element. Used for * parsing a sequence. */ virtual TokenType getTokenType() const { return NAME; } /** * We are our own main child. This causes interessting effects. */ virtual SequenceElement* getMainChild() { return this; } virtual void calcCursorSize( const ContextStyle& context, FormulaCursor* cursor, bool smallCursor ); /** * If the cursor is inside a sequence it needs to be drawn. */ virtual void drawCursor( QPainter& painter, const ContextStyle& context, StyleAttributes& style, FormulaCursor* cursor, bool smallCursor, bool activeCursor ); /** * Moves to the beginning of this word or if we are there already * to the beginning of the previous. */ virtual void moveWordLeft(FormulaCursor* cursor); /** * Moves to the end of this word or if we are there already * to the end of the next. */ virtual void moveWordRight(FormulaCursor* cursor); /** * This is called by the container to get a command depending on * the current cursor position (this is how the element gets chosen) * and the request. * * @returns the command that performs the requested action with * the containers active cursor. */ virtual KCommand* buildCommand( Container*, Request* ); /** * Parses the input. It's the container which does create * new elements because it owns the undo stack. But only the * sequence knows what chars are allowed. */ virtual KCommand* input( Container* container, QChar ch ); /** * Sets a new type. This is done during parsing. */ virtual void setElementType( ElementType* t ); /** * @returns the element this sequence is to be replaced with. */ BasicElement* replaceElement( const SymbolTable& table ); /** * Tests whether the selected elements can be inserted in a * name sequence. */ static bool isValidSelection( FormulaCursor* cursor ); protected: /** * Returns the tag name of this element type. */ virtual QString getTagName() const { return "NAMESEQUENCE"; } virtual QString getElementName() const { return "mi"; } /** * Creates a new element with the given type. * * @param type the desired type of the element */ virtual BasicElement* createElement( QString type ); /** * Parses the sequence and generates a new syntax tree. * Has to be called after each modification. */ //virtual void parse(); /** * @returns whether the child is the first element of its token. * This can never happen here. Our children reuse our own * element type. */ virtual bool isFirstOfToken( BasicElement* ) { return false; } private: KCommand* compactExpressionCmd( Container* container ); QString buildName(); }; KFORMULA_NAMESPACE_END #endif // SEQUENCEELEMENT_H