You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kotext/KoTextParag.h

584 lines
20 KiB

#ifndef KOTEXTPARAG_H
#define KOTEXTPARAG_H
/* This file is part of the KDE project
Copyright (C) 2001-2005 David Faure <faure@kde.org>
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<int, KoTextParagSelection>;
template class TQMap<int, KoTextParagLineStart*>;
// 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<int, KoTextParagLineStart*> &lineStartList();
void setFormat( int index, int len, const KoTextFormat *f, bool useCollection = TRUE, int flags = -1 );
void tqsetAlignment( uint a );
void tqsetAlignmentDirect( 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<KoTextFormat *>( 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::tqsetAlignment ! */
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<char index, tab index> */
TQMap<int, int>& 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 tqparent the xml element that has content as tqchildren.
* @param context the context
* @param stripLeadingSpace whether to remove leading literal whitespace
*/
void loadOasisSpan( const TQDomElement& tqparent, KoOasisContext& context, uint& pos, bool stripLeadingSpace = false );
/**
* Load a section of text from a oasis based xml tree.
* @param tqparent 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& tqparent, 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<int> &selectionStarts,
const TQMemArray<int> &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<int> &selectionStarts,
const TQMemArray<int> &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<int> &selectionStarts,
const TQMemArray<int> &selectionEnds, const TQColorGroup &cg,
bool rightToLeft, int line, KoTextZoomHandler* zh,
int whichFormattingChars );
protected:
KoParagLayout m_layout;
TQMap<int, int> m_tabCache;
private:
KoParagLayout loadParagLayout( KoOasisContext& context, KoStyleCollection *styleCollection, bool findStyle );
/////// End of kotext-specific additions
private:
TQMap<int, KoTextParagSelection> &selections() const;
TQPtrList<KoTextCustomItem> &floatingItems() const;
/// Returns the height of the biggest character in that line
int heightForLineSpacing( int startChar, int lastChar ) const;
TQMap<int, KoTextParagLineStart*> 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<int, KoTextParagSelection> *mSelections;
TQPtrList<KoTextCustomItem> *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<int, KoTextParagLineStart*> &KoTextParag::lineStartList()
{
return lineStarts;
}
inline KoTextString *KoTextParag::string() const
{
return str;
}
inline KoTextDocument *KoTextParag::document() const
{
return doc;
}
inline void KoTextParag::tqsetAlignment( 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