#ifndef KOTEXTPARAG_H #define KOTEXTPARAG_H /* This file is part of the KDE project Copyright (C) 2001-2005 David Faure 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. */ // -*- c++ -*- #include "KoParagLayout.h" #include "KoTextFormat.h" #include "KoRichText.h" // for KoTextString class KoTextFormatterBase; class KoTextParagLineStart; class KoTextString; class KoTextDocument; class KoParagCounter; class KoParagStyle; class KoTextCustomItem; class KoOasisContext; class KoSavingContext; class KoStyleCollection; struct KoTextParagSelection { int start, end; }; #if defined(TQ_TEMPLATEDLL) // TQMOC_SKIP_BEGIN template class TQMap; template class TQMap; // TQMOC_SKIP_END #endif class KOTEXT_EXPORT KoTextParag { friend class KoTextDocument; friend class KoTextCursor; public: KoTextParag( KoTextDocument *d, KoTextParag *pr = 0, KoTextParag *nx = 0, bool updateIds = TRUE ); virtual ~KoTextParag(); KoTextString *string() const; KoTextStringChar *at( int i ) const; int leftGap() const; int length() const; // Abstraction over the trailing-space thing, so that it can be removed later int lastCharPos() const { return str->length()-2; } void setFormat( KoTextFormat *fm ); KoTextFormat *paragFormat() const; KoTextDocument *document() const; TQRect rect() const; void setRect( const TQRect& rect ) { r = rect; } void setHeight( int h ) { r.setHeight( h ); } void setWidth( int w ) { r.setWidth( w ); } void show(); void hide(); bool isVisible() const { return visible; } KoTextParag *prev() const; KoTextParag *next() const; void setPrev( KoTextParag *s ); void setNext( KoTextParag *s ); void insert( int index, const TQString &s ); void append( const TQString &s, bool reallyAtEnd = FALSE ); void truncate( int index ); void remove( int index, int len ); void move( int &dy ); void format( int start = -1, bool doMove = TRUE ); /// Call this to ensure that format() will be called on this paragraph later on void tqinvalidate( int chr /*ignored*/ = 0 ); /// Returns false if format() needs to be called on this paragraph bool isValid() const; /// 'changed' tells the painting code what it needs to paint bool hasChanged() const; void setChanged( bool b, bool recursive = FALSE ); short int lineChanged(); // first line that has been changed. void setLineChanged( short int line ); int lineHeightOfChar( int i, int *bl = 0, int *y = 0 ) const; KoTextStringChar *lineStartOfChar( int i, int *index = 0, int *line = 0 ) const; int lines() const; KoTextStringChar *lineStartOfLine( int line, int *index = 0 ) const; int lineY( int l ) const; int lineBaseLine( int l ) const; int lineHeight( int l ) const; void lineInfo( int l, int &y, int &h, int &bl ) const; void setSelection( int id, int start, int end ); void removeSelection( int id ); int selectionStart( int id ) const; int selectionEnd( int id ) const; bool hasSelection( int id ) const; bool hasAnySelection() const; bool fullSelected( int id ) const; //void setEndState( int s ); //int endState() const; void setParagId( int i ); int paragId() const; TQMap &lineStartList(); void setFormat( int index, int len, const KoTextFormat *f, bool useCollection = TRUE, int flags = -1 ); void setAlignment( uint a ); void setAlignmentDirect( uint a ) { align = a; } uint tqalignment() const; virtual void paint( TQPainter &painter, const TQColorGroup &cg, KoTextCursor *cursor, bool drawSelections, int clipx, int clipy, int clipw, int cliph ); // kotextparag.cc int topMargin() const; int bottomMargin() const; int leftMargin() const; int firstLineMargin() const; int rightMargin() const; int lineSpacing( int line ) const; int calculateLineSpacing( int line, int start, int last ) const; void registerFloatingItem( KoTextCustomItem *i ); void unregisterFloatingItem( KoTextCustomItem *i ); void setFullWidth( bool b ) { fullWidth = b; } bool isFullWidth() const { return fullWidth; } int customItems() const; void setDocumentRect( const TQRect &r ); int documentWidth() const; //int documentVisibleWidth() const; int documentX() const; int documentY() const; KoTextFormatCollection *formatCollection() const; //void setFormatter( KoTextFormatterBase *f ); KoTextFormatterBase *formatter() const; //int minimumWidth() const; int widthUsed() const; int nextTabDefault( int i, int x ); int nextTab( int i, int x, int availableWidth ); int *tabArray() const; void setTabArray( int *a ); void setTabStops( int tw ); /// Set whether '\n' should break the paragraph into multiple lines /// Not used void setNewLinesAllowed( bool b ); /// Return whether '\n' should break the paragraph into multiple lines bool isNewLinesAllowed() const; virtual void join( KoTextParag *s ); virtual void copyParagData( KoTextParag *parag ); //void setBreakable( bool b ) { breakable = b; } //bool isBreakable() const { return breakable; } void setMovedDown( bool b ) { movedDown = b; } bool wasMovedDown() const { return movedDown; } void setDirection( TQChar::Direction d ); TQChar::Direction direction() const; /// Mark a paragraph as being part of the table of contents (kword only) void setPartOfTableOfContents( bool b ) { m_toc = b; } bool partOfTableOfContents() const { return m_toc; } // For KoTextFormatter only void insertLineStart( int index, KoTextParagLineStart *ls ); protected: void drawLabel( TQPainter* p, int x, int y, int w, int h, int base, const TQColorGroup& cg ); void drawCursorDefault( TQPainter &painter, KoTextCursor *cursor, int curx, int cury, int curh, const TQColorGroup &cg ); void drawCursor( TQPainter &painter, KoTextCursor *cursor, int curx, int cury, int curh, const TQColorGroup &cg ); /** * We extend KoTextParag with more (zoom-aware) features, * like linespacing, borders, counter, tabulators, etc. * This also implements WYSIWYG text drawing. */ public: KoTextDocument * textDocument() const { return document(); } KoTextFormat * paragraphFormat() const { return static_cast( paragFormat() ); } /** Sets all or some parameters from a paragLayout struct. * @param flags selects which settings to apply, see KoParagLayout's enum. */ virtual void setParagLayout( const KoParagLayout &tqlayout, int flags = KoParagLayout::All, int marginIndex = -1 ); const KoParagLayout & paragLayout() { return m_layout; } // Margins double margin( TQStyleSheetItem::Margin m ) { return m_layout.margins[m]; } const double * margins() const { return m_layout.margins; } void setMargin( TQStyleSheetItem::Margin m, double _i ); void setMargins( const double * _i ); /** Line spacing in pt if >=0, can also be one of the LS_* values */ double kwLineSpacing() const { return m_layout.lineSpacingValue(); } void setLineSpacing( double _i ); KoParagLayout::SpacingType kwLineSpacingType() const { return m_layout.lineSpacingType; } void setLineSpacingType( KoParagLayout::SpacingType _type ); /** Use this to change the paragraph tqalignment, not KoTextParag::setAlignment ! */ void setAlign( int align ); /** Return the real tqalignment: Auto is resolved to either Left or Right */ int resolveAlignment() const; /// The part of the top margin that can be broken by a page break /// Obviously the non-breakable part (e.g. border width) is topMargin()-breakableTopMargin() int breakableTopMargin() const; // Borders KoBorder leftBorder() const { return m_layout.leftBorder; } KoBorder rightBorder() const { return m_layout.rightBorder; } KoBorder topBorder() const { return m_layout.topBorder; } KoBorder bottomBorder() const { return m_layout.bottomBorder; } bool hasBorder() const { return m_layout.hasBorder(); } bool joinBorder() const { return m_layout.joinBorder; } void setLeftBorder( const KoBorder & _brd ) { m_layout.leftBorder = _brd; } void setRightBorder( const KoBorder & _brd ) { m_layout.rightBorder = _brd; } void setTopBorder( const KoBorder & _brd ); void setBottomBorder( const KoBorder & _brd ); void setJoinBorder( bool join ); // Paragraph background TQColor backgroundColor() { return m_layout.backgroundColor; } void setBackgroundColor( const TQColor& color); // Counters are used to implement list and heading numbering/bullets. void setCounter( const KoParagCounter & counter ); void setNoCounter(); void setCounter( const KoParagCounter * pCounter ); KoParagCounter *counter(); /** The space required to draw the complete counter label (i.e. the Counter for this * paragraph, as well as the Counters for any paragraphs above us in the numbering * hierarchy). @see drawLabel(). */ int counterWidth() const; /** Style used by this paragraph */ KoParagStyle *style() const { return m_layout.style; } /** Sets the style in this paragraph, but doesn't _apply_ it, only sets a reference */ void setStyle( KoParagStyle *style ) { m_layout.style = style; } /** Applies the style directly (without undo/redo! See KoTextObject for the full command) */ void applyStyle( KoParagStyle *style ); /** Get tabulator positions */ const KoTabulatorList& tabList() const { return m_layout.tabList(); } /** Set tabulator positions */ void setTabList( const KoTabulatorList &tabList ); /** Return the X for the shadow distance in pixels (zoomed) */ int shadowX( KoTextZoomHandler *zh ) const; /** Return the Y for the shadow distance in pixels (zoomed) */ int shadowY( KoTextZoomHandler *zh ) const; /** Return the Y for the shadow distance in pt */ double shadowDistanceY() const; /** Set a @p custom item at position @p index, with format @p currentFormat (convenience method) */ void setCustomItem( int index, KoTextCustomItem * custom, KoTextFormat * currentFormat ); /** Remove the custom item from position @p index, but doesn't delete it */ void removeCustomItem( int index ); /** Find a custom item that we know is somewhere in this paragraph * Returns the index in the paragraph */ int findCustomItem( const KoTextCustomItem * custom ) const; /** Cache to find a tab by char index, TQMap */ TQMap& tabCache() { return m_tabCache; } /** @return the parag rect, in pixels. This takes care of some rounding problems */ TQRect pixelRect( KoTextZoomHandler* zh ) const; /** draw underline and double underline. Static because it's used * for draw double/simple in variable. */ static void drawFontEffects( TQPainter * p, KoTextFormat *format, KoTextZoomHandler *zh, TQFont font, const TQColor & color, int startX, int baseLine, int bw, int y, int h, TQChar firstChar ); /** a bit more clever than KoTextString::toString, e.g. with numbered lists */ TQString toString( int from = 0, int length = 0xffffffff) const; /// The app should call this during formatting - e.g. in formatVertically void fixParagWidth( bool viewFormattingChars ); /// Load from XML virtual void loadOasis( const TQDomElement& e, KoOasisContext& context, KoStyleCollection *styleCollection, uint& pos ); /// Save to XML /// By default the whole paragraph is saved. from/to allow to save only a portion of it. /// The 'from' and 'to' characters are both included. virtual void saveOasis( KoXmlWriter& writer, KoSavingContext& context, int from, int to, bool saveAnchorsFramesets = false ) const; /** * Load a section of text from a oasis based xml tree. * @param parent the xml element that has content as tqchildren. * @param context the context * @param stripLeadingSpace whether to remove leading literal whitespace */ void loadOasisSpan( const TQDomElement& parent, KoOasisContext& context, uint& pos, bool stripLeadingSpace = false ); /** * Load a section of text from a oasis based xml tree. * @param parent the xml element that has content as tqchildren. * @param context the context * @param stripLeadingSpace whether to remove leading literal whitespace * @param hasTrailingSpace whether there was trailing literal whitespace in the span's text */ void loadOasisSpan( const TQDomElement& parent, KoOasisContext& context, uint& pos, bool stripLeadingSpace, bool *hasTrailingSpace ); void applyListStyle( KoOasisContext& context, int restartNumbering, bool orderedList, bool heading, int level ); #ifndef NDEBUG void printRTDebug( int ); #endif protected: void invalidateCounters(); bool lineHyphenated( int l ) const; void paintLines( TQPainter &painter, const TQColorGroup &cg, KoTextCursor *cursor, bool drawSelections, int clipx, int clipy, int clipw, int cliph ); void drawParagString( TQPainter &painter, const TQString &str, int start, int len, int startX, int lastY, int baseLine, int bw, int h, bool drawSelections, KoTextFormat *lastFormat, const TQMemArray &selectionStarts, const TQMemArray &selectionEnds, const TQColorGroup &cg, bool rightToLeft, int line ); void drawParagStringInternal( TQPainter &painter, const TQString &s, int start, int len, int startX, int lastY, int baseLine, int bw, int h, bool drawSelections, KoTextFormat *lastFormat, const TQMemArray &selectionStarts, const TQMemArray &selectionEnds, const TQColorGroup &cg, bool rightToLeft, int line, KoTextZoomHandler* zh, bool drawingShadow ); /// Bitfield for drawFormattingChars's "whichFormattingChars" param enum { FormattingSpace = 1, FormattingBreak = 2, FormattingEndParag = 4, FormattingTabs = 8, AllFormattingChars = FormattingSpace | FormattingBreak | FormattingEndParag | FormattingTabs }; /// Called by drawParagStringInternal to draw the formatting characters, if the /// kotextdocument drawingflag for it was set. /// The last arg is a bit special: drawParagStringInternal always sets it to "all", /// but reimplementations can change its value. virtual void drawFormattingChars( TQPainter &painter, int start, int len, int lastY_pix, int baseLine_pix, int h_pix, // in pixels bool drawSelections, KoTextFormat *format, const TQMemArray &selectionStarts, const TQMemArray &selectionEnds, const TQColorGroup &cg, bool rightToLeft, int line, KoTextZoomHandler* zh, int whichFormattingChars ); protected: KoParagLayout m_layout; TQMap m_tabCache; private: KoParagLayout loadParagLayout( KoOasisContext& context, KoStyleCollection *styleCollection, bool findStyle ); /////// End of kotext-specific additions private: TQMap &selections() const; TQPtrList &floatingItems() const; /// Returns the height of the biggest character in that line int heightForLineSpacing( int startChar, int lastChar ) const; TQMap lineStarts; TQRect r; KoTextParag *p, *n; KoTextDocument *doc; bool m_invalid : 1; bool changed : 1; bool fullWidth : 1; bool newLinesAllowed : 1; bool visible : 1; bool movedDown : 1; bool m_toc : 1; uint align : 4; short int m_lineChanged; int id; int m_wused; KoTextString *str; TQMap *mSelections; TQPtrList *mFloatingItems; KoTextFormat *defFormat; // is this really used? int *tArray; // Those things are used by TQRT for the case of a paragraph without document // We don't use this currently, and it's not worth making EVERY parag bigger // just for a special case that's rarely used. Better have lightweight KoTextDocument // replacement (with common base class), if we ever want efficient single-parag docs... //int tabStopWidth; //TQRect docRect; //KoTextFormatterBase *pFormatter; //KoTextDocCommandHistory *commandHistory; }; inline int KoTextParag::length() const { return str->length(); } inline TQRect KoTextParag::rect() const { return r; } inline KoTextStringChar *KoTextParag::at( int i ) const { return &str->at( i ); } inline bool KoTextParag::isValid() const { return !m_invalid; } inline bool KoTextParag::hasChanged() const { return changed; } inline short int KoTextParag::lineChanged() { return m_lineChanged; } inline void KoTextParag::append( const TQString &s, bool reallyAtEnd ) { if ( reallyAtEnd ) insert( str->length(), s ); else insert( TQMAX( str->length() - 1, 0 ), s ); } inline KoTextParag *KoTextParag::prev() const { return p; } inline KoTextParag *KoTextParag::next() const { return n; } inline bool KoTextParag::hasAnySelection() const { return mSelections ? !selections().isEmpty() : FALSE; } /*inline void KoTextParag::setEndState( int s ) { if ( s == state ) return; state = s; } inline int KoTextParag::endState() const { return state; }*/ inline void KoTextParag::setParagId( int i ) { id = i; } inline int KoTextParag::paragId() const { //if ( id == -1 ) // kdWarning() << "invalid parag id!!!!!!!! (" << (void*)this << ")" << endl; return id; } inline TQMap &KoTextParag::lineStartList() { return lineStarts; } inline KoTextString *KoTextParag::string() const { return str; } inline KoTextDocument *KoTextParag::document() const { return doc; } inline void KoTextParag::setAlignment( uint a ) { if ( a == align ) return; align = a; tqinvalidate( 0 ); } /*inline void KoTextParag::setListStyle( TQStyleSheetItem::ListStyle ls ) { lstyle = ls; tqinvalidate( 0 ); } inline TQStyleSheetItem::ListStyle KoTextParag::listStyle() const { return lstyle; }*/ inline KoTextFormat *KoTextParag::paragFormat() const { return defFormat; } inline void KoTextParag::registerFloatingItem( KoTextCustomItem *i ) { floatingItems().append( i ); } inline void KoTextParag::unregisterFloatingItem( KoTextCustomItem *i ) { floatingItems().removeRef( i ); } /*inline void KoTextParag::addCustomItem() { numCustomItems++; } inline void KoTextParag::removeCustomItem() { numCustomItems--; }*/ inline int KoTextParag::customItems() const { return mFloatingItems ? mFloatingItems->count() : 0; // was numCustomItems, but no need for a separate count } inline void KoTextParag::setNewLinesAllowed( bool b ) { newLinesAllowed = b; } inline bool KoTextParag::isNewLinesAllowed() const { return newLinesAllowed; } #endif