/* This file is part of the KDE project Copyright (C) 2001 Simon Hausmann 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 __kstextview_h__ #define __kstextview_h__ #include #include #include #include #include #include class TQTimer; class TQDragObject; namespace KSirc { class TextView; struct StringPtr { StringPtr() : ptr( 0 ), len( 0 ) {} StringPtr( const TQChar *_ptr, uint _len ) : ptr( _ptr ), len( _len ) {} explicit StringPtr( const TQString &s ) // use with care! : ptr( s.unicode() ), len( s.length() ) {} inline bool isNull() const { return ptr == 0; } // makes deep copy inline TQString toTQString() const { return ( ptr && len > 0 ) ? TQString( ptr, len ) : TQString(); } const TQChar *ptr; uint len; }; #define CONSTSTRING( substr ) TQConstString( substr.ptr, substr.len ).string() inline bool operator<( const StringPtr &s1, const StringPtr &s2 ) { return CONSTSTRING( s1 ) < CONSTSTRING( s2 ); } inline bool operator==( const StringPtr &s1, const StringPtr &s2 ) { return CONSTSTRING( s1 ) == CONSTSTRING( s2 ); } inline bool operator==( const StringPtr &s1, const char *s2 ) { return CONSTSTRING( s1 ) == s2; } class AttributeMap : public TQMap { public: AttributeMap() {} AttributeMap( const AttributeMap &rhs ) : TQMap( rhs ) {} AttributeMap &operator=( const AttributeMap &rhs ) { TQMap::operator=( rhs ); return *this; } // helper for 'const char *' key... ConstIterator findAttribute( const char *key ) const { TQString qkey( key ); return find( StringPtr( qkey ) ); } Iterator findAttribute( const char *key ) { TQString qkey( key ); return find( StringPtr( qkey ) ); } StringPtr operator[]( const char *key ) const { ConstIterator it = findAttribute( key ); if ( it == end() ) return StringPtr(); return it.data(); } StringPtr &operator[]( const StringPtr &key ) { return TQMap::operator[]( key ); } }; struct Token { Token() : id( -1 ) {} enum Id { TagOpen, Text, TagClose }; int id; StringPtr value; AttributeMap attributes; }; struct ItemProperties { ItemProperties(); ItemProperties( const TQFont &defaultFont ); ItemProperties( const ItemProperties &other, const Token &token, TextView *textView ); ItemProperties( const ItemProperties &rhs ); ItemProperties &operator=( const ItemProperties &rhs ); void updateFont( const TQFont &newFont ); // these three are inherited/merged TQFont font; TQColor color; TQColor selColor; TQColor bgColor; TQColor bgSelColor; bool reversed; // ### todo: inherit these, too AttributeMap attributes; }; class TextParag; class TextLine; class SelectionPoint; class Item { public: enum LayoutResetStatus { DeleteItem, KeepItem }; enum SelectionStatus { SelectionStart = 0, InSelection, SelectionEnd, SelectionBoth, NoSelection }; enum SelectionAccuracy { SelectExact, SelectFuzzy }; Item( TextParag *parag, const ItemProperties &props = ItemProperties() ); virtual ~Item(); virtual const char *type() { return "Item"; } virtual void paint( TQPainter &painter ) = 0; int width() const; int minWidth() const; int height() const; virtual Item *breakLine( int width ); virtual LayoutResetStatus resetLayout() = 0; virtual int calcSelectionOffset( int x ); void setSelectionStatus( SelectionStatus status ) { m_selection = status; } SelectionStatus selectionStatus() const { return m_selection; } void selectionOffsets( int &startOffset, int &endOffset ); int maxSelectionOffset() const; void setLine(TextLine *line); // ### virtual StringPtr text() const; virtual void setProps( const ItemProperties &props ); ItemProperties &props() { return m_props; } static Item *create( TextParag *parag, const Token &tok, const ItemProperties &props = ItemProperties() ); protected: mutable bool m_extendsDirty; mutable int m_minWidth; mutable int m_width; mutable int m_height; virtual void calcExtends() const = 0; SelectionStatus m_selection; TextLine *m_line; TextParag *m_parag; ItemProperties m_props; }; class TextChunk : public Item { public: TextChunk( TextParag *parag, const StringPtr &text, const ItemProperties &props ); virtual const char *type() { return "TextChunk"; } virtual void paint( TQPainter &painter ); virtual Item *breakLine( int width ); virtual LayoutResetStatus resetLayout(); virtual int calcSelectionOffset( int x ); virtual StringPtr text() const; virtual void setProps( const ItemProperties &props ); protected: virtual void calcExtends() const; private: StringPtr breakInTheMiddle( int width ); Item *hardBreak( const StringPtr &rightHandSide ); void paintSelection( TQPainter &p ); int paintSelection( TQPainter &p, int x, const StringPtr &text ); int paintText( TQPainter &p, int x, const StringPtr &text ); void mergeSelection( TextChunk *child, SelectionPoint *selection ); StringPtr m_text; uint m_originalTextLength; TQFontMetrics m_metrics; class TextChunk *m_parent; }; class ImageItem : public Item { public: ImageItem( TextParag *parag, const TQPixmap &pixmap ); virtual const char *type() { return "Image"; } virtual void paint( TQPainter &painter ); virtual LayoutResetStatus resetLayout(); protected: virtual void calcExtends() const; private: TQPixmap m_pixmap; }; class Tokenizer { public: struct TagIndex { enum Type { Open, Close }; TagIndex() : index( 0 ), type( -1 ) {} TagIndex( int _index, int _type ) : index( _index ), type( _type ) {} uint index; int type; }; typedef TQValueList TagIndexList; // preprocessed string struct PString { TQString data; TagIndexList tags; }; Tokenizer( PString &text ); static PString preprocess( const TQString &richText ); static TQString convertToRichText( const PString &ptext ); bool parseNextToken( Token &tok ); private: void parseTag( const StringPtr &text, StringPtr &tag, AttributeMap &attributes ); static TagIndexList scanTagIndices( const TQString &text ); static void resolveEntities( TQString &text, TagIndexList &tags ); enum TagParsingState { ScanForName, ScanForEqual, ScanForValue }; TQString &m_text; TagIndexList m_tags; TagIndexList::ConstIterator m_lastTag; bool m_textBeforeFirstTagProcessed; bool m_done; Tokenizer( const Tokenizer & ); Tokenizer &operator=( const Tokenizer & ); }; class SelectionPoint; class TextLine { public: enum LayoutPolicy { NoUpdate, UpdateMaxHeight }; TextLine(); // tranfers ownership of items! make sure that 'items' does not // have autodeletion enabled! TextLine( const TQPtrList &items ); int maxHeight() const { return m_maxHeight; } TQString updateSelection( const SelectionPoint &start, const SelectionPoint &end ); void clearSelection(); // transfers ownership void appendItem( Item *i, int layoutUpdatePolicy = NoUpdate ); bool isEmpty() const { return m_items.isEmpty(); } Item *resetLayout( TQPtrList &remainingItems); void paint( TQPainter &p, int y ); Item *itemAt( int px, SelectionPoint *selectionInfo, Item::SelectionAccuracy accuracy = Item::SelectExact ); TQPtrListIterator iterator() const { return TQPtrListIterator( m_items ); } TQString plainText() const; void fontChange( const TQFont &newFont ); private: TQPtrList m_items; int m_maxHeight; }; class SelectionPoint; class TextParag { public: TextParag( TextView *textView, const TQString &richText ); ~TextParag(); void layout( int width ); void paint( TQPainter &p, int y, int maxY ); inline void setLayouted( bool l ) { m_layouted = l; } inline bool isLayouted() const { return m_layouted; } inline int minWidth() const { return m_minWidth; } inline int height() const { return m_height; } Item *itemAt( int px, int py, SelectionPoint *selectionInfo, Item::SelectionAccuracy accuracy = Item::SelectExact ); TextView *textView() const { return m_textView; } TQString updateSelection( const SelectionPoint &start, const SelectionPoint &end ); void clearSelection(); void setRichText( const TQString &richText ); Tokenizer::PString processedRichText() const { return m_processedRichText; } TQString plainText() const; void fontChange( const TQFont &newFont ); private: Tokenizer::PString m_processedRichText; TQPtrList m_lines; bool m_layouted; int m_height; int m_minWidth; TextView *m_textView; struct Tag { Tag() {} Tag( const StringPtr &_name, const ItemProperties &_props ) : name( _name ), props( _props ) {} StringPtr name; ItemProperties props; }; TextParag( const TextParag & ); TextParag &operator=( const TextParag & ); }; struct SelectionPoint { SelectionPoint() : item( 0 ), line( 0 ), parag( 0 ), offset( 0 ) {} Item *item; TextLine *line; TextParag *parag; uint offset; TQPoint pos; }; class TextParagIterator { friend class TextView; public: TextParagIterator( const TextParagIterator &rhs ) : m_paragIt( rhs.m_paragIt ) {} TextParagIterator &operator=( const TextParagIterator &rhs ) { m_paragIt = rhs.m_paragIt; return *this; } TQString richText() const; void setRichText( const TQString &richText ); TQString plainText() const; bool atEnd() const { return m_paragIt.current() == 0; } TextParagIterator &operator++() { ++m_paragIt; return *this; } TextParagIterator &operator++( int steps ) { m_paragIt += steps; return *this; } TextParagIterator &operator--() { --m_paragIt; return *this; } TextParagIterator &operator--( int steps ) { m_paragIt -= steps; return *this; } protected: TextParagIterator( const TQPtrListIterator ¶gIt ) : m_paragIt( paragIt ) {} private: TQPtrListIterator m_paragIt; }; class ContentsPaintAlgorithm { public: ContentsPaintAlgorithm( const TQPtrListIterator ¶gIt, TQWidget *viewport, TQPixmap &paintBuffer, TQPainter &painter, int clipX, int clipY, int clipHeight ); void paint(); private: int goToFirstVisibleParagraph(); int paint( TQPainter &bufferedPainter, int currentY ); int adjustYAndIterator( int startY, int currentY, int nextY ); TQPtrListIterator m_paragIt; TQWidget *m_viewport; TQPixmap &m_paintBuffer; TQPainter &m_painter; int m_clipX, m_clipY, m_clipHeight; int m_overshoot; }; class TextView : public TQScrollView { Q_OBJECT friend class Item; friend class TextChunk; friend class TextParag; friend class TextParagIterator; public: TextView( TQWidget *parent, const char *name = 0 ); virtual ~TextView(); virtual void clear(); TextParagIterator appendParag( const TQString &richText ); bool removeParag( const TextParagIterator ¶g ); void clearSelection( bool repaint = false ); // ### re-consider the repaint arg... TQString selectedText() const { return m_selectedText; } TextParagIterator firstParag() const; TQString plainText() const; TQColor linkColor() const; void setLinkColor( const TQColor &linkColor ); void scrollToBottom( bool force = false ); signals: void selectionChanged(); void pasteReq(const TQString&); void linkClicked( const TQMouseEvent *ev, const TQString &url ); public slots: void copy(); protected slots: void scrolling(int value); protected: virtual void viewportResizeEvent( TQResizeEvent *ev ); virtual void drawContents( TQPainter *p, int cx, int cy, int cw, int ch ); virtual void contentsMousePressEvent( TQMouseEvent *ev ); virtual void contentsMouseMoveEvent( TQMouseEvent *ev ); virtual void contentsMouseReleaseEvent( TQMouseEvent *ev ); virtual void fontChange( const TQFont & ); virtual void startDrag(); virtual TQDragObject *dragObject( const TQString &dragURL ); private slots: void autoScroll(); private: void emitLinkClickedForMouseEvent( TQMouseEvent *ev ); void startAutoScroll(); void stopAutoScroll(); void selectionOffsets( int &startOffset, int &endOffset ); void updateSelectionOrder(); TQString updateSelection( const SelectionPoint &start, const SelectionPoint &end ); SelectionPoint *selectionStart(); SelectionPoint *selectionEnd(); void layout( bool force = true ); Item *itemAt( const TQPoint &pos, SelectionPoint *selectionInfo = 0, Item::SelectionAccuracy accuracy = Item::SelectExact ); void clearSelectionInternal(); void contentsChange(int heightChange, bool force = false); TQPtrList m_parags; TQPixmap m_paintBuffer; SelectionPoint m_selectionMaybeStart; SelectionPoint m_selectionStart; SelectionPoint m_selectionEnd; bool m_selectionEndBeforeStart; TQTimer *m_autoScrollTimer; TQString m_selectedText; TQPoint m_dragStartPos; TQString m_dragURL; bool m_mousePressed : 1; bool m_mmbPressed : 1; TQColor m_linkColor; TQColor m_selectionBackgroundColor; int m_height; bool m_inScroll; int m_lastScroll; }; } // namespace KSirc #endif /* * vim: et sw=4 */