diff options
Diffstat (limited to 'editeng/source/editeng')
38 files changed, 33667 insertions, 0 deletions
diff --git a/editeng/source/editeng/editattr.cxx b/editeng/source/editeng/editattr.cxx new file mode 100644 index 000000000000..a1d4a66b8fb1 --- /dev/null +++ b/editeng/source/editeng/editattr.cxx @@ -0,0 +1,454 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//#include <eeng_pch.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/svxfont.hxx> +#include <editeng/flditem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> + +#include "editattr.hxx" + +DBG_NAME( EE_EditAttrib ) + +// ------------------------------------------------------------------------- +// class EditAttrib +// ------------------------------------------------------------------------- +EditAttrib::EditAttrib( const SfxPoolItem& rAttr ) +{ + DBG_CTOR( EE_EditAttrib, 0 ); + pItem = &rAttr; +} + +EditAttrib::~EditAttrib() +{ + DBG_DTOR( EE_EditAttrib, 0 ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttrib +// ------------------------------------------------------------------------- +EditCharAttrib::EditCharAttrib( const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) + : EditAttrib( rAttr ) +{ + nStart = nS; + nEnd = nE; + bFeature = FALSE; + bEdge = FALSE; + + DBG_ASSERT( ( rAttr.Which() >= EE_ITEMS_START ) && ( rAttr.Which() <= EE_ITEMS_END ), "EditCharAttrib CTOR: Invalid id!" ); + DBG_ASSERT( ( rAttr.Which() < EE_FEATURE_START ) || ( rAttr.Which() > EE_FEATURE_END ) || ( nE == (nS+1) ), "EditCharAttrib CTOR: Invalid feature!" ); +} + +void EditCharAttrib::SetFont( SvxFont&, OutputDevice* ) +{ +} + + +// ------------------------------------------------------------------------- +// class EditCharAttribFont +// ------------------------------------------------------------------------- +EditCharAttribFont::EditCharAttribFont( const SvxFontItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTINFO || rAttr.Which() == EE_CHAR_FONTINFO_CJK || rAttr.Which() == EE_CHAR_FONTINFO_CTL, "Kein Fontattribut!" ); +} + +void EditCharAttribFont::SetFont( SvxFont& rFont, OutputDevice* ) +{ + const SvxFontItem& rAttr = (const SvxFontItem&)(*GetItem()); + + rFont.SetName( rAttr.GetFamilyName() ); + rFont.SetFamily( rAttr.GetFamily() ); + rFont.SetPitch( rAttr.GetPitch() ); + rFont.SetCharSet( rAttr.GetCharSet() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribItalic +// ------------------------------------------------------------------------- +EditCharAttribItalic::EditCharAttribItalic( const SvxPostureItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_ITALIC || rAttr.Which() == EE_CHAR_ITALIC_CJK || rAttr.Which() == EE_CHAR_ITALIC_CTL, "Kein Italicattribut!" ); +} + +void EditCharAttribItalic::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetItalic( ((const SvxPostureItem*)GetItem())->GetPosture() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribWeight +// ------------------------------------------------------------------------- +EditCharAttribWeight::EditCharAttribWeight( const SvxWeightItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_WEIGHT || rAttr.Which() == EE_CHAR_WEIGHT_CJK || rAttr.Which() == EE_CHAR_WEIGHT_CTL, "Kein Weightttribut!" ); +} + +void EditCharAttribWeight::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetWeight( (FontWeight)((const SvxWeightItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribUnderline +// ------------------------------------------------------------------------- +EditCharAttribUnderline::EditCharAttribUnderline( const SvxUnderlineItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_UNDERLINE, "Kein Underlineattribut!" ); +} + +void EditCharAttribUnderline::SetFont( SvxFont& rFont, OutputDevice* pOutDev ) +{ + rFont.SetUnderline( (FontUnderline)((const SvxUnderlineItem*)GetItem())->GetValue() ); + if ( pOutDev ) + pOutDev->SetTextLineColor( ((const SvxUnderlineItem*)GetItem())->GetColor() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribOverline +// ------------------------------------------------------------------------- +EditCharAttribOverline::EditCharAttribOverline( const SvxOverlineItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_OVERLINE, "Kein Overlineattribut!" ); +} + +void EditCharAttribOverline::SetFont( SvxFont& rFont, OutputDevice* pOutDev ) +{ + rFont.SetOverline( (FontUnderline)((const SvxOverlineItem*)GetItem())->GetValue() ); + if ( pOutDev ) + pOutDev->SetOverlineColor( ((const SvxOverlineItem*)GetItem())->GetColor() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFontHeight +// ------------------------------------------------------------------------- +EditCharAttribFontHeight::EditCharAttribFontHeight( const SvxFontHeightItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTHEIGHT || rAttr.Which() == EE_CHAR_FONTHEIGHT_CJK || rAttr.Which() == EE_CHAR_FONTHEIGHT_CTL, "Kein Heightattribut!" ); +} + +void EditCharAttribFontHeight::SetFont( SvxFont& rFont, OutputDevice* ) +{ + // Prop wird ignoriert + rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem*)GetItem())->GetHeight() ) ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFontWidth +// ------------------------------------------------------------------------- +EditCharAttribFontWidth::EditCharAttribFontWidth( const SvxCharScaleWidthItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTWIDTH, "Kein Widthattribut!" ); +} + +void EditCharAttribFontWidth::SetFont( SvxFont& /*rFont*/, OutputDevice* ) +{ + // must be calculated outside, because f(device)... +} + +// ------------------------------------------------------------------------- +// class EditCharAttribStrikeout +// ------------------------------------------------------------------------- +EditCharAttribStrikeout::EditCharAttribStrikeout( const SvxCrossedOutItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_STRIKEOUT, "Kein Sizeattribut!" ); +} + +void EditCharAttribStrikeout::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetStrikeout( (FontStrikeout)((const SvxCrossedOutItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribColor +// ------------------------------------------------------------------------- +EditCharAttribColor::EditCharAttribColor( const SvxColorItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_COLOR, "Kein Colorattribut!" ); +} + +void EditCharAttribColor::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetColor( ((const SvxColorItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribLanguage +// ------------------------------------------------------------------------- +EditCharAttribLanguage::EditCharAttribLanguage( const SvxLanguageItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( ( rAttr.Which() == EE_CHAR_LANGUAGE ) || ( rAttr.Which() == EE_CHAR_LANGUAGE_CJK ) || ( rAttr.Which() == EE_CHAR_LANGUAGE_CTL ), "Kein Languageattribut!" ); +} + +void EditCharAttribLanguage::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetLanguage( ((const SvxLanguageItem*)GetItem())->GetLanguage() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribShadow +// ------------------------------------------------------------------------- +EditCharAttribShadow::EditCharAttribShadow( const SvxShadowedItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_SHADOW, "Kein Shadowattribut!" ); +} + +void EditCharAttribShadow::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetShadow( (BOOL)((const SvxShadowedItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribEscapement +// ------------------------------------------------------------------------- +EditCharAttribEscapement::EditCharAttribEscapement( const SvxEscapementItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_ESCAPEMENT, "Kein Escapementattribut!" ); +} + +#if defined( WIN ) && !defined( WNT ) +#pragma optimize ("", off) +#endif + +void EditCharAttribEscapement::SetFont( SvxFont& rFont, OutputDevice* ) +{ + USHORT nProp = ((const SvxEscapementItem*)GetItem())->GetProp(); + rFont.SetPropr( (BYTE)nProp ); + + short nEsc = ((const SvxEscapementItem*)GetItem())->GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + nEsc = 100 - nProp; + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + rFont.SetEscapement( nEsc ); +} + +#if defined( WIN ) && !defined( WNT ) +#pragma optimize ("", on) +#endif + + +// ------------------------------------------------------------------------- +// class EditCharAttribOutline +// ------------------------------------------------------------------------- +EditCharAttribOutline::EditCharAttribOutline( const SvxContourItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_OUTLINE, "Kein Outlineattribut!" ); +} + +void EditCharAttribOutline::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetOutline( (BOOL)((const SvxContourItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribTab +// ------------------------------------------------------------------------- +EditCharAttribTab::EditCharAttribTab( const SfxVoidItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); +} + +void EditCharAttribTab::SetFont( SvxFont&, OutputDevice* ) +{ +} + +// ------------------------------------------------------------------------- +// class EditCharAttribLineBreak +// ------------------------------------------------------------------------- +EditCharAttribLineBreak::EditCharAttribLineBreak( const SfxVoidItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); +} + +void EditCharAttribLineBreak::SetFont( SvxFont&, OutputDevice* ) +{ +} + +// ------------------------------------------------------------------------- +// class EditCharAttribField +// ------------------------------------------------------------------------- +EditCharAttribField::EditCharAttribField( const SvxFieldItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); // !!! + pTxtColor = 0; + pFldColor = 0; +} + +void EditCharAttribField::SetFont( SvxFont& rFont, OutputDevice* ) +{ + if ( pFldColor ) + { + rFont.SetFillColor( *pFldColor ); + rFont.SetTransparent( FALSE ); + } + if ( pTxtColor ) + rFont.SetColor( *pTxtColor ); +} + +EditCharAttribField::EditCharAttribField( const EditCharAttribField& rAttr ) + : EditCharAttrib( *rAttr.GetItem(), rAttr.GetStart(), rAttr.GetEnd() ), + aFieldValue( rAttr.aFieldValue ) +{ + // Diesen CCTOR nur fuer temporaeres Object verwenden, + // Item wird nicht gepoolt. + pTxtColor = rAttr.pTxtColor ? new Color( *rAttr.pTxtColor ) : 0; + pFldColor = rAttr.pFldColor ? new Color( *rAttr.pFldColor ) : 0; +} + +EditCharAttribField::~EditCharAttribField() +{ + Reset(); +} + +BOOL EditCharAttribField::operator == ( const EditCharAttribField& rAttr ) const +{ + if ( aFieldValue != rAttr.aFieldValue ) + return FALSE; + + if ( ( pTxtColor && !rAttr.pTxtColor ) || ( !pTxtColor && rAttr.pTxtColor ) ) + return FALSE; + if ( ( pTxtColor && rAttr.pTxtColor ) && ( *pTxtColor != *rAttr.pTxtColor ) ) + return FALSE; + + if ( ( pFldColor && !rAttr.pFldColor ) || ( !pFldColor && rAttr.pFldColor ) ) + return FALSE; + if ( ( pFldColor && rAttr.pFldColor ) && ( *pFldColor != *rAttr.pFldColor ) ) + return FALSE; + + return TRUE; +} + +// ------------------------------------------------------------------------- +// class EditCharAttribPairKerning +// ------------------------------------------------------------------------- +EditCharAttribPairKerning::EditCharAttribPairKerning( const SvxAutoKernItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_PAIRKERNING, "Kein PairKerning!" ); +} + +void EditCharAttribPairKerning::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetKerning( ((const SvxAutoKernItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribKerning +// ------------------------------------------------------------------------- +EditCharAttribKerning::EditCharAttribKerning( const SvxKerningItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_KERNING, "Kein Kerning!" ); +} + +void EditCharAttribKerning::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetFixKerning( ((const SvxKerningItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribWordLineMode +// ------------------------------------------------------------------------- +EditCharAttribWordLineMode::EditCharAttribWordLineMode( const SvxWordLineModeItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_WLM, "Kein Kerning!" ); +} + +void EditCharAttribWordLineMode::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetWordLineMode( ((const SvxWordLineModeItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribEmphasisMark +// ------------------------------------------------------------------------- +EditCharAttribEmphasisMark::EditCharAttribEmphasisMark( const SvxEmphasisMarkItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_EMPHASISMARK, "Kein Emphasisattribut!" ); +} + +void EditCharAttribEmphasisMark::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem*)GetItem())->GetEmphasisMark() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribRelief +// ------------------------------------------------------------------------- +EditCharAttribRelief::EditCharAttribRelief( const SvxCharReliefItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_RELIEF, "Not a relief attribute!" ); +} + +void EditCharAttribRelief::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetRelief( (FontRelief)((const SvxCharReliefItem*)GetItem())->GetValue() ); +} diff --git a/editeng/source/editeng/editattr.hxx b/editeng/source/editeng/editattr.hxx new file mode 100644 index 000000000000..9f07969ee74d --- /dev/null +++ b/editeng/source/editeng/editattr.hxx @@ -0,0 +1,426 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITATTR_HXX +#define _EDITATTR_HXX + +#include <editeng/eeitem.hxx> + +class SvxFont; +class SvxFontItem; +class SvxWeightItem; +class SvxPostureItem; +class SvxShadowedItem; +class SvxEscapementItem; +class SvxContourItem; +class SvxCrossedOutItem; +class SvxUnderlineItem; +class SvxOverlineItem; +class SvxFontHeightItem; +class SvxCharScaleWidthItem; +class SvxColorItem; +class SvxAutoKernItem; +class SvxKerningItem; +class SvxCharSetColorItem; +class SvxWordLineModeItem; +class SvxFieldItem; +class SvxLanguageItem; +class SvxEmphasisMarkItem; +class SvxCharReliefItem; +#include <svl/poolitem.hxx> + + +class SfxVoidItem; + +#define CH_FEATURE_OLD (BYTE) 0xFF +#define CH_FEATURE (sal_Unicode) 0x01 + +// DEF_METRIC: Bei meinem Pool sollte immer die DefMetric bei +// GetMetric( nWhich ) ankommen! +// => Zum ermitteln der DefMetrik einfach ein GetMetric( 0 ) +#define DEF_METRIC 0 + +// ------------------------------------------------------------------------- +// class EditAttrib +// ------------------------------------------------------------------------- +class EditAttrib +{ +private: + EditAttrib() {;} + EditAttrib( const EditAttrib & ) {;} + +protected: + const SfxPoolItem* pItem; + + EditAttrib( const SfxPoolItem& rAttr ); + virtual ~EditAttrib(); + +public: + // RemoveFromPool muss immer vorm DTOR Aufruf erfolgen!! + void RemoveFromPool( SfxItemPool& rPool ); + + USHORT Which() const { return pItem->Which(); } + const SfxPoolItem* GetItem() const { return pItem; } +}; + +// ------------------------------------------------------------------------- +// class EditCharAttrib +// ------------------------------------------------------------------------- +// bFeature: Attribut darf nicht expandieren/schrumfen, Laenge immer 1 +// bEdge: Attribut expandiert nicht, wenn genau an der Kante expandiert werden soll +class EditCharAttrib : public EditAttrib +{ +protected: + + USHORT nStart; + USHORT nEnd; + BOOL bFeature :1; + BOOL bEdge :1; + +public: + EditCharAttrib( const SfxPoolItem& rAttr, USHORT nStart, USHORT nEnd ); + + USHORT& GetStart() { return nStart; } + USHORT& GetEnd() { return nEnd; } + + USHORT GetStart() const { return nStart; } + USHORT GetEnd() const { return nEnd; } + + inline USHORT GetLen() const; + + inline void MoveForward( USHORT nDiff ); + inline void MoveBackward( USHORT nDiff ); + + inline void Expand( USHORT nDiff ); + inline void Collaps( USHORT nDiff ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); + + BOOL IsIn( USHORT nIndex ) + { return ( ( nStart <= nIndex ) && ( nEnd >= nIndex ) ); } + BOOL IsInside( USHORT nIndex ) + { return ( ( nStart < nIndex ) && ( nEnd > nIndex ) ); } + BOOL IsEmpty() + { return nStart == nEnd; } + + BOOL IsFeature() const { return bFeature; } + void SetFeature( BOOL b) { bFeature = b; } + + BOOL IsEdge() const { return bEdge; } + void SetEdge( BOOL b ) { bEdge = b; } +}; + +inline USHORT EditCharAttrib::GetLen() const +{ + DBG_ASSERT( nEnd >= nStart, "EditCharAttrib: nEnd < nStart!" ); + return nEnd-nStart; +} + +inline void EditCharAttrib::MoveForward( USHORT nDiff ) +{ + DBG_ASSERT( ((long)nEnd + nDiff) <= 0xFFFF, "EditCharAttrib: MoveForward?!" ); + nStart = nStart + nDiff; + nEnd = nEnd + nDiff; +} + +inline void EditCharAttrib::MoveBackward( USHORT nDiff ) +{ + DBG_ASSERT( ((long)nStart - nDiff) >= 0, "EditCharAttrib: MoveBackward?!" ); + nStart = nStart - nDiff; + nEnd = nEnd - nDiff; +} + +inline void EditCharAttrib::Expand( USHORT nDiff ) +{ + DBG_ASSERT( ( ((long)nEnd + nDiff) <= (long)0xFFFF ), "EditCharAttrib: Expand?!" ); + DBG_ASSERT( !bFeature, "Bitte keine Features expandieren!" ); + nEnd = nEnd + nDiff; +} + +inline void EditCharAttrib::Collaps( USHORT nDiff ) +{ + DBG_ASSERT( (long)nEnd - nDiff >= (long)nStart, "EditCharAttrib: Collaps?!" ); + DBG_ASSERT( !bFeature, "Bitte keine Features schrumpfen!" ); + nEnd = nEnd - nDiff; +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFont +// ------------------------------------------------------------------------- +class EditCharAttribFont: public EditCharAttrib +{ +public: + EditCharAttribFont( const SvxFontItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribWeight +// ------------------------------------------------------------------------- +class EditCharAttribWeight : public EditCharAttrib +{ +public: + EditCharAttribWeight( const SvxWeightItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; +// ------------------------------------------------------------------------- +// class EditCharAttribItalic +// ------------------------------------------------------------------------- +class EditCharAttribItalic : public EditCharAttrib +{ +public: + EditCharAttribItalic( const SvxPostureItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribShadow +// ------------------------------------------------------------------------- +class EditCharAttribShadow : public EditCharAttrib +{ +public: + EditCharAttribShadow( const SvxShadowedItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribEscapement +// ------------------------------------------------------------------------- +class EditCharAttribEscapement : public EditCharAttrib +{ +public: + EditCharAttribEscapement( const SvxEscapementItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribOutline +// ------------------------------------------------------------------------- +class EditCharAttribOutline : public EditCharAttrib +{ +public: + EditCharAttribOutline( const SvxContourItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribStrikeout +// ------------------------------------------------------------------------- +class EditCharAttribStrikeout : public EditCharAttrib +{ +public: + EditCharAttribStrikeout( const SvxCrossedOutItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribUnderline +// ------------------------------------------------------------------------- +class EditCharAttribUnderline : public EditCharAttrib +{ +public: + EditCharAttribUnderline( const SvxUnderlineItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribOverline +// ------------------------------------------------------------------------- +class EditCharAttribOverline : public EditCharAttrib +{ +public: + EditCharAttribOverline( const SvxOverlineItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribEmphasisMark +// ------------------------------------------------------------------------- +class EditCharAttribEmphasisMark : public EditCharAttrib +{ +public: + EditCharAttribEmphasisMark( const SvxEmphasisMarkItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribRelief +// ------------------------------------------------------------------------- +class EditCharAttribRelief : public EditCharAttrib +{ +public: + EditCharAttribRelief( const SvxCharReliefItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribFontHeight +// ------------------------------------------------------------------------- +class EditCharAttribFontHeight : public EditCharAttrib +{ +public: + EditCharAttribFontHeight( const SvxFontHeightItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribFontWidth +// ------------------------------------------------------------------------- +class EditCharAttribFontWidth : public EditCharAttrib +{ +public: + EditCharAttribFontWidth( const SvxCharScaleWidthItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribColor +// ------------------------------------------------------------------------- +class EditCharAttribColor : public EditCharAttrib +{ +public: + EditCharAttribColor( const SvxColorItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribLanguage +// ------------------------------------------------------------------------- +class EditCharAttribLanguage : public EditCharAttrib +{ +public: + EditCharAttribLanguage( const SvxLanguageItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribTab +// ------------------------------------------------------------------------- +class EditCharAttribTab : public EditCharAttrib +{ +public: + EditCharAttribTab( const SfxVoidItem& rAttr, USHORT nPos ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribLineBreak +// ------------------------------------------------------------------------- +class EditCharAttribLineBreak : public EditCharAttrib +{ +public: + EditCharAttribLineBreak( const SfxVoidItem& rAttr, USHORT nPos ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribField +// ------------------------------------------------------------------------- +class EditCharAttribField: public EditCharAttrib +{ + XubString aFieldValue; + Color* pTxtColor; + Color* pFldColor; + + EditCharAttribField& operator = ( const EditCharAttribField& rAttr ) const; + +public: + EditCharAttribField( const SvxFieldItem& rAttr, USHORT nPos ); + EditCharAttribField( const EditCharAttribField& rAttr ); + ~EditCharAttribField(); + + BOOL operator == ( const EditCharAttribField& rAttr ) const; + BOOL operator != ( const EditCharAttribField& rAttr ) const + { return !(operator == ( rAttr ) ); } + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); + Color*& GetTxtColor() { return pTxtColor; } + Color*& GetFldColor() { return pFldColor; } + + const XubString& GetFieldValue() const { return aFieldValue; } + XubString& GetFieldValue() { return aFieldValue; } + + void Reset() + { + aFieldValue.Erase(); + delete pTxtColor; pTxtColor = 0; + delete pFldColor; pFldColor = 0; + } +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribPairKerning +// ------------------------------------------------------------------------- +class EditCharAttribPairKerning : public EditCharAttrib +{ +public: + EditCharAttribPairKerning( const SvxAutoKernItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribKerning +// ------------------------------------------------------------------------- +class EditCharAttribKerning : public EditCharAttrib +{ +public: + EditCharAttribKerning( const SvxKerningItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribWordLineMode +// ------------------------------------------------------------------------- +class EditCharAttribWordLineMode: public EditCharAttrib +{ +public: + EditCharAttribWordLineMode( const SvxWordLineModeItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + + +#endif // _EDITATTR_HXX diff --git a/editeng/source/editeng/editdbg.cxx b/editeng/source/editeng/editdbg.cxx new file mode 100644 index 000000000000..01a387249f24 --- /dev/null +++ b/editeng/source/editeng/editdbg.cxx @@ -0,0 +1,586 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/lspcitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editdoc.hxx> +#include <editdbg.hxx> + +#if defined( DBG_UTIL ) || ( OSL_DEBUG_LEVEL > 1 ) + +ByteString DbgOutItem( const SfxItemPool& rPool, const SfxPoolItem& rItem ) +{ + ByteString aDebStr; + switch ( rItem.Which() ) + { + case EE_PARA_WRITINGDIR: + aDebStr += "WritingDir="; + aDebStr += ByteString::CreateFromInt32( ((SvxFrameDirectionItem&)rItem).GetValue() ); + break; + case EE_PARA_OUTLLRSPACE: + case EE_PARA_LRSPACE: + aDebStr += "FI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst() ); + aDebStr += ", LI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetTxtLeft() ); + aDebStr += ", RI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetRight() ); + break; + case EE_PARA_NUMBULLET: + { + aDebStr += "NumItem "; + for ( USHORT nLevel = 0; nLevel < 3; nLevel++ ) + { + aDebStr += "Level"; + aDebStr += ByteString::CreateFromInt32( nLevel ); + aDebStr += "="; + const SvxNumberFormat* pFmt = ((const SvxNumBulletItem&)rItem).GetNumRule()->Get( nLevel ); + if ( pFmt ) + { + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pFmt->GetFirstLineOffset() ); + aDebStr += ","; + aDebStr += ByteString::CreateFromInt32( pFmt->GetAbsLSpace() ); + aDebStr += ","; + if ( pFmt->GetNumberingType() == SVX_NUM_BITMAP ) + { + aDebStr += "Bitmap"; + } + else if( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) + { + aDebStr += "Number"; + } + else + { + aDebStr += "Char=["; + aDebStr += ByteString::CreateFromInt32( pFmt->GetBulletChar() ); + aDebStr += "]"; + } + aDebStr += ") "; + } + } + } + break; + case EE_PARA_BULLETSTATE: + aDebStr += "ShowBullet="; + aDebStr += ByteString::CreateFromInt32( ((SfxBoolItem&)rItem).GetValue() ); + break; + case EE_PARA_HYPHENATE: + aDebStr += "Hyphenate="; + aDebStr += ByteString::CreateFromInt32( ((SfxBoolItem&)rItem).GetValue() ); + break; + case EE_PARA_OUTLLEVEL: + aDebStr += "Level="; + aDebStr += ByteString::CreateFromInt32( ((SfxInt16Item&)rItem).GetValue() ); + break; + case EE_PARA_ULSPACE: + aDebStr += "SB="; + aDebStr += ByteString::CreateFromInt32( ((SvxULSpaceItem&)rItem).GetUpper() ); + aDebStr += ", SA="; + aDebStr += ByteString::CreateFromInt32( ((SvxULSpaceItem&)rItem).GetLower() ); + break; + case EE_PARA_SBL: + aDebStr += "SBL="; + if ( ((SvxLineSpacingItem&)rItem).GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + aDebStr += "Min: "; + aDebStr += ByteString::CreateFromInt32( ((SvxLineSpacingItem&)rItem).GetInterLineSpace() ); + } + else if ( ((SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + aDebStr += "Prop: "; + aDebStr += ByteString::CreateFromInt32( (ULONG)((SvxLineSpacingItem&)rItem).GetPropLineSpace() ); + } + else + aDebStr += "Unsupported Type!"; + break; + case EE_PARA_JUST: + aDebStr += "SvxAdust="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxAdjustItem&)rItem).GetAdjust() ); + break; + case EE_PARA_TABS: + { + aDebStr += "Tabs: "; + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; + aDebStr += ByteString::CreateFromInt32( rTabs.Count() ); + if ( rTabs.Count() ) + { + aDebStr += "( "; + for ( USHORT i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + aDebStr += ByteString::CreateFromInt32( rTab.GetTabPos() ); + aDebStr += " "; + } + aDebStr += ")"; + } + } + break; + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + aDebStr += "Language="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxLanguageItem&)rItem).GetLanguage() ); + break; + case EE_CHAR_COLOR: + { + aDebStr += "Color= "; + Color aColor( ((SvxColorItem&)rItem).GetValue() ); + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetRed() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetGreen() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetBlue() ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + aDebStr += "Font="; + aDebStr += ByteString( ((SvxFontItem&)rItem).GetFamilyName(), RTL_TEXTENCODING_ASCII_US ); + aDebStr += " (CharSet: "; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxFontItem&)rItem).GetCharSet() ); + aDebStr += ')'; + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + aDebStr += "Groesse="; + aDebStr += ByteString::CreateFromInt32( ((SvxFontHeightItem&)rItem).GetHeight() ); + Size aSz( 0, ((SvxFontHeightItem&)rItem).GetHeight() ); + SfxMapUnit eUnit = rPool.GetMetric( rItem.Which() ); + MapMode aItemMapMode( (MapUnit) eUnit ); + MapMode aPntMap( MAP_POINT ); + aSz = OutputDevice::LogicToLogic( aSz, aItemMapMode, aPntMap ); + aDebStr += " Points="; + aDebStr += ByteString::CreateFromInt32( aSz.Height() ); + } + break; + case EE_CHAR_FONTWIDTH: + { + aDebStr += "Breite="; + aDebStr += ByteString::CreateFromInt32( ((SvxCharScaleWidthItem&)rItem).GetValue() ); + aDebStr += "%"; + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + aDebStr += "FontWeight="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxWeightItem&)rItem).GetWeight() ); + break; + case EE_CHAR_UNDERLINE: + aDebStr += "FontUnderline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxUnderlineItem&)rItem).GetLineStyle() ); + break; + case EE_CHAR_OVERLINE: + aDebStr += "FontOverline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxOverlineItem&)rItem).GetLineStyle() ); + break; + case EE_CHAR_EMPHASISMARK: + aDebStr += "FontUnderline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxEmphasisMarkItem&)rItem).GetEmphasisMark() ); + break; + case EE_CHAR_RELIEF: + aDebStr += "FontRelief="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxCharReliefItem&)rItem).GetValue() ); + break; + case EE_CHAR_STRIKEOUT: + aDebStr += "FontStrikeout="; + aDebStr +=ByteString::CreateFromInt32( (USHORT)((SvxCrossedOutItem&)rItem).GetStrikeout() ); + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + aDebStr += "FontPosture="; + aDebStr +=ByteString::CreateFromInt32( (USHORT)((SvxPostureItem&)rItem).GetPosture() ); + break; + case EE_CHAR_OUTLINE: + aDebStr += "FontOutline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxContourItem&)rItem).GetValue() ); + break; + case EE_CHAR_SHADOW: + aDebStr += "FontShadowed="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxShadowedItem&)rItem).GetValue() ); + break; + case EE_CHAR_ESCAPEMENT: + aDebStr += "Escape="; + aDebStr += ByteString::CreateFromInt32( (short)((SvxEscapementItem&)rItem).GetEsc() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (short)((SvxEscapementItem&)rItem).GetProp() ); + break; + case EE_CHAR_PAIRKERNING: + aDebStr += "PairKerning="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxAutoKernItem&)rItem).GetValue() ); + break; + case EE_CHAR_KERNING: + { + aDebStr += "Kerning="; + aDebStr += ByteString::CreateFromInt32( (short)((SvxKerningItem&)rItem).GetValue() ); + Size aSz( 0, (short)((SvxKerningItem&)rItem).GetValue() ); + SfxMapUnit eUnit = rPool.GetMetric( rItem.Which() ); + MapMode aItemMapMode( (MapUnit) eUnit ); + MapMode aPntMap( MAP_POINT ); + aSz = OutputDevice::LogicToLogic( aSz, aItemMapMode, aPntMap ); + aDebStr += " Points="; + aDebStr += ByteString::CreateFromInt32( aSz.Height() ); + } + break; + case EE_CHAR_WLM: + aDebStr += "WordLineMode="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxWordLineModeItem&)rItem).GetValue() ); + break; + case EE_CHAR_XMLATTRIBS: + aDebStr += "XMLAttribs=..."; + break; + } + return aDebStr; +} + +void DbgOutItemSet( FILE* fp, const SfxItemSet& rSet, BOOL bSearchInParent, BOOL bShowALL ) +{ + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + fprintf( fp, "\nWhich: %i\t", nWhich ); + if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_OFF ) + fprintf( fp, "ITEM_OFF " ); + else if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_DONTCARE ) + fprintf( fp, "ITEM_DC " ); + else if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_ON ) + fprintf( fp, "ITEM_ON *" ); + + if ( !bShowALL && ( rSet.GetItemState( nWhich, bSearchInParent ) != SFX_ITEM_ON ) ) + continue; + + const SfxPoolItem& rItem = rSet.Get( nWhich, bSearchInParent ); + ByteString aDebStr = DbgOutItem( *rSet.GetPool(), rItem ); + fprintf( fp, "%s", aDebStr.GetBuffer() ); + } +} + +void EditDbg::ShowEditEngineData( EditEngine* pEE, BOOL bInfoBox ) +{ +#if defined UNX + FILE* fp = fopen( "/tmp/debug.log", "w" ); +#else + FILE* fp = fopen( "d:\\debug.log", "w" ); +#endif + if ( fp == 0 ) + { + DBG_ERROR( "Log-File konnte nicht angelegt werden!" ); + return; + } + + const SfxItemPool& rPool = *pEE->GetEmptyItemSet().GetPool(); + + fprintf( fp, "================================================================================" ); + fprintf( fp, "\n================== Dokument ================================================" ); + fprintf( fp, "\n================================================================================" ); + for ( USHORT nPortion = 0; nPortion < pEE->pImpEditEngine->GetParaPortions(). Count(); nPortion++) + { + + ParaPortion* pPPortion = pEE->pImpEditEngine->GetParaPortions().GetObject(nPortion ); + fprintf( fp, "\nAbsatz %i: Laenge = %i, Invalid = %i\nText = '%s'", nPortion, pPPortion->GetNode()->Len(), pPPortion->IsInvalid(), ByteString( *pPPortion->GetNode(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nVorlage:" ); + SfxStyleSheet* pStyle = pPPortion->GetNode()->GetStyleSheet(); + if ( pStyle ) + fprintf( fp, " %s", ByteString( pStyle->GetName(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nAbsatzattribute:" ); + DbgOutItemSet( fp, pPPortion->GetNode()->GetContentAttribs().GetItems(), FALSE, FALSE ); + + fprintf( fp, "\nZeichenattribute:" ); + BOOL bZeroAttr = FALSE; + USHORT z; + for ( z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); z++ ) + { + EditCharAttrib* pAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( z ); + ByteString aCharAttribs; + aCharAttribs += "\nA"; + aCharAttribs += ByteString::CreateFromInt32( nPortion ); + aCharAttribs += ": "; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetItem()->Which() ); + aCharAttribs += '\t'; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetStart() ); + aCharAttribs += '\t'; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetEnd() ); + if ( pAttr->IsEmpty() ) + bZeroAttr = TRUE; + fprintf( fp, "%s => ", aCharAttribs.GetBuffer() ); + + ByteString aDebStr = DbgOutItem( rPool, *pAttr->GetItem() ); + fprintf( fp, "%s", aDebStr.GetBuffer() ); + } + if ( bZeroAttr ) + fprintf( fp, "\nNULL-Attribute!" ); + + USHORT nTextPortions = pPPortion->GetTextPortions().Count(); + ByteString aPortionStr("\nTextportions: #"); + aPortionStr += ByteString::CreateFromInt32( nTextPortions ); + aPortionStr += " \nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": Absatzlaenge = "; + aPortionStr += ByteString::CreateFromInt32( pPPortion->GetNode()->Len() ); + aPortionStr += "\nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": "; + ULONG n = 0; + for ( z = 0; z < nTextPortions; z++ ) + { + TextPortion* pPortion = pPPortion->GetTextPortions().GetObject( z ); + aPortionStr += " "; + aPortionStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aPortionStr += "("; + aPortionStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aPortionStr += ")"; + aPortionStr += "["; + aPortionStr += ByteString::CreateFromInt32( (USHORT)pPortion->GetKind() ); + aPortionStr += "]"; + aPortionStr += ";"; + n += pPortion->GetLen(); + } + aPortionStr += "\nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": Gesamtlaenge: "; + aPortionStr += ByteString::CreateFromInt32( n ); + if ( pPPortion->GetNode()->Len() != n ) + aPortionStr += " => Fehler !!!"; + fprintf( fp, "%s", aPortionStr.GetBuffer() ); + + + fprintf( fp, "\n\nZeilen:" ); + // Erstmal die Inhalte... + USHORT nLine; + for ( nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + + ByteString aLine( *(pPPortion->GetNode()), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart(), RTL_TEXTENCODING_ASCII_US ); + fprintf( fp, "\nZeile %i\t>%s<", nLine, aLine.GetBuffer() ); + } + // dann die internen Daten... + for ( nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + fprintf( fp, "\nZeile %i:\tStart: %i,\tEnd: %i", nLine, pLine->GetStart(), pLine->GetEnd() ); + fprintf( fp, "\t\tPortions: %i - %i.\tHoehe: %i, Ascent=%i", pLine->GetStartPortion(), pLine->GetEndPortion(), pLine->GetHeight(), pLine->GetMaxAscent() ); + } + + fprintf( fp, "\n-----------------------------------------------------------------------------" ); + } + + if ( pEE->pImpEditEngine->GetStyleSheetPool() ) + { + ULONG nStyles = pEE->pImpEditEngine->GetStyleSheetPool() ? pEE->pImpEditEngine->GetStyleSheetPool()->Count() : 0; + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Stylesheets =============================================" ); + fprintf( fp, "\n================================================================================" ); + fprintf( fp, "\n#Vorlagen: %lu\n", nStyles ); + SfxStyleSheetIterator aIter( pEE->pImpEditEngine->GetStyleSheetPool(), SFX_STYLE_FAMILY_ALL ); + SfxStyleSheetBase* pStyle = aIter.First(); + while ( pStyle ) + { + fprintf( fp, "\nVorlage: %s", ByteString( pStyle->GetName(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nParent: %s", ByteString( pStyle->GetParent(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nFollow: %s", ByteString( pStyle->GetFollow(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + DbgOutItemSet( fp, pStyle->GetItemSet(), FALSE, FALSE ); + fprintf( fp, "\n----------------------------------" ); + + pStyle = aIter.Next(); + } + } + + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Defaults ================================================" ); + fprintf( fp, "\n================================================================================" ); + DbgOutItemSet( fp, pEE->pImpEditEngine->GetEmptyItemSet(), TRUE, TRUE ); + + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== EditEngine & Views ======================================" ); + fprintf( fp, "\n================================================================================" ); + fprintf( fp, "\nControl: %lx", pEE->GetControlWord() ); + fprintf( fp, "\nRefMapMode: %i", pEE->pImpEditEngine->pRefDev->GetMapMode().GetMapUnit() ); + fprintf( fp, "\nPaperSize: %li x %li", pEE->GetPaperSize().Width(), pEE->GetPaperSize().Height() ); + fprintf( fp, "\nMaxAutoPaperSize: %li x %li", pEE->GetMaxAutoPaperSize().Width(), pEE->GetMaxAutoPaperSize().Height() ); + fprintf( fp, "\nMinAutoPaperSize: %li x %li", pEE->GetMinAutoPaperSize().Width(), pEE->GetMinAutoPaperSize().Height() ); + fprintf( fp, "\nUpdate: %i", pEE->GetUpdateMode() ); + fprintf( fp, "\nAnzahl der Views: %i", pEE->GetViewCount() ); + for ( USHORT nView = 0; nView < pEE->GetViewCount(); nView++ ) + { + EditView* pV = pEE->GetView( nView ); + DBG_ASSERT( pV, "View nicht gefunden!" ); + fprintf( fp, "\nView %i: Focus=%i", nView, pV->GetWindow()->HasFocus() ); + Rectangle aR( pV->GetOutputArea() ); + fprintf( fp, "\n OutputArea: nX=%li, nY=%li, dX=%li, dY=%li, MapMode = %i", aR.TopLeft().X(), aR.TopLeft().Y(), aR.GetSize().Width(), aR.GetSize().Height() , pV->GetWindow()->GetMapMode().GetMapUnit() ); + aR = pV->GetVisArea(); + fprintf( fp, "\n VisArea: nX=%li, nY=%li, dX=%li, dY=%li", aR.TopLeft().X(), aR.TopLeft().Y(), aR.GetSize().Width(), aR.GetSize().Height() ); + ESelection aSel = pV->GetSelection(); + fprintf( fp, "\n Selektion: Start=%u,%u, End=%u,%u", aSel.nStartPara, aSel.nStartPos, aSel.nEndPara, aSel.nEndPos ); + } + if ( pEE->GetActiveView() ) + { + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Aktuelle View ===========================================" ); + fprintf( fp, "\n================================================================================" ); + DbgOutItemSet( fp, pEE->GetActiveView()->GetAttribs(), TRUE, FALSE ); + } + fclose( fp ); + if ( bInfoBox ) + InfoBox(0, String( RTL_CONSTASCII_USTRINGPARAM( "D:\\DEBUG.LOG !" ) ) ).Execute(); +} + +ByteString EditDbg::GetPortionInfo( ParaPortion* pPPortion ) +{ + USHORT z; + + ByteString aDebStr( "Absatzlaenge = " ); + aDebStr += ByteString::CreateFromInt32( pPPortion->GetNode()->Len() ); + + aDebStr += "\nZeichenattribute:"; + for ( z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); z++ ) + { + EditCharAttrib* pAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( z ); + aDebStr += "\n "; + aDebStr += ByteString::CreateFromInt32( pAttr->GetItem()->Which() ); + aDebStr += '\t'; + aDebStr += ByteString::CreateFromInt32( pAttr->GetStart() ); + aDebStr += '\t'; + aDebStr += ByteString::CreateFromInt32( pAttr->GetEnd() ); + } + + aDebStr += "\nTextportions:"; + USHORT n = 0; + for ( z = 0; z < pPPortion->GetTextPortions().Count(); z++ ) + { + TextPortion* pPortion = pPPortion->GetTextPortions().GetObject( z ); + aDebStr += " "; + aDebStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aDebStr += ")"; + aDebStr += ";"; + n = n + pPortion->GetLen(); + } + aDebStr += "\nGesamtlaenge: "; + aDebStr += ByteString::CreateFromInt32( n ); + aDebStr += "\nSortiert nach Start:"; + for ( USHORT x = 0; x < pPPortion->GetNode()->GetCharAttribs().Count(); x++ ) + { + EditCharAttrib* pCurAttrib = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( x ); + aDebStr += "\nStart: "; + aDebStr += ByteString::CreateFromInt32( pCurAttrib->GetStart() ); + aDebStr += "\tEnde: "; + aDebStr += ByteString::CreateFromInt32( pCurAttrib->GetEnd() ); + } + return aDebStr; +} + +ByteString EditDbg::GetTextPortionInfo( TextPortionList& rPortions ) +{ + ByteString aDebStr; + for ( USHORT z = 0; z < rPortions.Count(); z++ ) + { + TextPortion* pPortion = rPortions.GetObject( z ); + aDebStr += " "; + aDebStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aDebStr += ")"; + aDebStr += ";"; + } + return aDebStr; +} + +void EditDbg::ShowPortionData( ParaPortion* pPortion ) +{ + ByteString aDebStr( GetPortionInfo( pPortion ) ); + InfoBox( 0, String( aDebStr, RTL_TEXTENCODING_ASCII_US ) ).Execute(); +} + + +BOOL ParaPortion::DbgCheckTextPortions() +{ + // pruefen, ob Portionlaenge ok: + USHORT nXLen = 0; + for ( USHORT nPortion = 0; nPortion < aTextPortionList.Count(); nPortion++ ) + nXLen = nXLen + aTextPortionList[nPortion]->GetLen(); + return nXLen == pNode->Len() ? TRUE : FALSE; +} + +BOOL CheckOrderedList( CharAttribArray& rAttribs, BOOL bStart ) +{ + USHORT nPrev = 0; + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + USHORT nCur = bStart ? pAttr->GetStart() : pAttr->GetEnd(); + if ( nCur < nPrev ) + return FALSE; + + nPrev = nCur; + } + return TRUE; +} + +#endif + diff --git a/editeng/source/editeng/editdbg.hxx b/editeng/source/editeng/editdbg.hxx new file mode 100644 index 000000000000..efe3248e9af4 --- /dev/null +++ b/editeng/source/editeng/editdbg.hxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITDBG_HXX +#define _EDITDBG_HXX + +#include <svl/solar.hrc> +#include <tools/string.hxx> +#include <stdio.h> + +class EditEngine; +class ParaPortion; +class EditUndoList; +class TextPortionList; +class SfxItemSet; +class SfxItemPool; +class SfxPoolItem; + +ByteString DbgOutItem( const SfxItemPool& rPool, const SfxPoolItem& rItem ); +void DbgOutItemSet( FILE* fp, const SfxItemSet& rSet, BOOL bSearchInParent, BOOL bShowALL ); + +class EditDbg +{ +public: + static void ShowEditEngineData( EditEngine* pEditEngine, BOOL bInfoBox = TRUE ); + static void ShowPortionData( ParaPortion* pPortion ); + static ByteString GetPortionInfo( ParaPortion* pPPortion ); + static ByteString GetTextPortionInfo( TextPortionList& rPortions ); + static ByteString GetUndoDebStr( EditUndoList* pUndoList ); +}; + + +#endif // _EDITDBG_HXX diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx new file mode 100644 index 000000000000..9ac179a2a47f --- /dev/null +++ b/editeng/source/editeng/editdoc.cxx @@ -0,0 +1,2314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/tstpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/editids.hrc> + +#include <editdoc.hxx> +#include <editdbg.hxx> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <tools/shl.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <stdlib.h> // qsort + +using namespace ::com::sun::star; + + +// ------------------------------------------------------------ + +USHORT GetScriptItemId( USHORT nItemId, short nScriptType ) +{ + USHORT nId = nItemId; + + if ( ( nScriptType == i18n::ScriptType::ASIAN ) || + ( nScriptType == i18n::ScriptType::COMPLEX ) ) + { + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL; + break; + case EE_CHAR_FONTINFO: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL; + break; + case EE_CHAR_FONTHEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL; + break; + case EE_CHAR_WEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL; + break; + case EE_CHAR_ITALIC: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL; + break; + } + } + + return nId; +} + +BOOL IsScriptItemValid( USHORT nItemId, short nScriptType ) +{ + BOOL bValid = TRUE; + + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_LANGUAGE_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_LANGUAGE_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTINFO: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTINFO_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTINFO_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTHEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTHEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTHEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_WEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_WEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_WEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_ITALIC: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_ITALIC_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_ITALIC_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + } + + return bValid; +} + + +// ------------------------------------------------------------ + +// Sollte spaeter zentral nach TOOLS/STRING (Aktuell: 303) +// fuer Grep: WS_TARGET + +DBG_NAME( EE_TextPortion ); +DBG_NAME( EE_EditLine ); +DBG_NAME( EE_ContentNode ); +DBG_NAME( EE_CharAttribList ); + +SfxItemInfo aItemInfos[EDITITEMCOUNT] = { + { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE }, // EE_PARA_WRITINGDIR + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_XMLATTRIBS + { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE }, // EE_PARA_HANGINGPUNCTUATION + { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ASIANCJKSPACING + { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE }, // EE_PARA_NUMBULL + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_HYPHENATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_BULLETSTATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_OUTLLRSPACE + { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE }, + { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE }, + { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_RUBI_DUMMY + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_XMLATTRIBS + { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_TAB + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_LINEBR + { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE }, // EE_FEATURE_NOTCONV + { SID_FIELD, SFX_ITEM_POOLABLE } +}; + +USHORT aV1Map[] = { + 3999, 4001, 4002, 4003, 4004, 4005, 4006, + 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019? +}; + +USHORT aV2Map[] = { + 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, + 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020 +}; + +USHORT aV3Map[] = { + 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, + 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, + 4020, 4021 +}; + +USHORT aV4Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, + /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */ + 4034, 4035, 4036, 4037 +}; + +USHORT aV5Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, + 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, + /* EE_CHAR_OVERLINE inserted here */ + 4035, 4036, 4037, 4038 +}; + +SV_IMPL_PTRARR( DummyContentList, ContentNode* ); +SV_IMPL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo ); +SV_IMPL_VARARR( WritingDirectionInfos, WritingDirectionInfo ); +// SV_IMPL_VARARR( ExtraCharInfos, ExtraCharInfo ); + + +int SAL_CALL CompareStart( const void* pFirst, const void* pSecond ) +{ + if ( (*((EditCharAttrib**)pFirst))->GetStart() < (*((EditCharAttrib**)pSecond))->GetStart() ) + return (-1); + else if ( (*((EditCharAttrib**)pFirst))->GetStart() > (*((EditCharAttrib**)pSecond))->GetStart() ) + return (1); + return 0; +} + +EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) +{ + // das neue Attribut im Pool anlegen + const SfxPoolItem& rNew = rPool.Put( rAttr ); + + EditCharAttrib* pNew = 0; + switch( rNew.Which() ) + { + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + { + pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_COLOR: + { + pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTWIDTH: + { + pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_UNDERLINE: + { + pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OVERLINE: + { + pNew = new EditCharAttribOverline( (const SvxOverlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_EMPHASISMARK: + { + pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_RELIEF: + { + pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_STRIKEOUT: + { + pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OUTLINE: + { + pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_SHADOW: + { + pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_PAIRKERNING: + { + pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_KERNING: + { + pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WLM: + { + pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_XMLATTRIBS: + { + pNew = new EditCharAttrib( rNew, nS, nE ); // Attrib is only for holding XML information... + } + break; + case EE_FEATURE_TAB: + { + pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_LINEBR: + { + pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_FIELD: + { + pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS ); + } + break; + default: + { + DBG_ERROR( "Ungueltiges Attribut!" ); + } + } + return pNew; +} + +// ------------------------------------------------------------------------- +// class EditLine +// ------------------------------------------------------------------------- + +EditLine::EditLine() +{ + DBG_CTOR( EE_EditLine, 0 ); + + nStart = nEnd = 0; + nStartPortion = 0; // damit in ungueltiger Zeile ohne Portions von einer gueltigen Zeile mit der Portion Nr0 unterscieden werden kann. + nEndPortion = 0; + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bHangingPunctuation = FALSE; + bInvalid = TRUE; +} + +EditLine::EditLine( const EditLine& r ) +{ + DBG_CTOR( EE_EditLine, 0 ); + + nEnd = r.nEnd; + nStart = r.nStart; + nStartPortion = r.nStartPortion; + nEndPortion = r.nEndPortion; + bHangingPunctuation = r.bHangingPunctuation; + + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bInvalid = TRUE; +} + +EditLine::~EditLine() +{ + DBG_DTOR( EE_EditLine, 0 ); +} + +EditLine* EditLine::Clone() const +{ + EditLine* pL = new EditLine; + if ( aPositions.Count() ) + { + pL->aPositions.Insert (aPositions.GetData(), aPositions.Count(), 0); + } + pL->nStartPosX = nStartPosX; + pL->nStart = nStart; + pL->nEnd = nEnd; + pL->nStartPortion = nStartPortion; + pL->nEndPortion = nEndPortion; + pL->nHeight = nHeight; + pL->nTxtWidth = nTxtWidth; + pL->nTxtHeight = nTxtHeight; + pL->nCrsrHeight = nCrsrHeight; + pL->nMaxAscent = nMaxAscent; + + return pL; +} + +BOOL operator == ( const EditLine& r1, const EditLine& r2 ) +{ + if ( r1.nStart != r2.nStart ) + return FALSE; + + if ( r1.nEnd != r2.nEnd ) + return FALSE; + + if ( r1.nStartPortion != r2.nStartPortion ) + return FALSE; + + if ( r1.nEndPortion != r2.nEndPortion ) + return FALSE; + + return TRUE; +} + +EditLine& EditLine::operator = ( const EditLine& r ) +{ + nEnd = r.nEnd; + nStart = r.nStart; + nEndPortion = r.nEndPortion; + nStartPortion = r.nStartPortion; + return *this; +} + + +BOOL operator != ( const EditLine& r1, const EditLine& r2 ) +{ + return !( r1 == r2 ); +} + +Size EditLine::CalcTextSize( ParaPortion& rParaPortion ) +{ + Size aSz; + Size aTmpSz; + TextPortion* pPortion; + + USHORT nIndex = GetStart(); + + DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize vor CreatePortions !" ); + + for ( USHORT n = nStartPortion; n <= nEndPortion; n++ ) + { + pPortion = rParaPortion.GetTextPortions().GetObject(n); + switch ( pPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + { + aTmpSz = pPortion->GetSize(); + aSz.Width() += aTmpSz.Width(); + if ( aSz.Height() < aTmpSz.Height() ) + aSz.Height() = aTmpSz.Height(); + } + break; + case PORTIONKIND_TAB: +// case PORTIONKIND_EXTRASPACE: + { + aSz.Width() += pPortion->GetSize().Width(); + } + break; + } + nIndex = nIndex + pPortion->GetLen(); + } + + SetHeight( (USHORT)aSz.Height() ); + return aSz; +} + +// ------------------------------------------------------------------------- +// class EditLineList +// ------------------------------------------------------------------------- +EditLineList::EditLineList() +{ +} + +EditLineList::~EditLineList() +{ + Reset(); +} + +void EditLineList::Reset() +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + delete GetObject(nLine); + Remove( 0, Count() ); +} + +void EditLineList::DeleteFromLine( USHORT nDelFrom ) +{ + DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" ); + for ( USHORT nL = nDelFrom; nL < Count(); nL++ ) + delete GetObject(nL); + Remove( nDelFrom, Count()-nDelFrom ); +} + +USHORT EditLineList::FindLine( USHORT nChar, BOOL bInclEnd ) +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + { + EditLine* pLine = GetObject( nLine ); + if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || + ( pLine->GetEnd() > nChar ) ) + { + return nLine; + } + } + + DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" ); + return ( Count() - 1 ); +} + +// ------------------------------------------------------------------------- +// class EditSelection +// ------------------------------------------------------------------------- +BOOL EditPaM::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( !pNode ) + return TRUE; + if ( rDoc.GetPos( pNode ) >= rDoc.Count() ) + return TRUE; + if ( nIndex > pNode->Len() ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( aStartPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + if ( aEndPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + + return FALSE; +} + +EditSelection::EditSelection() +{ +} + +EditSelection::EditSelection( const EditPaM& rStartAndAnd ) +{ + // koennte noch optimiert werden! + // nicht erst Def-CTOR vom PaM rufen! + aStartPaM = rStartAndAnd; + aEndPaM = rStartAndAnd; +} + +EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd ) +{ + // koennte noch optimiert werden! + aStartPaM = rStart; + aEndPaM = rEnd; +} + +EditSelection& EditSelection::operator = ( const EditPaM& rPaM ) +{ + aStartPaM = rPaM; + aEndPaM = rPaM; + return *this; +} + +BOOL EditSelection::IsInvalid() const +{ + EditPaM aEmptyPaM; + + if ( aStartPaM == aEmptyPaM ) + return TRUE; + + if ( aEndPaM == aEmptyPaM ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::Adjust( const ContentList& rNodes ) +{ + DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in Adjust(1)" ); + DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in Adjust(2)" ); + + ContentNode* pStartNode = aStartPaM.GetNode(); + ContentNode* pEndNode = aEndPaM.GetNode(); + + USHORT nStartNode = rNodes.GetPos( pStartNode ); + USHORT nEndNode = rNodes.GetPos( pEndNode ); + + DBG_ASSERT( nStartNode != USHRT_MAX, "Node im Wald in Adjust(1)" ); + DBG_ASSERT( nEndNode != USHRT_MAX, "Node im Wald in Adjust(2)" ); + + BOOL bSwap = FALSE; + if ( nStartNode > nEndNode ) + bSwap = TRUE; + else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) ) + bSwap = TRUE; + + if ( bSwap ) + { + EditPaM aTmpPaM( aStartPaM ); + aStartPaM = aEndPaM; + aEndPaM = aTmpPaM; + } + + return bSwap; +} + + +// ------------------------------------------------------------------------- +// class EditPaM +// ------------------------------------------------------------------------- +BOOL operator == ( const EditPaM& r1, const EditPaM& r2 ) +{ + if ( r1.GetNode() != r2.GetNode() ) + return FALSE; + + if ( r1.GetIndex() != r2.GetIndex() ) + return FALSE; + + return TRUE; +} + +EditPaM& EditPaM::operator = ( const EditPaM& rPaM ) +{ + nIndex = rPaM.nIndex; + pNode = rPaM.pNode; + return *this; +} + +BOOL operator != ( const EditPaM& r1, const EditPaM& r2 ) +{ + return !( r1 == r2 ); +} + + +// ------------------------------------------------------------------------- +// class ContentNode +// ------------------------------------------------------------------------- +ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) : + XubString( rStr ), aContentAttribs( rContentAttribs ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::~ContentNode() +{ + DBG_DTOR( EE_ContentNode, 0 ); +#ifndef SVX_LIGHT + delete pWrongList; +#endif +} + +void ContentNode::ExpandAttribs( USHORT nIndex, USHORT nNew, SfxItemPool& rItemPool ) +{ + if ( !nNew ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + // In jedem if..., in dem weiter (n) Moeglichkeiten aufgrund von + // bFeature oder Spezialfall existieren, + // muessen (n-1) Moeglichkeiten mit bResort versehen werden. + // Die wahrscheinlichste Moeglichkeit erhaelt kein bResort, + // so dass nicht neu sortiert wird, wenn sich alle Attribute + // gleich verhalten. + BOOL bResort = FALSE; + BOOL bExpandedEmptyAtIndexNull = FALSE; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alle Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() > nIndex ) + { + pAttrib->MoveForward( nNew ); + } + // 0: Leeres Attribut expandieren, wenn an Einfuegestelle + else if ( pAttrib->IsEmpty() ) + { + // Index nicht pruefen, leeres durfte nur dort liegen. + // Wenn spaeter doch Ueberpruefung: + // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch! + // Start <= nIndex, End >= nIndex => Start=End=nIndex! +// if ( pAttrib->GetStart() == nIndex ) + pAttrib->Expand( nNew ); + if ( pAttrib->GetStart() == 0 ) + bExpandedEmptyAtIndexNull = TRUE; + } + // 1: Attribut startet davor, geht bis Index... + else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen + { + // Nur expandieren, wenn kein Feature, + // und wenn nicht in ExcludeListe! + // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren +// if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) ) + if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) + { + if ( !pAttrib->IsEdge() ) + pAttrib->Expand( nNew ); + } + else + bResort = TRUE; + } + // 2: Attribut startet davor, geht hinter Index... + else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Grosses Feature?!" ); + pAttrib->Expand( nNew ); + } + // 3: Attribut startet auf Index... + else if ( pAttrib->GetStart() == nIndex ) + { + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveForward( nNew ); + bResort = TRUE; + } + else + { + BOOL bExpand = FALSE; + if ( nIndex == 0 ) + { + bExpand = TRUE; + if( bExpandedEmptyAtIndexNull ) + { + // Check if this kind of attribut was empty and expanded here... + USHORT nW = pAttrib->GetItem()->Which(); + for ( USHORT nA = 0; nA < nAttr; nA++ ) + { + EditCharAttrib* pA = aCharAttribList.GetAttribs()[nA]; + if ( ( pA->GetStart() == 0 ) && ( pA->GetItem()->Which() == nW ) ) + { + bExpand = FALSE; + break; + } + } + + } + } + if ( bExpand ) + { + pAttrib->Expand( nNew ); + bResort = TRUE; + } + else + { + pAttrib->MoveForward( nNew ); + } + } + } + } + + if ( pAttrib->IsEdge() ) + pAttrib->SetEdge( FALSE ); + + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attrib groesser als Absatz!" ); + if ( pAttrib->IsEmpty() ) + { + DBG_ERROR( "Leeres Attribut nach ExpandAttribs?" ); + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + { + BOOL bSep = ( GetChar( nIndex ) == ' ' ) || IsFeature( nIndex ); + pWrongList->TextInserted( nIndex, nNew, bSep ); + } +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Expand: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CollapsAttribs( USHORT nIndex, USHORT nDeleted, SfxItemPool& rItemPool ) +{ + if ( !nDeleted ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + BOOL bResort = FALSE; + BOOL bDelAttr = FALSE; + USHORT nEndChanges = nIndex+nDeleted; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + bDelAttr = FALSE; + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alles Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() >= nEndChanges ) + { + pAttrib->MoveBackward( nDeleted ); + } + // 1. Innenliegende Attribute loeschen... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) + { + // Spezialfall: Attrubt deckt genau den Bereich ab + // => als leeres Attribut behalten. + if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) + pAttrib->GetEnd() = nIndex; // leer + else + bDelAttr = TRUE; + } + // 2. Attribut beginnt davor, endet drinnen oder dahinter... + else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" ); + if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen + pAttrib->GetEnd() = nIndex; + else + pAttrib->Collaps( nDeleted ); // endet dahinter + } + // 3. Attribut beginnt drinnen, endet dahinter... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) + { + // Features duerfen nicht expandieren! + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveBackward( nDeleted ); + bResort = TRUE; + } + else + { + pAttrib->GetStart() = nEndChanges; + pAttrib->MoveBackward( nDeleted ); + } + } + } + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" ); + if ( bDelAttr /* || pAttrib->IsEmpty() */ ) + { + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + else if ( pAttrib->IsEmpty() ) + aCharAttribList.HasEmptyAttribs() = TRUE; + + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + pWrongList->TextDeleted( nIndex, nDeleted ); +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Collaps: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( pPrevNode, "kopieren von Attributen auf einen NULL-Pointer ?" ); + + xub_StrLen nCut = pPrevNode->Len(); + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() < nCut ) + { + // bleiben unveraendert.... + ; + } + else if ( pAttrib->GetEnd() == nCut ) + { + // muessen als leeres Attribut kopiert werden. + if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) ) + { + EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 ); + DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" ); + aCharAttribList.InsertAttrib( pNewAttrib ); + } + } + else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) ) + { + // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben! + // muessen kopiert und geaendert werden + EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut ); + DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" ); + aCharAttribList.InsertAttrib( pNewAttrib ); + // stutzen: + pAttrib->GetEnd() = nCut; + } + else + { + // alle dahinter verschieben in den neuen Node (this) +// pPrevNode->GetCharAttribs().RemoveAttrib( pAttrib ); + pPrevNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + aCharAttribList.InsertAttrib( pAttrib ); + DBG_ASSERT( pAttrib->GetStart() >= nCut, "Start < nCut!" ); + DBG_ASSERT( pAttrib->GetEnd() >= nCut, "End < nCut!" ); + pAttrib->GetStart() = pAttrib->GetStart() - nCut; + pAttrib->GetEnd() = pAttrib->GetEnd() - nCut; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +void ContentNode::AppendAttribs( ContentNode* pNextNode ) +{ + DBG_ASSERT( pNextNode, "kopieren von Attributen von einen NULL-Pointer ?" ); + + USHORT nNewStart = Len(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" ); +#endif + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + // alle Attribute verschieben in den aktuellen Node (this) + BOOL bMelted = FALSE; + if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) ) + { + // Evtl koennen Attribute zusammengefasst werden: + USHORT nTmpAttr = 0; + EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr ); + while ( !bMelted && pTmpAttrib ) + { + if ( pTmpAttrib->GetEnd() == nNewStart ) + { + if ( ( pTmpAttrib->Which() == pAttrib->Which() ) && + ( *(pTmpAttrib->GetItem()) == *(pAttrib->GetItem() ) ) ) + { + pTmpAttrib->GetEnd() = + pTmpAttrib->GetEnd() + pAttrib->GetLen(); + pNextNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + // Vom Pool abmelden ?! + delete pAttrib; + bMelted = TRUE; + } + } + ++nTmpAttr; + pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr ); + } + } + + if ( !bMelted ) + { + pAttrib->GetStart() = pAttrib->GetStart() + nNewStart; + pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart; + aCharAttribList.InsertAttrib( pAttrib ); + ++nAttr; + } + pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + } + // Fuer die Attribute, die nur ruebergewandert sind: + pNextNode->GetCharAttribs().Clear(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" ); +#endif +} + +void ContentNode::CreateDefFont() +{ + // Erst alle Informationen aus dem Style verwenden... + SfxStyleSheet* pS = aContentAttribs.GetStyleSheet(); + if ( pS ) + CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() ); + + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ) +{ + aContentAttribs.SetStyleSheet( pS ); + + // Erst alle Informationen aus dem Style verwenden... + GetCharAttribs().GetDefFont() = rFontFromStyle; + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont ) +{ + aContentAttribs.SetStyleSheet( pS ); + if ( bRecalcFont ) + CreateDefFont(); +} + +void ContentNode::DestroyWrongList() +{ +#ifndef SVX_LIGHT + delete pWrongList; +#endif + pWrongList = NULL; +} + +void ContentNode::CreateWrongList() +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); +#ifndef SVX_LIGHT + pWrongList = new WrongList; +#endif +} + +void ContentNode::SetWrongList( WrongList* p ) +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); + pWrongList = p; +} + +// ------------------------------------------------------------------------- +// class ContentAttribs +// ------------------------------------------------------------------------- +ContentAttribs::ContentAttribs( SfxItemPool& rPool ) : + aAttribSet( rPool, EE_PARA_START, EE_CHAR_END ) +{ + pStyle = 0; +} + +ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) : + aAttribSet( rRef.aAttribSet ) +{ + pStyle = rRef.pStyle; +} + +ContentAttribs::~ContentAttribs() +{ +} + +SvxTabStop ContentAttribs::FindTabStop( long nCurPos, USHORT nDefTab ) +{ + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS ); + for ( USHORT i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + if ( rTab.GetTabPos() > nCurPos ) + return rTab; + } + + // DefTab ermitteln... + SvxTabStop aTabStop; + long x = nCurPos / nDefTab + 1; + aTabStop.GetTabPos() = nDefTab * x; + return aTabStop; +} + +void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS ) +{ + BOOL bStyleChanged = ( pStyle != pS ); + pStyle = pS; + // #104799# Only when other style sheet, not when current style sheet modified + if ( pStyle && bStyleChanged ) + { + // Gezielt die Attribute aus der Absatzformatierung entfernen, die im Style + // spezifiziert sind, damit die Attribute des Styles wirken koennen. + const SfxItemSet& rStyleAttribs = pStyle->GetItemSet(); + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + // #99635# Don't change bullet on/off + if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) ) + aAttribSet.ClearItem( nWhich ); + } + } +} + +const SfxPoolItem& ContentAttribs::GetItem( USHORT nWhich ) +{ + // Harte Absatzattribute haben Vorrang! + SfxItemSet* pTakeFrom = &aAttribSet; + if ( pStyle && ( aAttribSet.GetItemState( nWhich, FALSE ) != SFX_ITEM_ON ) ) + pTakeFrom = &pStyle->GetItemSet(); + + return pTakeFrom->Get( nWhich ); +} + +BOOL ContentAttribs::HasItem( USHORT nWhich ) +{ + BOOL bHasItem = FALSE; + if ( aAttribSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_ON ) + bHasItem = TRUE; + else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON ) + bHasItem = TRUE; + + return bHasItem; +} + + + +// ---------------------------------------------------------------------- +// class ItemList +// ---------------------------------------------------------------------- +const SfxPoolItem* ItemList::FindAttrib( USHORT nWhich ) +{ + const SfxPoolItem* pItem = First(); + while ( pItem && ( pItem->Which() != nWhich ) ) + pItem = Next(); + + return pItem; +} + +// ------------------------------------------------------------------------- +// class EditDoc +// ------------------------------------------------------------------------- +EditDoc::EditDoc( SfxItemPool* pPool ) +{ + if ( pPool ) + { + pItemPool = pPool; + bOwnerOfPool = FALSE; + } + else + { + pItemPool = new EditEngineItemPool( FALSE ); + bOwnerOfPool = TRUE; + } + + nDefTab = DEFTAB; + bIsVertical = FALSE; + bIsFixedCellHeight = FALSE; + + // Don't create a empty node, Clear() will be called in EditEngine-CTOR + + SetModified( FALSE ); +}; + +EditDoc::~EditDoc() +{ + ImplDestroyContents(); + if ( bOwnerOfPool ) + SfxItemPool::Free(pItemPool); +} + +void EditDoc::ImplDestroyContents() +{ + for ( USHORT nNode = Count(); nNode; ) + RemoveItemsFromPool( GetObject( --nNode ) ); + DeleteAndDestroy( 0, Count() ); +} + +void EditDoc::RemoveItemsFromPool( ContentNode* pNode ) +{ + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[nAttr]; + GetItemPool().Remove( *pAttr->GetItem() ); + } +} + +void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType ) +{ + Font aPrevFont( rFont ); + rFont.SetAlign( ALIGN_BASELINE ); + rFont.SetTransparent( TRUE ); + + USHORT nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); + USHORT nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + USHORT nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ); + USHORT nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ); + USHORT nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType ); + + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo ); + rFont.SetName( rFontItem.GetFamilyName() ); + rFont.SetFamily( rFontItem.GetFamily() ); + rFont.SetPitch( rFontItem.GetPitch() ); + rFont.SetCharSet( rFontItem.GetCharSet() ); + } + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) ) + rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) ) + rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) ) + rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) ) + rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) ) + rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SFX_ITEM_ON ) ) + rFont.SetOverline( ((const SvxOverlineItem&)rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) ) + rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) ) + rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) ) + rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) ) + rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) ) + { + const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT ); + + USHORT nProp = rEsc.GetProp(); + rFont.SetPropr( (BYTE)nProp ); + + short nEsc = rEsc.GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + nEsc = 100 - nProp; + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + rFont.SetEscapement( nEsc ); + } + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) ) + rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) ) + rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) ) + rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) ) + rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) ) + rFont.SetRelief( (FontRelief)((const SvxCharReliefItem&)rSet.Get( EE_CHAR_RELIEF )).GetValue() ); + + // Ob ich jetzt den ganzen Font vergleiche, oder vor jeder Aenderung + // pruefe, ob der Wert sich aendert, bleibt sich relativ gleich. + // So ggf ein MakeUniqFont im Font mehr, dafuer bei Aenderung schnellerer + // Abbruch der Abfrage, oder ich musste noch jedesmal ein bChanged pflegen. + if ( rFont == aPrevFont ) + rFont = aPrevFont; // => Gleicher ImpPointer fuer IsSameInstance +} + +void EditDoc::CreateDefFont( BOOL bUseStyles ) +{ + SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END ); + CreateFont( aDefFont, aTmpSet ); + aDefFont.SetVertical( IsVertical() ); + aDefFont.SetOrientation( IsVertical() ? 2700 : 0 ); + + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + pNode->GetCharAttribs().GetDefFont() = aDefFont; + if ( bUseStyles ) + pNode->CreateDefFont(); + } +} + +static const sal_Unicode aCR[] = { 0x0d, 0x00 }; +static const sal_Unicode aLF[] = { 0x0a, 0x00 }; +static const sal_Unicode aCRLF[] = { 0x0d, 0x0a, 0x00 }; + +XubString EditDoc::GetSepStr( LineEnd eEnd ) +{ + XubString aSep; + if ( eEnd == LINEEND_CR ) + aSep = aCR; + else if ( eEnd == LINEEND_LF ) + aSep = aLF; + else + aSep = aCRLF; + return aSep; +} + +XubString EditDoc::GetText( LineEnd eEnd ) const +{ + ULONG nLen = GetTextLen(); + USHORT nNodes = Count(); + + String aSep = EditDoc::GetSepStr( eEnd ); + USHORT nSepSize = aSep.Len(); + + if ( nSepSize ) + nLen += nNodes * nSepSize; + if ( nLen > 0xFFFb / sizeof(xub_Unicode) ) + { + DBG_ERROR( "Text zu gross fuer String" ); + return XubString(); + } + xub_Unicode* pStr = new xub_Unicode[nLen+1]; + xub_Unicode* pCur = pStr; + USHORT nLastNode = nNodes-1; + for ( USHORT nNode = 0; nNode < nNodes; nNode++ ) + { + XubString aTmp( GetParaAsString( GetObject(nNode) ) ); + memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) ); + pCur += aTmp.Len(); + if ( nSepSize && ( nNode != nLastNode ) ) + { + memcpy( pCur, aSep.GetBuffer(), nSepSize*sizeof(sal_Unicode ) ); + pCur += nSepSize; + } + } + *pCur = '\0'; + XubString aASCIIText( pStr ); + delete[] pStr; + return aASCIIText; +} + +XubString EditDoc::GetParaAsString( USHORT nNode ) const +{ + return GetParaAsString( SaveGetObject( nNode ) ); +} + +XubString EditDoc::GetParaAsString( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, BOOL bResolveFields ) const +{ + if ( nEndPos > pNode->Len() ) + nEndPos = pNode->Len(); + + DBG_ASSERT( nStartPos <= nEndPos, "Start und Ende vertauscht?" ); + + USHORT nIndex = nStartPos; + XubString aStr; + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + while ( nIndex < nEndPos ) + { + USHORT nEnd = nEndPos; + if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) ) + nEnd = pNextFeature->GetStart(); + else + pNextFeature = 0; // Feature interessiert unten nicht + + DBG_ASSERT( nEnd >= nIndex, "Ende vorm Index?" ); + //!! beware of sub string length of -1 which is also defined as STRING_LEN and + //!! thus would result in adding the whole sub string up to the end of the node !! + if (nEnd > nIndex) + aStr += XubString( *pNode, nIndex, nEnd - nIndex ); + + if ( pNextFeature ) + { + switch ( pNextFeature->GetItem()->Which() ) + { + case EE_FEATURE_TAB: aStr += '\t'; + break; + case EE_FEATURE_LINEBR: aStr += '\x0A'; + break; + case EE_FEATURE_FIELD: if ( bResolveFields ) + aStr += ((EditCharAttribField*)pNextFeature)->GetFieldValue(); + break; + default: DBG_ERROR( "Was fuer ein Feature ?" ); + } + pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd ); + } + nIndex = nEnd; + } + return aStr; +} + +ULONG EditDoc::GetTextLen() const +{ + ULONG nLen = 0; + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + nLen += pNode->Len(); + // Felder k”nnen laenger sein als der Platzhalter im Node. + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( USHORT nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + USHORT nFieldLen = ((EditCharAttribField*)pAttr)->GetFieldValue().Len(); + if ( !nFieldLen ) + nLen--; + else + nLen += nFieldLen-1; + } + } + } + return nLen; +} + +EditPaM EditDoc::Clear() +{ + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + CreateDefFont( FALSE ); + + SetModified( FALSE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::SetModified( BOOL b ) +{ + bModified = b; + if ( bModified ) + { + aModifyHdl.Call( NULL ); + } +} + +EditPaM EditDoc::RemoveText() +{ + // Das alte ItemSetmerken, damit z.B. im Chart Font behalten bleibt + ContentNode* pPrevFirstNode = GetObject(0); + SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet(); + SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() ); + Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() ); + + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + pNode->SetStyleSheet( pPrevStyle, FALSE ); + pNode->GetContentAttribs().GetItems().Set( aPrevSet ); + pNode->GetCharAttribs().GetDefFont() = aPrevFont; + + SetModified( TRUE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::InsertText( const EditPaM& rPaM, xub_Unicode c ) +{ + DBG_ASSERT( c != 0x0A, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != 0x0D, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != '\t', "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + + rPaM.GetNode()->Insert( c, rPaM.GetIndex() ); + rPaM.GetNode()->ExpandAttribs( rPaM.GetIndex(), 1, GetItemPool() ); + + SetModified( TRUE ); +} + +EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" ); + + aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() ); + aPaM.GetIndex() = aPaM.GetIndex() + rStr.Len(); + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" ); + ContentNode* pCurNode = aPaM.GetNode(); + USHORT nPos = GetPos( pCurNode ); + XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() ); + aPaM.GetNode()->Erase( aPaM.GetIndex() ); + + // the paragraph attributes... + ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() ); + + // for a new paragraph we like to have the bullet/numbering visible by default + aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, TRUE), EE_PARA_BULLETSTATE ); + + // ContenNode-CTOR kopiert auch die Absatzattribute + ContentNode* pNode = new ContentNode( aStr, aContentAttribs ); + + // Den Default-Font kopieren + pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont(); + SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet(); + if ( pStyle ) + { + XubString aFollow( pStyle->GetFollow() ); + if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) ) + { + SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() ); + pNode->SetStyleSheet( (SfxStyleSheet*)pNext ); + } + } + + // Zeichenattribute muessen ggf. kopiert bzw gestutzt werden: + pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs ); + + Insert( pNode, nPos+1 ); + + SetModified( TRUE ); + + aPaM.SetNode( pNode ); + aPaM.SetIndex( 0 ); + return aPaM; +} + +EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" ); + + aPaM.GetNode()->Insert( CH_FEATURE, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() ); + + // Fuer das Feature ein Feature-Attribut anlegen... + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 ); + DBG_ASSERT( pAttrib, "Warum kann ich kein Feature anlegen ?" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); + + aPaM.GetIndex()++; + return aPaM; +} + +EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ) +{ + const EditPaM aPaM( pLeft, pLeft->Len() ); + + // Erst die Attribute, da sonst nLen nicht stimmt! + pLeft->AppendAttribs( pRight ); + // Dann den Text... + *pLeft += *pRight; + + // der rechte verschwindet. + RemoveItemsFromPool( pRight ); + USHORT nRight = GetPos( pRight ); + Remove( nRight ); + delete pRight; + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::RemoveChars( EditPaM aPaM, USHORT nChars ) +{ + // Evtl. Features entfernen! + aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars ); + aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() ); + + SetModified( TRUE ); + + return aPaM; +} + +void EditDoc::InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // fuer Optimierung: + // dieses endet am Anfang der Selektion => kann erweitert werden + EditCharAttrib* pEndingAttrib = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + EditCharAttrib* pStartingAttrib = 0; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() ); + + if ( pStartingAttrib && pEndingAttrib && + ( *(pStartingAttrib->GetItem()) == rPoolItem ) && + ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + { + // wird ein groesses Attribut. + pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd(); + GetItemPool().Remove( *(pStartingAttrib->GetItem()) ); + pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) ); + delete pStartingAttrib; + } + else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) ) + pStartingAttrib->GetStart() = nStart; + else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + pEndingAttrib->GetEnd() = nEnd; + else + InsertAttrib( rPoolItem, pNode, nStart, nEnd ); + + if ( pStartingAttrib ) + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich ) +{ + EditCharAttrib* pStarting; + EditCharAttrib* pEnding; + return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // dieses endet am Anfang der Selektion => kann erweitert werden + rpEnding = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + rpStarting = 0; + + BOOL bChanged = FALSE; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + // ueber die Attribute iterieren... + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + BOOL bRemoveAttrib = FALSE; + // MT 11.9.97: + // Ich denke dass in dieser Methode generell keine Features geloescht + // werden sollen. + // => Dann koennen die Feature-Abfragen weiter unten entfallen + USHORT nAttrWhich = pAttr->Which(); + if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) ) + { + // Attribut beginnt in Selection + if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetEnd() > nEnd ) + { + pAttr->GetStart() = nEnd; // dann faengt es dahinter an + rpStarting = pAttr; + if ( nWhich ) + break; // es kann kein weiteres Attrib hier liegen + } + else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) + { + // Feature nur loeschen, wenn genau an der Stelle + bRemoveAttrib = TRUE; + } + } + + // Attribut endet in Selection + else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) ) + { + bChanged = TRUE; + if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() ) + { + pAttr->GetEnd() = nStart; // dann hoert es hier auf + rpEnding = pAttr; + } + else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) + { + // Feature nur loeschen, wenn genau an der Stelle + bRemoveAttrib = TRUE; + } + } + // Attribut ueberlappt die Selektion + else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetStart() == nStart ) + { + pAttr->GetStart() = nEnd; + rpStarting = pAttr; + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + else if ( pAttr->GetEnd() == nEnd ) + { + pAttr->GetEnd() = nStart; + rpEnding = pAttr; + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + else // Attribut muss gesplittet werden... + { + USHORT nOldEnd = pAttr->GetEnd(); + pAttr->GetEnd() = nStart; + rpEnding = pAttr; + InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd ); + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + } + } + if ( bRemoveAttrib ) + { + DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" ); + DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" ); + pNode->GetCharAttribs().GetAttribs().Remove(nAttr); + GetItemPool().Remove( *pAttr->GetItem() ); + delete pAttr; + nAttr--; + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + + if ( bChanged ) + { + // char attributes need to be sorted by start again + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); + } + + return bChanged; +} + +void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, USHORT nStart, USHORT nEnd ) +{ + // Diese Methode prueft nicht mehr, ob ein entspr. Attribut + // schon an der Stelle existiert! + + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd ); + DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" ); + pNode->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); +} + +void EditDoc::InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + if ( nStart != nEnd ) + { + InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem ); + } + else + { + // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle: + EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + // Attribut entfernen.... + pNode->GetCharAttribs().GetAttribs().Remove( + pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) ); + } + + // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt. + pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + if ( pAttr->IsInside( nStart ) ) // splitten + { + // ??????????????????????????????? + // eigentlich noch pruefen, ob wirklich splittet, oder return ! + // ??????????????????????????????? + USHORT nOldEnd = pAttr->GetEnd(); + pAttr->GetEnd() = nStart; + pAttr = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd ); + pNode->GetCharAttribs().InsertAttrib( pAttr ); + } + else if ( pAttr->GetEnd() == nStart ) + { + DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" ); + // pruefen, ob genau das gleiche Attribut + if ( *(pAttr->GetItem()) == rPoolItem ) + return; + } + } + InsertAttrib( rPoolItem, pNode, nStart, nStart ); + } + + SetModified( TRUE ); +} + +void EditDoc::FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet ) +{ + DBG_ASSERT( pNode, "Wo soll ich suchen ?" ); + DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + // keine Selection... + if ( nStartPos == nEndPos ) + { + while ( pAttr && ( pAttr->GetStart() <= nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + pItem = pAttr->GetItem(); + // Attribut endet hier, ist nicht leer + else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) ) + pItem = pAttr->GetItem(); + } + // Attribut endet hier, ist leer + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + pItem = pAttr->GetItem(); + } + // Attribut beginnt hier + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + { + if ( nStartPos == 0 ) // Sonderfall + pItem = pAttr->GetItem(); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } + else // Selektion + { + while ( pAttr && ( pAttr->GetStart() < nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) ) + pItem = pAttr->GetItem(); + // Attribut startet mitten drin... + else if ( pAttr->GetStart() >= nStartPos ) + { + // !!! pItem = pAttr->GetItem(); + // einfach nur pItem reicht nicht, da ich z.B. bei Shadow + // niemals ein ungleiches Item finden wuerde, da ein solche + // seine Anwesenheit durch Abwesenheit repraesentiert! + // if ( ... ) + // Es muesste geprueft werden, on genau das gleiche Attribut + // an der Bruchstelle aufsetzt, was recht aufwendig ist. + // Da ich beim Einfuegen von Attributen aber etwas optimiere + // tritt der Fall nicht so schnell auf... + // Also aus Geschwindigkeitsgruenden: + rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); + + } + // Attribut endet mitten drin... + else if ( pAttr->GetEnd() > nStartPos ) + { + // pItem = pAttr->GetItem(); + // s.o. + /*-----------------31.05.95 16:01------------------- + Ist falsch, wenn das gleiche Attribut sofort wieder + eingestellt wird! + => Sollte am besten nicht vorkommen, also gleich beim + Setzen von Attributen richtig machen! + --------------------------------------------------*/ + rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } +} + + +// ------------------------------------------------------------------------- +// class EditCharAttribList +// ------------------------------------------------------------------------- + +CharAttribList::CharAttribList() +{ + DBG_CTOR( EE_CharAttribList, 0 ); + bHasEmptyAttribs = FALSE; +} + +CharAttribList::~CharAttribList() +{ + DBG_DTOR( EE_CharAttribList, 0 ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + delete pAttr; + ++nAttr; + pAttr = GetAttrib( aAttribs, nAttr ); + } + Clear(); +} + +void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib ) +{ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// optimieren: binaere Suche ? ! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // MT: 26.11.98 + // Vielleicht aber auch einfach nur rueckwaerts iterieren: + // Der haeufigste und kritischste Fall: Attribute kommen bereits + // sortiert an (InsertBinTextObject!) + // Hier waere auch binaere Suche nicht optimal. + // => Wuerde einiges bringen! + + const USHORT nCount = Count(); + const USHORT nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt. + + if ( pAttrib->IsEmpty() ) + bHasEmptyAttribs = TRUE; + + BOOL bInserted = FALSE; + for ( USHORT x = 0; x < nCount; x++ ) + { + EditCharAttribPtr pCurAttrib = aAttribs[x]; + if ( pCurAttrib->GetStart() > nStart ) + { + aAttribs.Insert( pAttrib, x ); + bInserted = TRUE; + break; + } + } + if ( !bInserted ) + aAttribs.Insert( pAttrib, nCount ); +} + +void CharAttribList::ResortAttribs() +{ + if ( Count() ) + { +#if defined __SUNPRO_CC +#pragma disable_warn +#endif + qsort( (void*)aAttribs.GetData(), aAttribs.Count(), sizeof( EditCharAttrib* ), CompareStart ); +#if defined __SUNPRO_CC +#pragma enable_warn +#endif + } +} + +void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool ) +{ + for ( USHORT n = 0; n < aAttribs.Count(); n++ ) + { + EditCharAttrib* pAttr = aAttribs.GetObject( n ); + for ( USHORT nNext = n+1; nNext < aAttribs.Count(); nNext++ ) + { + EditCharAttrib* p = aAttribs.GetObject( nNext ); + if ( !pAttr->IsFeature() && ( p->GetStart() == pAttr->GetEnd() ) && ( p->Which() == pAttr->Which() ) ) + { + if ( *p->GetItem() == *pAttr->GetItem() ) + { + pAttr->GetEnd() = p->GetEnd(); + aAttribs.Remove( nNext ); + rItemPool.Remove( *p->GetItem() ); + delete p; + } + break; // only 1 attr with same which can start here. + } + else if ( p->GetStart() > pAttr->GetEnd() ) + { + break; + } + } + } +} + +EditCharAttrib* CharAttribList::FindAttrib( USHORT nWhich, USHORT nPos ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) ) + return pAttr; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const +{ + DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); + const USHORT nAttribs = aAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[ nAttr ]; + if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + } + return 0; +} + +BOOL CharAttribList::HasAttrib( USHORT nWhich ) const +{ + for ( USHORT nAttr = aAttribs.Count(); nAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( pAttr->Which() == nWhich ) + return TRUE; + } + return FALSE; +} + +BOOL CharAttribList::HasAttrib( USHORT nStartPos, USHORT nEndPos ) const +{ + BOOL bAttr = FALSE; + for ( USHORT nAttr = aAttribs.Count(); nAttr && !bAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( ( pAttr->GetStart() < nEndPos ) && ( pAttr->GetEnd() > nStartPos ) ) + return bAttr = TRUE; + } + return bAttr; +} + + +BOOL CharAttribList::HasBoundingAttrib( USHORT nBound ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetEnd() >= nBound ) ) + { + if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) + return TRUE; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return FALSE; +} + +EditCharAttrib* CharAttribList::FindEmptyAttrib( USHORT nWhich, USHORT nPos ) +{ + if ( !bHasEmptyAttribs ) + return 0; + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nPos ) ) + { + if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + nAttr++; + pAttr = GetAttrib( aAttribs, nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindFeature( USHORT nPos ) const +{ + + USHORT nAttr = 0; + EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr ); + + // erstmal zur gewuenschten Position... + while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + // jetzt das Feature suchen... + while ( pNextAttrib && !pNextAttrib->IsFeature() ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + return pNextAttrib; +} + + +void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool ) +{ + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->IsEmpty() ) + { + rItemPool.Remove( *pAttr->GetItem() ); + aAttribs.Remove( nAttr ); + delete pAttr; + nAttr--; + } + } + bHasEmptyAttribs = FALSE; +} + +BOOL CharAttribList::DbgCheckAttribs() +{ +#ifdef DBG_UTIL + BOOL bOK = TRUE; + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->GetStart() > pAttr->GetEnd() ) + { + bOK = FALSE; + DBG_ERROR( "Attr verdreht" ); + } + else if ( pAttr->IsFeature() && ( pAttr->GetLen() != 1 ) ) + { + bOK = FALSE; + DBG_ERROR( "Feature, Len != 1" ); + } + } + return bOK; +#else + return TRUE; +#endif +} + + + +SvxFontTable::SvxFontTable() +{ +} + +SvxFontTable::~SvxFontTable() +{ + SvxFontItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxFontTable::GetId( const SvxFontItem& rFontItem ) +{ + SvxFontItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rFontItem ) + return GetCurKey(); + pItem = Next(); + } + DBG_WARNING( "Font nicht gefunden: GetId()" ); + return 0; +} + +SvxColorList::SvxColorList() +{ +} + +SvxColorList::~SvxColorList() +{ + SvxColorItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxColorList::GetId( const SvxColorItem& rColorItem ) +{ + SvxColorItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rColorItem ) + return GetCurPos(); + pItem = Next(); + } + DBG_WARNING( "Color nicht gefunden: GetId()" ); + return 0; +} + +EditEngineItemPool::EditEngineItemPool( BOOL bPersistenRefCounts ) + : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END, + aItemInfos, 0, bPersistenRefCounts ) +{ + SetVersionMap( 1, 3999, 4015, aV1Map ); + SetVersionMap( 2, 3999, 4019, aV2Map ); + SetVersionMap( 3, 3997, 4020, aV3Map ); + SetVersionMap( 4, 3994, 4022, aV4Map ); + SetVersionMap( 5, 3994, 4037, aV5Map ); + + DBG_ASSERT( EE_DLL(), "EditDLL?!" ); + SfxPoolItem** ppDefItems = EE_DLL()->GetGlobalData()->GetDefItems(); + SetDefaults( ppDefItems ); +} + +EditEngineItemPool::~EditEngineItemPool() +{ +} + +SvStream& EditEngineItemPool::Store( SvStream& rStream ) const +{ + // Bei einem 3.1-Export muess ein Hack eingebaut werden, da BUG im + // SfxItemSet::Load, aber nicht nachtraeglich in 3.1 fixbar. + + // Der eingestellte Range muss nach Store erhalten bleiben, weil dann + // erst die ItemSets gespeichert werden... + + long nVersion = rStream.GetVersion(); + BOOL b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) ) + ? TRUE : FALSE; + + EditEngineItemPool* pThis = (EditEngineItemPool*)this; + if ( b31Format ) + pThis->SetStoringRange( 3997, 4022 ); + else + pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END ); + + return SfxItemPool::Store( rStream ); +} diff --git a/editeng/source/editeng/editdoc.hxx b/editeng/source/editeng/editdoc.hxx new file mode 100644 index 000000000000..bf2e3d01852b --- /dev/null +++ b/editeng/source/editeng/editdoc.hxx @@ -0,0 +1,802 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITDOC_HXX +#define _EDITDOC_HXX + +#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_ +#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp> +#endif + +#include <editattr.hxx> +#include <edtspell.hxx> +#include <editeng/svxfont.hxx> +#include <svl/itemset.hxx> +#include <svl/style.hxx> +#include <svl/itempool.hxx> +#include <tools/table.hxx> + +class ImpEditEngine; +class SvxTabStop; +class SvtCTLOptions; + +DBG_NAMEEX( EE_TextPortion ) + +#define CHARPOSGROW 16 +#define DEFTAB 720 + +void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent = true, short nScriptType = 0 ); +USHORT GetScriptItemId( USHORT nItemId, short nScriptType ); +BOOL IsScriptItemValid( USHORT nItemId, short nScriptType ); + +EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE ); + +class ContentNode; +class EditDoc; + +struct EPaM +{ + USHORT nPara; + USHORT nIndex; + + EPaM() { nPara = 0; nIndex = 0; } + EPaM( USHORT nP, USHORT nI ) { nPara = nP; nIndex = nI; } + EPaM( const EPaM& r) { nPara = r.nPara; nIndex = r.nIndex; } + EPaM& operator = ( const EPaM& r ) { nPara = r.nPara; nIndex = r.nIndex; return *this; } + inline BOOL operator == ( const EPaM& r ) const; + inline BOOL operator < ( const EPaM& r ) const; +}; + +inline BOOL EPaM::operator < ( const EPaM& r ) const +{ + return ( ( nPara < r.nPara ) || + ( ( nPara == r.nPara ) && nIndex < r.nIndex ) ) ? TRUE : FALSE; +} + +inline BOOL EPaM::operator == ( const EPaM& r ) const +{ + return ( ( nPara == r.nPara ) && ( nIndex == r.nIndex ) ) ? TRUE : FALSE; +} + +struct ScriptTypePosInfo +{ + short nScriptType; + USHORT nStartPos; + USHORT nEndPos; + + ScriptTypePosInfo( short _Type, USHORT _Start, USHORT _End ) + { + nScriptType = _Type; + nStartPos = _Start; + nEndPos = _End; + } +}; + +SV_DECL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo, 0, 4 ) + +struct WritingDirectionInfo +{ + BYTE nType; + USHORT nStartPos; + USHORT nEndPos; + + WritingDirectionInfo( BYTE _Type, USHORT _Start, USHORT _End ) + { + nType = _Type; + nStartPos = _Start; + nEndPos = _End; + } +}; + +SV_DECL_VARARR( WritingDirectionInfos, WritingDirectionInfo, 0, 4 ) + +typedef EditCharAttrib* EditCharAttribPtr; +SV_DECL_PTRARR( CharAttribArray, EditCharAttribPtr, 0, 4 ) + +class ContentAttribsInfo +{ +private: + SfxItemSet aPrevParaAttribs; + CharAttribArray aPrevCharAttribs; + +public: + ContentAttribsInfo( const SfxItemSet& rParaAttribs ); + + const SfxItemSet& GetPrevParaAttribs() const { return aPrevParaAttribs; } + const CharAttribArray& GetPrevCharAttribs() const { return aPrevCharAttribs; } + + CharAttribArray& GetPrevCharAttribs() { return aPrevCharAttribs; } +}; + +typedef ContentAttribsInfo* ContentAttribsInfoPtr; +SV_DECL_PTRARR( ContentInfoArray, ContentAttribsInfoPtr, 1, 1 ) + +// ---------------------------------------------------------------------- +// class SvxFontTable +// ---------------------------------------------------------------------- +DECLARE_TABLE( DummyFontTable, SvxFontItem* ) +class SvxFontTable : public DummyFontTable +{ +public: + SvxFontTable(); + ~SvxFontTable(); + + ULONG GetId( const SvxFontItem& rFont ); +}; + +// ---------------------------------------------------------------------- +// class SvxColorList +// ---------------------------------------------------------------------- +typedef ContentNode* ContentNodePtr; +DECLARE_LIST( DummyColorList, SvxColorItem* ) +class SvxColorList : public DummyColorList +{ +public: + SvxColorList(); + ~SvxColorList(); + + ULONG GetId( const SvxColorItem& rColor ); +}; + +// ---------------------------------------------------------------------- +// class ItemList +// ---------------------------------------------------------------------- +typedef const SfxPoolItem* ConstPoolItemPtr; +DECLARE_LIST( DummyItemList, ConstPoolItemPtr ) +class ItemList : public DummyItemList +{ +public: + const SfxPoolItem* FindAttrib( USHORT nWhich ); +}; + +// ------------------------------------------------------------------------- +// class ContentAttribs +// ------------------------------------------------------------------------- +class ContentAttribs +{ +private: + SfxStyleSheet* pStyle; + SfxItemSet aAttribSet; + +public: + ContentAttribs( SfxItemPool& rItemPool ); + ContentAttribs( const ContentAttribs& ); + ~ContentAttribs(); // erst bei umfangreicheren Tabs + + SvxTabStop FindTabStop( long nCurPos, USHORT nDefTab ); + SfxItemSet& GetItems() { return aAttribSet; } + SfxStyleSheet* GetStyleSheet() const { return pStyle; } + void SetStyleSheet( SfxStyleSheet* pS ); + + const SfxPoolItem& GetItem( USHORT nWhich ); + BOOL HasItem( USHORT nWhich ); +}; + +// ------------------------------------------------------------------------- +// class CharAttribList +// ------------------------------------------------------------------------- +class CharAttribList +{ +private: + CharAttribArray aAttribs; + SvxFont aDefFont; // schneller, als jedesmal vom Pool! + BOOL bHasEmptyAttribs; + + CharAttribList( const CharAttribList& ) {;} + +public: + CharAttribList(); + ~CharAttribList(); + + void DeleteEmptyAttribs( SfxItemPool& rItemPool ); + void RemoveItemsFromPool( SfxItemPool* pItemPool ); + + EditCharAttrib* FindAttrib( USHORT nWhich, USHORT nPos ); + EditCharAttrib* FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const; + EditCharAttrib* FindEmptyAttrib( USHORT nWhich, USHORT nPos ); + EditCharAttrib* FindFeature( USHORT nPos ) const; + + + void ResortAttribs(); + void OptimizeRanges( SfxItemPool& rItemPool ); + + USHORT Count() { return aAttribs.Count(); } + void Clear() { aAttribs.Remove( 0, aAttribs.Count()); } + void InsertAttrib( EditCharAttrib* pAttrib ); + + SvxFont& GetDefFont() { return aDefFont; } + + BOOL HasEmptyAttribs() const { return bHasEmptyAttribs; } + BOOL& HasEmptyAttribs() { return bHasEmptyAttribs; } + BOOL HasBoundingAttrib( USHORT nBound ); + BOOL HasAttrib( USHORT nWhich ) const; + BOOL HasAttrib( USHORT nStartPos, USHORT nEndPos ) const; + + CharAttribArray& GetAttribs() { return aAttribs; } + const CharAttribArray& GetAttribs() const { return aAttribs; } + + // Debug: + BOOL DbgCheckAttribs(); +}; + +// ------------------------------------------------------------------------- +// class ContentNode +// ------------------------------------------------------------------------- +class ContentNode : public XubString +{ +private: + ContentAttribs aContentAttribs; + CharAttribList aCharAttribList; + WrongList* pWrongList; + +public: + ContentNode( SfxItemPool& rItemPool ); + ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ); + ~ContentNode(); + + ContentAttribs& GetContentAttribs() { return aContentAttribs; } + CharAttribList& GetCharAttribs() { return aCharAttribList; } + + void ExpandAttribs( USHORT nIndex, USHORT nNewChars, SfxItemPool& rItemPool ); + void CollapsAttribs( USHORT nIndex, USHORT nDelChars, SfxItemPool& rItemPool ); + void AppendAttribs( ContentNode* pNextNode ); + void CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs ); + + void SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont = TRUE ); + void SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ); + SfxStyleSheet* GetStyleSheet() { return aContentAttribs.GetStyleSheet(); } + + void CreateDefFont(); + + WrongList* GetWrongList() { return pWrongList; } + void SetWrongList( WrongList* p ); + + void CreateWrongList(); + void DestroyWrongList(); + + BOOL IsFeature( USHORT nPos ) const { return ( GetChar( nPos ) == CH_FEATURE ); } +}; + +typedef ContentNode* ContentNodePtr; +SV_DECL_PTRARR( DummyContentList, ContentNodePtr, 0, 4 ) + +class ContentList : public DummyContentList +{ + USHORT nLastCache; +public: + ContentList() : DummyContentList( 0, 4 ), nLastCache(0) {} + USHORT GetPos( const ContentNodePtr &rPtr ) const; +}; + +// ------------------------------------------------------------------------- +// class EditPaM +// ------------------------------------------------------------------------- +class EditPaM +{ +private: + ContentNode* pNode; + USHORT nIndex; + +public: + EditPaM() { pNode = NULL; nIndex = 0; } + EditPaM( ContentNode* p, USHORT n ) { pNode = p; nIndex = n; } + + ContentNode* GetNode() const { return pNode; } + void SetNode( ContentNode* p) { pNode = p; } + + USHORT GetIndex() const { return nIndex; } + USHORT& GetIndex() { return nIndex; } + void SetIndex( USHORT n ) { nIndex = n; } + + BOOL IsParaStart() const { return nIndex == 0; } + BOOL IsParaEnd() const { return nIndex == pNode->Len(); } + + BOOL DbgIsBuggy( EditDoc& rDoc ); + + EditPaM& operator = ( const EditPaM& rPaM ); + friend BOOL operator == ( const EditPaM& r1, const EditPaM& r2 ); + friend BOOL operator != ( const EditPaM& r1, const EditPaM& r2 ); +}; + +#define PORTIONKIND_TEXT 0 +#define PORTIONKIND_TAB 1 +#define PORTIONKIND_LINEBREAK 2 +#define PORTIONKIND_FIELD 3 +#define PORTIONKIND_HYPHENATOR 4 +// #define PORTIONKIND_EXTRASPACE 5 + +#define DELMODE_SIMPLE 0 +#define DELMODE_RESTOFWORD 1 +#define DELMODE_RESTOFCONTENT 2 + +#define CHAR_NORMAL 0x00 +#define CHAR_KANA 0x01 +#define CHAR_PUNCTUATIONLEFT 0x02 +#define CHAR_PUNCTUATIONRIGHT 0x04 + +// ------------------------------------------------------------------------- +// struct ExtraPortionInfos +// ------------------------------------------------------------------------- +struct ExtraPortionInfo +{ + long nOrgWidth; + long nWidthFullCompression; + + long nPortionOffsetX; + + USHORT nMaxCompression100thPercent; + + BYTE nAsianCompressionTypes; + BOOL bFirstCharIsRightPunktuation; + BOOL bCompressed; + + sal_Int32* pOrgDXArray; + + + ExtraPortionInfo(); + ~ExtraPortionInfo(); + + void SaveOrgDXArray( const sal_Int32* pDXArray, USHORT nLen ); + void DestroyOrgDXArray(); +}; + + +// ------------------------------------------------------------------------- +// class TextPortion +// ------------------------------------------------------------------------- +class TextPortion +{ +private: + ExtraPortionInfo* pExtraInfos; + USHORT nLen; + Size aOutSz; + BYTE nKind; + BYTE nRightToLeft; + sal_Unicode nExtraValue; + + + TextPortion() { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = 0; nKind = PORTIONKIND_TEXT; nExtraValue = 0; nRightToLeft = FALSE;} + +public: + TextPortion( USHORT nL ) : aOutSz( -1, -1 ) + { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = nL; nKind = PORTIONKIND_TEXT; nExtraValue = 0; nRightToLeft = FALSE;} + TextPortion( const TextPortion& r ) : aOutSz( r.aOutSz ) + { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = r.nLen; nKind = r.nKind; nExtraValue = r.nExtraValue; nRightToLeft = r.nRightToLeft; } + + ~TextPortion() { DBG_DTOR( EE_TextPortion, 0 ); delete pExtraInfos; } + + USHORT GetLen() const { return nLen; } + USHORT& GetLen() { return nLen; } + void SetLen( USHORT nL ) { nLen = nL; } + + Size& GetSize() { return aOutSz; } + Size GetSize() const { return aOutSz; } + + BYTE& GetKind() { return nKind; } + BYTE GetKind() const { return nKind; } + + void SetRightToLeft( BYTE b ) { nRightToLeft = b; } + BYTE GetRightToLeft() const { return nRightToLeft; } + BOOL IsRightToLeft() const { return (nRightToLeft&1); } + + sal_Unicode GetExtraValue() const { return nExtraValue; } + void SetExtraValue( sal_Unicode n ) { nExtraValue = n; } + + BOOL HasValidSize() const { return aOutSz.Width() != (-1); } + + ExtraPortionInfo* GetExtraInfos() const { return pExtraInfos; } + void SetExtraInfos( ExtraPortionInfo* p ) { delete pExtraInfos; pExtraInfos = p; } +}; + +// ------------------------------------------------------------------------- +// class TextPortionList +// ------------------------------------------------------------------------- +typedef TextPortion* TextPortionPtr; +SV_DECL_PTRARR( TextPortionArray, TextPortionPtr, 0, 8 ) + +class TextPortionList : public TextPortionArray +{ +public: + TextPortionList(); + ~TextPortionList(); + + void Reset(); + USHORT FindPortion( USHORT nCharPos, USHORT& rPortionStart, BOOL bPreferStartingPortion = FALSE ); + USHORT GetStartPos( USHORT nPortion ); + void DeleteFromPortion( USHORT nDelFrom ); +}; + +class ParaPortion; + +SV_DECL_VARARR( CharPosArray, sal_Int32, 0, CHARPOSGROW ) + +// ------------------------------------------------------------------------ +// class EditLine +// ------------------------------------------------------------------------- +class EditLine +{ +private: + CharPosArray aPositions; + long nTxtWidth; + USHORT nStartPosX; + USHORT nStart; // koennte durch nStartPortion ersetzt werden + USHORT nEnd; // koennte durch nEndPortion ersetzt werden + USHORT nStartPortion; + USHORT nEndPortion; + USHORT nHeight; // Gesamthoehe der Zeile + USHORT nTxtHeight; // Reine Texthoehe + USHORT nCrsrHeight; // Bei Konturfluss hohe Zeilen => Cursor zu groá. + USHORT nMaxAscent; + BOOL bHangingPunctuation; + BOOL bInvalid; // fuer geschickte Formatierung + +public: + EditLine(); + EditLine( const EditLine& ); + ~EditLine(); + + BOOL IsIn( USHORT nIndex ) const + { return ( (nIndex >= nStart ) && ( nIndex < nEnd ) ); } + + BOOL IsIn( USHORT nIndex, BOOL bInclEnd ) const + { return ( ( nIndex >= nStart ) && ( bInclEnd ? ( nIndex <= nEnd ) : ( nIndex < nEnd ) ) ); } + + void SetStart( USHORT n ) { nStart = n; } + USHORT GetStart() const { return nStart; } + USHORT& GetStart() { return nStart; } + + void SetEnd( USHORT n ) { nEnd = n; } + USHORT GetEnd() const { return nEnd; } + USHORT& GetEnd() { return nEnd; } + + void SetStartPortion( USHORT n ) { nStartPortion = n; } + USHORT GetStartPortion() const { return nStartPortion; } + USHORT& GetStartPortion() { return nStartPortion; } + + void SetEndPortion( USHORT n ) { nEndPortion = n; } + USHORT GetEndPortion() const { return nEndPortion; } + USHORT& GetEndPortion() { return nEndPortion; } + + void SetHeight( USHORT nH, USHORT nTxtH = 0, USHORT nCrsrH = 0 ) + { nHeight = nH; + nTxtHeight = ( nTxtH ? nTxtH : nH ); + nCrsrHeight = ( nCrsrH ? nCrsrH : nTxtHeight ); + } + USHORT GetHeight() const { return nHeight; } + USHORT GetTxtHeight() const { return nTxtHeight; } + USHORT GetCrsrHeight() const { return nCrsrHeight; } + + void SetTextWidth( long n ) { nTxtWidth = n; } + long GetTextWidth() const { return nTxtWidth; } + + void SetMaxAscent( USHORT n ) { nMaxAscent = n; } + USHORT GetMaxAscent() const { return nMaxAscent; } + + void SetHangingPunctuation( BOOL b ) { bHangingPunctuation = b; } + BOOL IsHangingPunctuation() const { return bHangingPunctuation; } + + USHORT GetLen() const { return nEnd - nStart; } + + USHORT GetStartPosX() const { return nStartPosX; } + void SetStartPosX( USHORT start ) { nStartPosX = start; } + + Size CalcTextSize( ParaPortion& rParaPortion ); + + BOOL IsInvalid() const { return bInvalid; } + BOOL IsValid() const { return !bInvalid; } + void SetInvalid() { bInvalid = TRUE; } + void SetValid() { bInvalid = FALSE; } + + BOOL IsEmpty() const { return (nEnd > nStart) ? FALSE : TRUE; } + + CharPosArray& GetCharPosArray() { return aPositions; } + + EditLine* Clone() const; + + EditLine& operator = ( const EditLine& rLine ); + friend BOOL operator == ( const EditLine& r1, const EditLine& r2 ); + friend BOOL operator != ( const EditLine& r1, const EditLine& r2 ); +}; + + +// ------------------------------------------------------------------------- +// class LineList +// ------------------------------------------------------------------------- +typedef EditLine* EditLinePtr; +SV_DECL_PTRARR( LineArray, EditLinePtr, 0, 4 ) + +class EditLineList : public LineArray +{ +public: + EditLineList(); + ~EditLineList(); + + void Reset(); + void DeleteFromLine( USHORT nDelFrom ); + USHORT FindLine( USHORT nChar, BOOL bInclEnd ); +}; + +// ------------------------------------------------------------------------- +// class ParaPortion +// ------------------------------------------------------------------------- +class ParaPortion +{ + friend class ImpEditEngine; // zum Einstellen der Hoehe +private: + EditLineList aLineList; + TextPortionList aTextPortionList; + ContentNode* pNode; + long nHeight; + + ScriptTypePosInfos aScriptInfos; + WritingDirectionInfos aWritingDirectionInfos; + + USHORT nInvalidPosStart; + USHORT nFirstLineOffset; // Fuer Writer-LineSpacing-Interpretation + USHORT nBulletX; + short nInvalidDiff; + + BOOL bInvalid : 1; + BOOL bSimple : 1; // nur lineares Tippen + BOOL bVisible : 1; // MT 05/00: Gehoert an den Node!!! + BOOL bForceRepaint : 1; + + ParaPortion( const ParaPortion& ); + +public: + ParaPortion( ContentNode* pNode ); + ~ParaPortion(); + + USHORT GetLineNumber( USHORT nIndex ); + + EditLineList& GetLines() { return aLineList; } + + BOOL IsInvalid() const { return bInvalid; } + BOOL IsSimpleInvalid() const { return bSimple; } + void SetValid() { bInvalid = FALSE; bSimple = TRUE;} + + BOOL MustRepaint() const { return bForceRepaint; } + void SetMustRepaint( BOOL bRP ) { bForceRepaint = bRP; } + + USHORT GetBulletX() const { return nBulletX; } + void SetBulletX( USHORT n ) { nBulletX = n; } + + void MarkInvalid( USHORT nStart, short nDiff); + void MarkSelectionInvalid( USHORT nStart, USHORT nEnd ); + + void SetVisible( BOOL bVisible ); + BOOL IsVisible() { return bVisible; } + + long GetHeight() const { return ( bVisible ? nHeight : 0 ); } + USHORT GetFirstLineOffset() const { return ( bVisible ? nFirstLineOffset : 0 ); } + void ResetHeight() { nHeight = 0; nFirstLineOffset = 0; } + + ContentNode* GetNode() const { return pNode; } + TextPortionList& GetTextPortions() { return aTextPortionList; } + + USHORT GetInvalidPosStart() const { return nInvalidPosStart; } + short GetInvalidDiff() const { return nInvalidDiff; } + + void CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine ); + + BOOL DbgCheckTextPortions(); +}; + +typedef ParaPortion* ParaPortionPtr; +SV_DECL_PTRARR( DummyParaPortionList, ParaPortionPtr, 0, 4 ) + +// ------------------------------------------------------------------------- +// class ParaPortionList +// ------------------------------------------------------------------------- +class ParaPortionList : public DummyParaPortionList +{ + USHORT nLastCache; +public: + ParaPortionList(); + ~ParaPortionList(); + + void Reset(); + long GetYOffset( ParaPortion* pPPortion ); + USHORT FindParagraph( long nYOffset ); + + inline ParaPortion* SaveGetObject( USHORT nPos ) const + { return ( nPos < Count() ) ? GetObject( nPos ) : 0; } + + USHORT GetPos( const ParaPortionPtr &rPtr ) const; + + // temporaer: + void DbgCheck( EditDoc& rDoc ); +}; + +// ------------------------------------------------------------------------- +// class EditSelection +// ------------------------------------------------------------------------- +class EditSelection +{ +private: + EditPaM aStartPaM; + EditPaM aEndPaM; + +public: + EditSelection(); // kein CCTOR und DTOR, geht autom. richtig! + EditSelection( const EditPaM& rStartAndAnd ); + EditSelection( const EditPaM& rStart, const EditPaM& rEnd ); + + EditPaM& Min() { return aStartPaM; } + EditPaM& Max() { return aEndPaM; } + + const EditPaM& Min() const { return aStartPaM; } + const EditPaM& Max() const { return aEndPaM; } + + BOOL HasRange() const { return aStartPaM != aEndPaM; } + BOOL IsInvalid() const; + BOOL DbgIsBuggy( EditDoc& rDoc ); + + BOOL Adjust( const ContentList& rNodes ); + + EditSelection& operator = ( const EditPaM& r ); + BOOL operator == ( const EditSelection& r ) const + { return ( ( aStartPaM == r.aStartPaM ) && ( aEndPaM == r.aEndPaM ) ) + ? TRUE : FALSE; } + BOOL operator != ( const EditSelection& r ) const { return !( r == *this ); } +}; + +// ------------------------------------------------------------------------- +// class DeletedNodeInfo +// ------------------------------------------------------------------------- +class DeletedNodeInfo +{ +private: + ULONG nInvalidAdressPtr; + USHORT nInvalidParagraph; + +public: + DeletedNodeInfo( ULONG nInvAdr, USHORT nPos ) + { nInvalidAdressPtr = nInvAdr; + nInvalidParagraph = nPos; } + + ULONG GetInvalidAdress() { return nInvalidAdressPtr; } + USHORT GetPosition() { return nInvalidParagraph; } +}; + +typedef DeletedNodeInfo* DeletedNodeInfoPtr; +SV_DECL_PTRARR( DeletedNodesList, DeletedNodeInfoPtr, 0, 4 ) + +// ------------------------------------------------------------------------- +// class EditDoc +// ------------------------------------------------------------------------- +class EditDoc : public ContentList +{ +private: + SfxItemPool* pItemPool; + Link aModifyHdl; + + SvxFont aDefFont; //schneller, als jedesmal vom Pool! + USHORT nDefTab; + BOOL bIsVertical; + BOOL bIsFixedCellHeight; + + BOOL bOwnerOfPool; + BOOL bModified; + +protected: + void ImplDestroyContents(); + +public: + EditDoc( SfxItemPool* pItemPool ); + ~EditDoc(); + + BOOL IsModified() const { return bModified; } + void SetModified( BOOL b ); + + void SetModifyHdl( const Link& rLink ) { aModifyHdl = rLink; } + Link GetModifyHdl() const { return aModifyHdl; } + + void CreateDefFont( BOOL bUseStyles ); + const SvxFont& GetDefFont() { return aDefFont; } + + void SetDefTab( USHORT nTab ) { nDefTab = nTab ? nTab : DEFTAB; } + USHORT GetDefTab() const { return nDefTab; } + + void SetVertical( BOOL bVertical ) { bIsVertical = bVertical; } + BOOL IsVertical() const { return bIsVertical; } + + void SetFixedCellHeight( BOOL bUseFixedCellHeight ) { bIsFixedCellHeight = bUseFixedCellHeight; } + BOOL IsFixedCellHeight() const { return bIsFixedCellHeight; } + + EditPaM Clear(); + EditPaM RemoveText(); + EditPaM RemoveChars( EditPaM aPaM, USHORT nChars ); + void InsertText( const EditPaM& rPaM, xub_Unicode c ); + EditPaM InsertText( EditPaM aPaM, const XubString& rStr ); + EditPaM InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs ); + EditPaM InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem ); + EditPaM ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ); + + String GetText( LineEnd eEnd ) const; + ULONG GetTextLen() const; + + XubString GetParaAsString( USHORT nNode ) const; + XubString GetParaAsString( ContentNode* pNode, USHORT nStartPos = 0, USHORT nEndPos = 0xFFFF, BOOL bResolveFields = TRUE ) const; + + inline EditPaM GetStartPaM() const; + inline EditPaM GetEndPaM() const; + + SfxItemPool& GetItemPool() { return *pItemPool; } + const SfxItemPool& GetItemPool() const { return *pItemPool; } + + void RemoveItemsFromPool( ContentNode* pNode ); + + void InsertAttrib( const SfxPoolItem& rItem, ContentNode* pNode, USHORT nStart, USHORT nEnd ); + void InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ); + void InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ); + BOOL RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich = 0 ); + BOOL RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich = 0 ); + void FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet ); + + USHORT GetPos( ContentNode* pNode ) const { return ContentList::GetPos(pNode); } + ContentNode* SaveGetObject( USHORT nPos ) const { return ( nPos < Count() ) ? GetObject( nPos ) : 0; } + + static XubString GetSepStr( LineEnd eEnd ); +}; + +inline EditPaM EditDoc::GetStartPaM() const +{ + return EditPaM( GetObject( 0 ), 0 ); +} + +inline EditPaM EditDoc::GetEndPaM() const +{ + ContentNode* pLastNode = GetObject( Count()-1 ); + return EditPaM( pLastNode, pLastNode->Len() ); +} + +inline EditCharAttrib* GetAttrib( const CharAttribArray& rAttribs, USHORT nAttr ) +{ + return ( nAttr < rAttribs.Count() ) ? rAttribs[nAttr] : 0; +} + +BOOL CheckOrderedList( CharAttribArray& rAttribs, BOOL bStart ); + +// ------------------------------------------------------------------------- +// class EditEngineItemPool +// ------------------------------------------------------------------------- +class EditEngineItemPool : public SfxItemPool +{ +public: + EditEngineItemPool( BOOL bPersistenRefCounts ); +protected: + virtual ~EditEngineItemPool(); +public: + + virtual SvStream& Store( SvStream& rStream ) const; +}; + +#endif // _EDITDOC_HXX diff --git a/editeng/source/editeng/editdoc2.cxx b/editeng/source/editeng/editdoc2.cxx new file mode 100644 index 000000000000..b2a83ffd6274 --- /dev/null +++ b/editeng/source/editeng/editdoc2.cxx @@ -0,0 +1,544 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <svl/smplhint.hxx> + +#include <tools/rtti.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> + +#include <editdoc.hxx> +#include <impedit.hxx> +#include <editdbg.hxx> + +#include <editeng/numitem.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/charscaleitem.hxx> + +#include <vcl/svapp.hxx> // Fuer AppWindow... + +DBG_NAME( EE_ParaPortion ) + +SV_IMPL_VARARR( CharPosArray, sal_Int32 ); + +/* + +BOOL EditStyleSheet::HasStyleAsAnyParent( SfxStyleSheet& rStyle ) +{ + if ( GetParent() == rStyle.GetName() ) + return TRUE; + + if ( GetParent().Len() && ( GetParent() != GetName() ) ) + { + EditStyleSheet* pS = (EditStyleSheet*)GetPool().Find( GetParent(), rStyle.GetFamily() ); + if ( pS ) + return pS->HasStyleAsAnyParent( rStyle ); + } + return FALSE; +} + +*/ + +// ------------------------------------------------------------------------- +// class TextPortionList +// ------------------------------------------------------------------------- +TextPortionList::TextPortionList() +{ +} + +TextPortionList::~TextPortionList() +{ + Reset(); +} + +void TextPortionList::Reset() +{ + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + delete GetObject( nPortion ); + Remove( 0, Count() ); +} + +void TextPortionList::DeleteFromPortion( USHORT nDelFrom ) +{ + DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" ); + for ( USHORT nP = nDelFrom; nP < Count(); nP++ ) + delete GetObject( nP ); + Remove( nDelFrom, Count()-nDelFrom ); +} + +USHORT TextPortionList::FindPortion( USHORT nCharPos, USHORT& nPortionStart, BOOL bPreferStartingPortion ) +{ + // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden + USHORT nTmpPos = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + TextPortion* pPortion = GetObject( nPortion ); + nTmpPos = nTmpPos + pPortion->GetLen(); + if ( nTmpPos >= nCharPos ) + { + // take this one if we don't prefer the starting portion, or if it's the last one + if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) ) + { + nPortionStart = nTmpPos - pPortion->GetLen(); + return nPortion; + } + } + } + DBG_ERROR( "FindPortion: Nicht gefunden!" ); + return ( Count() - 1 ); +} + +USHORT TextPortionList::GetStartPos( USHORT nPortion ) +{ + USHORT nPos = 0; + for ( USHORT n = 0; n < nPortion; n++ ) + { + TextPortion* pPortion = GetObject( n ); + nPos = nPos + pPortion->GetLen(); + } + return nPos; +} + + +// ------------------------------------------------------------------------- +// class ExtraPortionInfo +// ------------------------------------------------------------------------- + +ExtraPortionInfo::ExtraPortionInfo() +{ + nOrgWidth = 0; + nWidthFullCompression = 0; + nMaxCompression100thPercent = 0; + nAsianCompressionTypes = 0; + nPortionOffsetX = 0; + bFirstCharIsRightPunktuation = FALSE; + bCompressed = FALSE; + pOrgDXArray = NULL; +} + +ExtraPortionInfo::~ExtraPortionInfo() +{ + delete[] pOrgDXArray; +} + +void ExtraPortionInfo::SaveOrgDXArray( const sal_Int32* pDXArray, USHORT nLen ) +{ + delete[] pOrgDXArray; + pOrgDXArray = new sal_Int32[nLen]; + memcpy( pOrgDXArray, pDXArray, nLen*sizeof(sal_Int32) ); +} + +void ExtraPortionInfo::DestroyOrgDXArray() +{ + delete[] pOrgDXArray; + pOrgDXArray = NULL; +} + + +// ------------------------------------------------------------------------- +// class ParaPortion +// ------------------------------------------------------------------------- +ParaPortion::ParaPortion( ContentNode* pN ) +{ + DBG_CTOR( EE_ParaPortion, 0 ); + + pNode = pN; + bInvalid = TRUE; + bVisible = TRUE; + bSimple = FALSE; + bForceRepaint = FALSE; + nInvalidPosStart = 0; + nInvalidDiff = 0; + nHeight = 0; + nFirstLineOffset = 0; + nBulletX = 0; +} + +ParaPortion::~ParaPortion() +{ + DBG_DTOR( EE_ParaPortion, 0 ); +} + +void ParaPortion::MarkInvalid( USHORT nStart, short nDiff ) +{ + if ( bInvalid == FALSE ) + { +// nInvalidPosEnd = nStart; // ??? => CreateLines + nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff ); + nInvalidDiff = nDiff; + } + else + { + // Einfaches hintereinander tippen + if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) && + ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) ) + { + nInvalidDiff = nInvalidDiff + nDiff; + } + // Einfaches hintereinander loeschen + else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) ) + { + nInvalidPosStart = nInvalidPosStart + nDiff; + nInvalidDiff = nInvalidDiff + nDiff; + } + else + { +// nInvalidPosEnd = pNode->Len(); + DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" ); + nInvalidPosStart = Min( nInvalidPosStart, (USHORT) ( nDiff < 0 ? nStart+nDiff : nDiff ) ); + nInvalidDiff = 0; + bSimple = FALSE; + } + } + bInvalid = TRUE; + aScriptInfos.Remove( 0, aScriptInfos.Count() ); + aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() ); +// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() ); +} + +void ParaPortion::MarkSelectionInvalid( USHORT nStart, USHORT /* nEnd */ ) +{ + if ( bInvalid == FALSE ) + { + nInvalidPosStart = nStart; +// nInvalidPosEnd = nEnd; + } + else + { + nInvalidPosStart = Min( nInvalidPosStart, nStart ); +// nInvalidPosEnd = pNode->Len(); + } + nInvalidDiff = 0; + bInvalid = TRUE; + bSimple = FALSE; + aScriptInfos.Remove( 0, aScriptInfos.Count() ); + aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() ); +// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() ); +} + +USHORT ParaPortion::GetLineNumber( USHORT nIndex ) +{ + DBG_ASSERTWARNING( aLineList.Count(), "Leere ParaPortion in GetLine!" ); + DBG_ASSERT( bVisible, "Wozu GetLine() bei einem unsichtbaren Absatz?" ); + + for ( USHORT nLine = 0; nLine < aLineList.Count(); nLine++ ) + { + if ( aLineList[nLine]->IsIn( nIndex ) ) + return nLine; + } + + // Dann sollte es am Ende der letzten Zeile sein! + DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index voll daneben!" ); + return (aLineList.Count()-1); +} + +void ParaPortion::SetVisible( BOOL bMakeVisible ) +{ + bVisible = bMakeVisible; +} + +void ParaPortion::CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine ) +{ + USHORT nLines = aLineList.Count(); + DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" ); + if ( nLastFormattedLine < ( nLines - 1 ) ) + { + const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ]; + const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ]; + short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion(); + short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd(); + nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen! + + // Die erste unformatierte muss genau eine Portion hinter der letzten der + // formatierten beginnen: + // Wenn in der geaenderten Zeile eine Portion gesplittet wurde, + // kann nLastEnd > nNextStart sein! + int nPDiff = -( nPortionDiff-1 ); + int nTDiff = -( nTextDiff-1 ); + if ( nPDiff || nTDiff ) + { + for ( USHORT nL = nLastFormattedLine+1; nL < nLines; nL++ ) + { + EditLine* pLine = aLineList[ nL ]; + + pLine->GetStartPortion() = sal::static_int_cast< USHORT >( + pLine->GetStartPortion() + nPDiff); + pLine->GetEndPortion() = sal::static_int_cast< USHORT >( + pLine->GetEndPortion() + nPDiff); + + pLine->GetStart() = sal::static_int_cast< USHORT >( + pLine->GetStart() + nTDiff); + pLine->GetEnd() = sal::static_int_cast< USHORT >( + pLine->GetEnd() + nTDiff); + + pLine->SetValid(); + } + } + } + DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: Ende stimmt nicht!" ); +} + +// Shared reverse lookup acceleration pieces ... + +static USHORT FastGetPos( const VoidPtr *pPtrArray, USHORT nPtrArrayLen, + VoidPtr pPtr, USHORT &rLastPos ) +{ + // Through certain filter code-paths we do a lot of appends, which in + // turn call GetPos - creating some N^2 nightmares. If we have a + // non-trivially large list, do a few checks from the end first. + if( rLastPos > 16 ) + { + USHORT nEnd; + if (rLastPos > nPtrArrayLen - 2) + nEnd = nPtrArrayLen; + else + nEnd = rLastPos + 2; + + for( USHORT nIdx = rLastPos - 2; nIdx < nEnd; nIdx++ ) + { + if( pPtrArray[ nIdx ] == pPtr ) + { + rLastPos = nIdx; + return nIdx; + } + } + } + // The world's lamest linear search from svarray ... + for( USHORT nIdx = 0; nIdx < nPtrArrayLen; nIdx++ ) + if (pPtrArray[ nIdx ] == pPtr ) + return rLastPos = nIdx; + return USHRT_MAX; +} + +// ------------------------------------------------------------------------- +// class ParaPortionList +// ------------------------------------------------------------------------- +ParaPortionList::ParaPortionList() : nLastCache( 0 ) +{ +} + +ParaPortionList::~ParaPortionList() +{ + Reset(); +} + +USHORT ParaPortionList::GetPos( const ParaPortionPtr &rPtr ) const +{ + return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ), + Count(), static_cast<VoidPtr>( rPtr ), + ((ParaPortionList *)this)->nLastCache ); +} + +USHORT ContentList::GetPos( const ContentNodePtr &rPtr ) const +{ + return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ), + Count(), static_cast<VoidPtr>( rPtr ), + ((ContentList *)this)->nLastCache ); +} + +void ParaPortionList::Reset() +{ + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + delete GetObject( nPortion ); + Remove( 0, Count() ); +} + +long ParaPortionList::GetYOffset( ParaPortion* pPPortion ) +{ + long nHeight = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + ParaPortion* pTmpPortion = GetObject(nPortion); + if ( pTmpPortion == pPPortion ) + return nHeight; + nHeight += pTmpPortion->GetHeight(); + } + DBG_ERROR( "GetYOffset: Portion nicht gefunden" ); + return nHeight; +} + +USHORT ParaPortionList::FindParagraph( long nYOffset ) +{ + long nY = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + nY += GetObject(nPortion)->GetHeight(); // sollte auch bei !bVisible richtig sein! + if ( nY > nYOffset ) + return nPortion; + } + return 0xFFFF; // solte mal ueber EE_PARA_NOT_FOUND erreicht werden! +} + +void ParaPortionList::DbgCheck( EditDoc& +#ifdef DBG_UTIL + rDoc +#endif + ) +{ +#ifdef DBG_UTIL + DBG_ASSERT( Count() == rDoc.Count(), "ParaPortionList::DbgCheck() - Count() ungleich!" ); + for ( USHORT i = 0; i < Count(); i++ ) + { + DBG_ASSERT( SaveGetObject(i), "ParaPortionList::DbgCheck() - Null-Pointer in Liste!" ); + DBG_ASSERT( GetObject(i)->GetNode(), "ParaPortionList::DbgCheck() - Null-Pointer in Liste(2)!" ); + DBG_ASSERT( GetObject(i)->GetNode() == rDoc.GetObject(i), "ParaPortionList::DbgCheck() - Eintraege kreuzen sich!" ); + } +#endif +} + + +ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) : + aPrevParaAttribs( rParaAttribs) +{ +} + + +void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit ) +{ + DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" ); + + switch ( rPoolItem.Which() ) + { + case EE_PARA_LRSPACE: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxLRSpaceItem& rItem = (SvxLRSpaceItem&)rPoolItem; + rItem.SetTxtFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTxtFirstLineOfst(), eSourceUnit, eDestUnit ) ) ); + rItem.SetTxtLeft( OutputDevice::LogicToLogic( rItem.GetTxtLeft(), eSourceUnit, eDestUnit ) ); +// rItem.SetLeft( OutputDevice::LogicToLogic( rItem.GetLeft(), eSourceUnit, eDestUnit ) ); // #96298# SetLeft manipulates nTxtLeft! + rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) ); + } + break; + case EE_PARA_ULSPACE: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxULSpaceItem& rItem = (SvxULSpaceItem&)rPoolItem; + rItem.SetUpper( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) ); + rItem.SetLower( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) ); + } + break; + case EE_PARA_SBL: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxLineSpacingItem& rItem = (SvxLineSpacingItem&)rPoolItem; + // #96298# SetLineHeight changes also eLineSpace! + if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + rItem.SetLineHeight( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) ); + } + break; + case EE_PARA_TABS: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxTabStopItem& rItem = (SvxTabStopItem&)rPoolItem; + SvxTabStopItem aNewItem( EE_PARA_TABS ); + for ( USHORT i = 0; i < rItem.Count(); i++ ) + { + const SvxTabStop& rTab = rItem[i]; + SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() ); + aNewItem.Insert( aNewStop ); + } + rItem = aNewItem; + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxFontHeightItem& rItem = (SvxFontHeightItem&)rPoolItem; + rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) ); + } + break; + } +} + +void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit ) +{ + const SfxItemPool* pSourcePool = rSource.GetPool(); + const SfxItemPool* pDestPool = rDest.GetPool(); + + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + // Wenn moeglich ueber SlotID gehen... + + USHORT nSourceWhich = nWhich; + USHORT nSlot = pDestPool->GetTrueSlotId( nWhich ); + if ( nSlot ) + { + USHORT nW = pSourcePool->GetTrueWhich( nSlot ); + if ( nW ) + nSourceWhich = nW; + } + + if ( rSource.GetItemState( nSourceWhich, FALSE ) == SFX_ITEM_ON ) + { + MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich ); + MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich ); + if ( eSourceUnit != eDestUnit ) + { + SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone(); +// pItem->SetWhich( nWhich ); + ConvertItem( *pItem, eSourceUnit, eDestUnit ); + rDest.Put( *pItem, nWhich ); + delete pItem; + } + else + { + rDest.Put( rSource.Get( nSourceWhich ), nWhich ); + } + } + else + { + // MT 3.3.99: Waere so eigentlich richtig, aber schon seit Jahren nicht so... +// rDest.ClearItem( nWhich ); + } + } +} + diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx new file mode 100644 index 000000000000..212fb8ff9446 --- /dev/null +++ b/editeng/source/editeng/editeng.cxx @@ -0,0 +1,2939 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#define USE_SVXFONT + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> +#include <svl/ctloptions.hxx> +#include <svtools/ctrltool.hxx> + +#include <editeng/svxfont.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editstat.hxx> +#include <editdbg.hxx> +#include <eerdll2.hxx> +#include <editeng/eerdll.hxx> +#include <editeng.hrc> +#include <editeng/flditem.hxx> +#include <editeng/txtrange.hxx> +#include <vcl/graph.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> + +#include <sot/exchange.hxx> +#include <sot/formats.hxx> + +#include <editeng/numitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/help.hxx> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/i18n/InputSequenceCheckMode.hpp> + +#include <svl/srchdefs.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#include <editeng/frmdiritem.hxx> +#endif +#include <basegfx/polygon/b2dpolygon.hxx> + +// Spaeter -> TOOLS\STRING.H (fuer Grep: WS_TARGET) + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + + +DBG_NAME( EditEngine ) +DBG_NAMEEX( EditView ) + +#if (OSL_DEBUG_LEVEL > 1) || defined ( DBG_UTIL ) +static sal_Bool bDebugPaint = sal_False; +#endif + +SV_IMPL_VARARR( EECharAttribArray, EECharAttrib ); + +static SfxItemPool* pGlobalPool=0; + +// ---------------------------------------------------------------------- +// EditEngine +// ---------------------------------------------------------------------- +EditEngine::EditEngine( SfxItemPool* pItemPool ) +{ + DBG_CTOR( EditEngine, 0 ); + pImpEditEngine = new ImpEditEngine( this, pItemPool ); +} + +EditEngine::~EditEngine() +{ + DBG_DTOR( EditEngine, 0 ); + delete pImpEditEngine; +} + +void EditEngine::EnableUndo( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnableUndo( bEnable ); +} + +sal_Bool EditEngine::IsUndoEnabled() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsUndoEnabled(); +} + +sal_Bool EditEngine::IsInUndo() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsInUndo(); +} + +SfxUndoManager& EditEngine::GetUndoManager() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetUndoManager(); +} + +void EditEngine::UndoActionStart( sal_uInt16 nId ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( !pImpEditEngine->IsInUndo(), "Aufruf von UndoActionStart im Undomodus!" ); + if ( !pImpEditEngine->IsInUndo() ) + pImpEditEngine->UndoActionStart( nId ); +} + +void EditEngine::UndoActionEnd( sal_uInt16 nId ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( !pImpEditEngine->IsInUndo(), "Aufruf von UndoActionEnd im Undomodus!" ); + if ( !pImpEditEngine->IsInUndo() ) + pImpEditEngine->UndoActionEnd( nId ); +} + +BOOL EditEngine::HasTriedMergeOnLastAddUndo() const +{ + return pImpEditEngine->mbLastTryMerge; +} + +void EditEngine::SetRefDevice( OutputDevice* pRefDev ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetRefDevice( pRefDev ); +} + +OutputDevice* EditEngine::GetRefDevice() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetRefDevice(); +} + +void EditEngine::SetRefMapMode( const MapMode& rMapMode ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetRefMapMode( rMapMode ); +} + +MapMode EditEngine::GetRefMapMode() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetRefMapMode(); +} + +void EditEngine::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetBackgroundColor( rColor ); +} + +Color EditEngine::GetBackgroundColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetBackgroundColor(); +} + +Color EditEngine::GetAutoColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetAutoColor(); +} + +void EditEngine::EnableAutoColor( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnableAutoColor( b ); +} + +BOOL EditEngine::IsAutoColorEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsAutoColorEnabled(); +} + +void EditEngine::ForceAutoColor( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ForceAutoColor( b ); +} + +BOOL EditEngine::IsForceAutoColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsForceAutoColor(); +} + +const SfxItemSet& EditEngine::GetEmptyItemSet() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEmptyItemSet(); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + Draw( pOutDev, rOutRect, Point( 0, 0 ) ); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Point& rStartPos, short nOrientation ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Mit 2 Punkten erzeugen, da bei Positivem Punkt, LONGMAX als Size + // Bottom und Right im Bereich > LONGMAX landen. + Rectangle aBigRec( -0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF ); + if( pOutDev->GetConnectMetaFile() ) + pOutDev->Push(); + Point aStartPos( rStartPos ); + if ( IsVertical() ) + { + aStartPos.X() += GetPaperSize().Width(); + aStartPos = Rotate( aStartPos, nOrientation, rStartPos ); + } + pImpEditEngine->Paint( pOutDev, aBigRec, aStartPos, sal_False, nOrientation ); + if( pOutDev->GetConnectMetaFile() ) + pOutDev->Pop(); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect, const Point& rStartDocPos ) +{ + Draw( pOutDev, rOutRect, rStartDocPos, sal_True ); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect, const Point& rStartDocPos, sal_Bool bClip ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + +#if defined( DBG_UTIL ) || (OSL_DEBUG_LEVEL > 1) + if ( bDebugPaint ) + EditDbg::ShowEditEngineData( this, sal_False ); +#endif + + // Auf Pixelgrenze ausrichten, damit genau das gleiche + // wie bei Paint(). + Rectangle aOutRect( pOutDev->LogicToPixel( rOutRect ) ); + aOutRect = pOutDev->PixelToLogic( aOutRect ); + + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos.X() = aOutRect.Left() - rStartDocPos.X(); + aStartPos.Y() = aOutRect.Top() - rStartDocPos.Y(); + } + else + { + aStartPos.X() = aOutRect.Right() + rStartDocPos.Y(); + aStartPos.Y() = aOutRect.Top() - rStartDocPos.X(); + } + + sal_Bool bClipRegion = pOutDev->IsClipRegion(); + sal_Bool bMetafile = pOutDev->GetConnectMetaFile() ? sal_True : sal_False; + Region aOldRegion = pOutDev->GetClipRegion(); + +#ifdef EDIT_PRINTER_LOG + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + { + SvFileStream aLog( "d:\\editprn.log", STREAM_WRITE ); + aLog.Seek( STREAM_SEEK_TO_END ); + aLog << '' << endl << "Printing: "; + aLog << GetText( "\n\r" ).GetStr(); + aLog << endl << endl; + aLog << "Ref-Device: " << String( (sal_uInt32)GetRefDevice() ).GetStr() << " Type=" << String( (sal_uInt16)GetRefDevice()->GetOutDevType() ).GetStr() << ", MapX=" << String( GetRefDevice()->GetMapMode().GetScaleX().GetNumerator() ).GetStr() << "/" << String( GetRefDevice()->GetMapMode().GetScaleX().GetDenominator() ).GetStr() <<endl; + aLog << "Paper-Width: " << String( GetPaperSize().Width() ).GetStr() << ",\tOut-Width: " << String( rOutRect.GetWidth() ).GetStr() << ",\tCalculated: " << String( CalcTextWidth() ).GetStr() << endl; + aLog << "Paper-Height: " << String( GetPaperSize().Height() ).GetStr() << ",\tOut-Height: " << String( rOutRect.GetHeight() ).GetStr() << ",\tCalculated: " << String( GetTextHeight() ).GetStr() << endl; + + aLog << endl; + } +#endif + + // Wenn es eine gab => Schnittmenge ! + // Bei der Metafileaufzeichnung Push/Pop verwenden. + if ( bMetafile ) + pOutDev->Push(); + + // Immer die Intersect-Methode, weil beim Metafile ein Muss! + if ( bClip ) + { + // Clip only if neccesary... + if ( !rStartDocPos.X() && !rStartDocPos.Y() && + ( rOutRect.GetHeight() >= (long)GetTextHeight() ) && + ( rOutRect.GetWidth() >= (long)CalcTextWidth() ) ) + { + bClip = FALSE; + } + else + { + // Einige Druckertreiber bereiten Probleme, wenn Buchstaben die + // ClipRegion streifen, deshalb lieber ein Pixel mehr... + Rectangle aClipRect( aOutRect ); + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + { + Size aPixSz( 1, 0 ); + aPixSz = pOutDev->PixelToLogic( aPixSz ); + aClipRect.Right() += aPixSz.Width(); + aClipRect.Bottom() += aPixSz.Width(); + } + pOutDev->IntersectClipRegion( aClipRect ); + } + } + + pImpEditEngine->Paint( pOutDev, aOutRect, aStartPos ); + + if ( bMetafile ) + pOutDev->Pop(); + else if ( bClipRegion ) + pOutDev->SetClipRegion( aOldRegion ); + else + pOutDev->SetClipRegion(); +} + +void EditEngine::InsertView( EditView* pEditView, sal_uInt16 nIndex ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pEditView, EditView, 0 ); + + if ( nIndex > pImpEditEngine->GetEditViews().Count() ) + nIndex = pImpEditEngine->GetEditViews().Count(); + + pImpEditEngine->GetEditViews().Insert( pEditView, nIndex ); + EditSelection aStartSel; + aStartSel = pImpEditEngine->GetEditDoc().GetStartPaM(); + pEditView->pImpEditView->SetEditSelection( aStartSel ); + if ( !pImpEditEngine->GetActiveView() ) + pImpEditEngine->SetActiveView( pEditView ); + + pEditView->pImpEditView->AddDragAndDropListeners(); +} + +EditView* EditEngine::RemoveView( EditView* pView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pView, EditView, 0 ); + + pView->HideCursor(); + EditView* pRemoved = 0; + sal_uInt16 nPos = pImpEditEngine->GetEditViews().GetPos( pView ); + DBG_ASSERT( nPos != USHRT_MAX, "RemoveView mit ungueltigem Index" ); + if ( nPos != USHRT_MAX ) + { + pRemoved = pImpEditEngine->GetEditViews().GetObject( nPos ); + pImpEditEngine->GetEditViews().Remove( nPos ); + if ( pImpEditEngine->GetActiveView() == pView ) + { + pImpEditEngine->SetActiveView( 0 ); + pImpEditEngine->GetSelEngine().SetCurView( 0 ); + } + pView->pImpEditView->RemoveDragAndDropListeners(); + + } + return pRemoved; +} + +EditView* EditEngine::RemoveView( sal_uInt16 nIndex ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditView* pView = pImpEditEngine->GetEditViews().GetObject( nIndex ); + if ( pView ) + return RemoveView( pView ); + return NULL; +} + +EditView* EditEngine::GetView( sal_uInt16 nIndex ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditViews().GetObject( nIndex ); +} + +sal_uInt16 EditEngine::GetViewCount() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditViews().Count(); +} + +sal_Bool EditEngine::HasView( EditView* pView ) const +{ + return pImpEditEngine->GetEditViews().GetPos( pView ) != USHRT_MAX; +} + +EditView* EditEngine::GetActiveView() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetActiveView(); +} + +void EditEngine::SetActiveView( EditView* pView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( pView ) + { + DBG_CHKOBJ( pView, EditView, 0 ); + } + pImpEditEngine->SetActiveView( pView ); +} + +void EditEngine::SetDefTab( sal_uInt16 nDefTab ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetEditDoc().SetDefTab( nDefTab ); + if ( pImpEditEngine->IsFormatted() ) + { + pImpEditEngine->FormatFullDoc(); + pImpEditEngine->UpdateViews( (EditView*) 0 ); + } +} + +sal_uInt16 EditEngine::GetDefTab() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetDefTab(); +} + +void EditEngine::SetPaperSize( const Size& rNewSize ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + Size aOldSize( pImpEditEngine->GetPaperSize() ); + pImpEditEngine->SetValidPaperSize( rNewSize ); + Size aNewSize( pImpEditEngine->GetPaperSize() ); + + sal_Bool bAutoPageSize = pImpEditEngine->GetStatus().AutoPageSize(); + if ( bAutoPageSize || ( aNewSize.Width() != aOldSize.Width() ) ) + { + for ( sal_uInt16 nView = 0; nView < pImpEditEngine->aEditViews.Count(); nView++ ) + { + EditView* pView = pImpEditEngine->aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + if ( bAutoPageSize ) + pView->pImpEditView->RecalcOutputArea(); + else if ( pView->pImpEditView->DoAutoSize() ) + { + pView->pImpEditView->ResetOutputArea( Rectangle( + pView->pImpEditView->GetOutputArea().TopLeft(), aNewSize ) ); + } + } + + if ( bAutoPageSize || pImpEditEngine->IsFormatted() ) + { + // Aendern der Breite hat bei AutoPageSize keine Wirkung, da durch + // Textbreite bestimmt. + // Optimierung erst nach Vobis-Auslieferung aktivieren... +// if ( !bAutoPageSize ) + pImpEditEngine->FormatFullDoc(); +// else +// { +// pImpEditEngine->FormatDoc(); // PageSize, falls Aenderung +// pImpEditEngine->CheckAutoPageSize(); // Falls nichts formatiert wurde +// } + + pImpEditEngine->UpdateViews( pImpEditEngine->GetActiveView() ); + + if ( pImpEditEngine->GetUpdateMode() && pImpEditEngine->GetActiveView() ) + pImpEditEngine->pActiveView->ShowCursor( sal_False, sal_False ); + } + } +} + +const Size& EditEngine::GetPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetPaperSize(); +} + +void EditEngine::SetVertical( BOOL bVertical ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetVertical( bVertical ); +} + +BOOL EditEngine::IsVertical() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsVertical(); +} + +void EditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetFixedCellHeight( bUseFixedCellHeight ); +} + +BOOL EditEngine::IsFixedCellHeight() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsFixedCellHeight(); +} + +void EditEngine::SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetDefaultHorizontalTextDirection( eHTextDir ); +} + +EEHorizontalTextDirection EditEngine::GetDefaultHorizontalTextDirection() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetDefaultHorizontalTextDirection(); +} + +USHORT EditEngine::GetScriptType( const ESelection& rSelection ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rSelection ) ); + return pImpEditEngine->GetScriptType( aSel ); +} + +LanguageType EditEngine::GetLanguage( USHORT nPara, USHORT nPos ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetLanguage - nPara is invalid!" ); + return pNode ? pImpEditEngine->GetLanguage( EditPaM( pNode, nPos ) ) : LANGUAGE_DONTKNOW; +} + + +void EditEngine::TransliterateText( const ESelection& rSelection, sal_Int32 nTransliterationMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->TransliterateText( pImpEditEngine->CreateSel( rSelection ), nTransliterationMode ); +} + +void EditEngine::SetAsianCompressionMode( USHORT n ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->SetAsianCompressionMode( n ); +} + +USHORT EditEngine::GetAsianCompressionMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditEngine->GetAsianCompressionMode(); +} + +void EditEngine::SetKernAsianPunctuation( BOOL b ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->SetKernAsianPunctuation( b ); +} + +BOOL EditEngine::IsKernAsianPunctuation() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditEngine->IsKernAsianPunctuation(); +} + +void EditEngine::SetAddExtLeading( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetAddExtLeading( b ); +} + +BOOL EditEngine::IsAddExtLeading() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsAddExtLeading(); +} + +void EditEngine::SetPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + SetPolygon( rPolyPolygon, 0L ); +} + +void EditEngine::SetPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon) +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bSimple(sal_False); + + if(pLinePolyPolygon && 1L == rPolyPolygon.count()) + { + if(rPolyPolygon.getB2DPolygon(0L).isClosed()) + { + // open polygon + bSimple = sal_True; + } + } + + TextRanger* pRanger = new TextRanger( rPolyPolygon, pLinePolyPolygon, 30, 2, 2, bSimple, sal_True ); + pImpEditEngine->SetTextRanger( pRanger ); + pImpEditEngine->SetPaperSize( pRanger->GetBoundRect().GetSize() ); +} + +void EditEngine::ClearPolygon() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetTextRanger( 0 ); +} + +const PolyPolygon* EditEngine::GetPolygon() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetTextRanger() ? + &pImpEditEngine->GetTextRanger()->GetPolyPolygon() : NULL; +} + +const Size& EditEngine::GetMinAutoPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetMinAutoPaperSize(); +} + +void EditEngine::SetMinAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetMinAutoPaperSize( rSz ); +} + +const Size& EditEngine::GetMaxAutoPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetMaxAutoPaperSize(); +} + +void EditEngine::SetMaxAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetMaxAutoPaperSize( rSz ); +} + +XubString EditEngine::GetText( LineEnd eEnd ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetText( eEnd ); +} + +XubString EditEngine::GetText( const ESelection& rESelection, const LineEnd eEnd ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rESelection ) ); + return pImpEditEngine->GetSelected( aSel, eEnd ); +} + +sal_uInt32 EditEngine::GetTextLen() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetTextLen(); +} + +sal_uInt16 EditEngine::GetParagraphCount() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aEditDoc.Count(); +} + +sal_uInt16 EditEngine::GetLineCount( sal_uInt16 nParagraph ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineCount( nParagraph ); +} + +sal_uInt16 EditEngine::GetLineLen( sal_uInt16 nParagraph, sal_uInt16 nLine ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineLen( nParagraph, nLine ); +} + +void EditEngine::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineBoundaries( rStart, rEnd, nParagraph, nLine ); +} + +USHORT EditEngine::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineNumberAtIndex( nPara, nIndex ); +} + +sal_uInt32 EditEngine::GetLineHeight( sal_uInt16 nParagraph, sal_uInt16 nLine ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Falls jemand mit einer leeren Engine ein GetLineHeight() macht. + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineHeight( nParagraph, nLine ); +} + +sal_uInt16 EditEngine::GetFirstLineOffset( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + return ( pPortion ? pPortion->GetFirstLineOffset() : 0 ); +} + +sal_uInt32 EditEngine::GetTextHeight( sal_uInt16 nParagraph ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nHeight = pImpEditEngine->GetParaHeight( nParagraph ); + return nHeight; +} + +XubString EditEngine::GetWord( sal_uInt16 nPara, sal_uInt16 nIndex ) +{ + ESelection aESel( nPara, nIndex, nPara, nIndex ); + EditSelection aSel( pImpEditEngine->CreateSel( aESel ) ); + aSel = pImpEditEngine->SelectWord( aSel ); + return pImpEditEngine->GetSelected( aSel ); +} + +ESelection EditEngine::GetWord( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->SelectWord( aSel, nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::WordLeft( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->WordLeft( aSel.Min(), nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::WordRight( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->WordRight( aSel.Max(), nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::CursorLeft( const ESelection& rSelection, USHORT nCharacterIteratorMode ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->CursorLeft( aSel.Min(), nCharacterIteratorMode ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::CursorRight( const ESelection& rSelection, USHORT nCharacterIteratorMode ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->CursorRight( aSel.Max(), nCharacterIteratorMode ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +sal_Bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pEditView, EditView, 0 ); + DBG_ASSERT( pEditView, "Keine View - keine Kekse !" ); + + sal_Bool bDone = sal_True; + + sal_Bool bModified = sal_False; + sal_Bool bMoved = sal_False; + sal_Bool bAllowIdle = sal_True; + sal_Bool bReadOnly = pEditView->IsReadOnly(); + + USHORT nNewCursorFlags = 0; + BOOL bSetCursorFlags = TRUE; + + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + DBG_ASSERT( !aCurSel.IsInvalid(), "Blinde Selection in EditEngine::PostKeyEvent" ); + + String aAutoText( pImpEditEngine->GetAutoCompleteText() ); + if ( pImpEditEngine->GetAutoCompleteText().Len() ) + pImpEditEngine->SetAutoCompleteText( String(), sal_True ); + + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_UNDO: + { + if ( !bReadOnly ) + pEditView->Undo(); + return sal_True; + } + // break; + case KEYFUNC_REDO: + { + if ( !bReadOnly ) + pEditView->Redo(); + return sal_True; + } + // break; + + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + + pImpEditEngine->EnterBlockNotifications(); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_INPUT_START ); + aNotify.pEditEngine = this; + pImpEditEngine->CallNotify( aNotify ); + } + + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( nCode ) + { + #if defined( DBG_UTIL ) || (OSL_DEBUG_LEVEL > 1) + case KEY_F1: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + USHORT nParas = GetParagraphCount(); + Point aPos; + Point aViewStart( pEditView->GetOutputArea().TopLeft() ); + long n20 = 40 * pImpEditEngine->nOnePixelInRef; + for ( USHORT n = 0; n < nParas; n++ ) + { + long nH = GetTextHeight( n ); + Point P1( aViewStart.X() + n20 + n20*(n%2), aViewStart.Y() + aPos.Y() ); + Point P2( P1 ); + P2.X() += n20; + P2.Y() += nH; + pEditView->GetWindow()->SetLineColor(); + pEditView->GetWindow()->SetFillColor( Color( (n%2) ? COL_YELLOW : COL_LIGHTGREEN ) ); + pEditView->GetWindow()->DrawRect( Rectangle( P1, P2 ) ); + aPos.Y() += nH; + } + } + bDone = FALSE; + } + break; + case KEY_F11: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + bDebugPaint = !bDebugPaint; + ByteString aInfo( "DebugPaint: " ); + aInfo += bDebugPaint ? "On" : "Off"; + InfoBox( NULL, String( aInfo, RTL_TEXTENCODING_ASCII_US ) ).Execute(); + } + bDone = FALSE; + } + break; + case KEY_F12: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + EditDbg::ShowEditEngineData( this ); + #ifdef EDIT_PRINTER_LOG + SvFileStream aLog( "d:\\editprn.log", STREAM_WRITE ); + aLog.Seek( STREAM_SEEK_TO_END ); + aLog << '' << endl << "Debug: "; + aLog << GetText( "\n\r" ).GetStr(); + aLog << endl << endl; + aLog << "Ref-Device: " << String( (sal_uInt32)GetRefDevice() ).GetStr() << " Type=" << String( (sal_uInt16)GetRefDevice()->GetOutDevType() ).GetStr() << ", MapX=" << String( GetRefDevice()->GetMapMode().GetScaleX().GetNumerator() ).GetStr() << "/" << String( GetRefDevice()->GetMapMode().GetScaleX().GetDenominator() ).GetStr() <<endl; + aLog << "Paper-Width: " << String( GetPaperSize().Width() ).GetStr() << ",\tCalculated: " << String( CalcTextWidth() ).GetStr() << endl; + aLog << "Paper-Height: " << String( GetPaperSize().Height() ).GetStr() << ",\tCalculated: " << String( GetTextHeight() ).GetStr() << endl; + aLog << endl; + #endif + } + bDone = FALSE; + } + break; + #endif + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_HOME: + case KEY_END: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + { + if ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) + { + if ( pImpEditEngine->DoVisualCursorTraveling( aCurSel.Max().GetNode() ) && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) /* || ( nCode == KEY_HOME ) || ( nCode == KEY_END ) */ ) ) + bSetCursorFlags = FALSE; // Will be manipulated within visual cursor move + + aCurSel = pImpEditEngine->MoveCursor( rKeyEvent, pEditView ); + + if ( aCurSel.HasRange() ) { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(pEditView->GetWindow()->GetPrimarySelection()); + pEditView->pImpEditView->CutCopy( aSelection, FALSE ); + } + + bMoved = sal_True; + if ( nCode == KEY_HOME ) + nNewCursorFlags |= GETCRSR_STARTOFLINE; + else if ( nCode == KEY_END ) + nNewCursorFlags |= GETCRSR_ENDOFLINE; + + } +#if OSL_DEBUG_LEVEL > 1 + GetLanguage( pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ), aCurSel.Max().GetIndex() ); +#endif + } + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH: + { + if ( !bReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) + { + // check if we are behind a bullet and using the backspace key + ContentNode *pNode = aCurSel.Min().GetNode(); + const SvxNumberFormat *pFmt = pImpEditEngine->GetNumberFormat( pNode ); + if (pFmt && nCode == KEY_BACKSPACE && + !aCurSel.HasRange() && aCurSel.Min().GetIndex() == 0) + { + // if the bullet is still visible just do not paint it from + // now on and that will be all. Otherwise continue as usual. + // ... + + USHORT nPara = pImpEditEngine->GetEditDoc().GetPos( pNode ); + SfxBoolItem aBulletState( (const SfxBoolItem&) pImpEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ) ); + bool bBulletIsVisible = aBulletState.GetValue() ? true : false; + + // just toggling EE_PARA_BULLETSTATE should be fine for both cases... + aBulletState.SetValue( !bBulletIsVisible ); + SfxItemSet aSet( pImpEditEngine->GetParaAttribs( nPara ) ); + aSet.Put( aBulletState ); + pImpEditEngine->SetParaAttribs( nPara, aSet ); + + // have this and the following paragraphs formatted and repainted. + // (not painting a numbering in the list may cause the following + // numberings to have different numbers than before and thus the + // length may have changed as well ) + pImpEditEngine->FormatAndUpdate( pImpEditEngine->GetActiveView() ); + + if (bBulletIsVisible) // bullet just turned invisible... + break; + } + + BYTE nDel = 0, nMode = 0; + switch( nCode ) + { + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + nMode = DELMODE_RESTOFWORD; + nDel = DEL_LEFT; + break; + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + nMode = DELMODE_RESTOFWORD; + nDel = DEL_RIGHT; + break; + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH: + nMode = DELMODE_RESTOFCONTENT; + nDel = DEL_LEFT; + break; + case com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH: + nMode = DELMODE_RESTOFCONTENT; + nDel = DEL_RIGHT; + break; + default: + nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; + nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; + if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) + nMode = DELMODE_RESTOFCONTENT; + break; + } + + pEditView->pImpEditView->DrawSelection(); + pImpEditEngine->UndoActionStart( EDITUNDO_DELETE ); + aCurSel = pImpEditEngine->DeleteLeftOrRight( aCurSel, nDel, nMode ); + pImpEditEngine->UndoActionEnd( EDITUNDO_DELETE ); + bModified = sal_True; + bAllowIdle = sal_False; + } + } + break; + case KEY_TAB: + { + if ( !bReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + { + sal_Bool bShift = rKeyEvent.GetKeyCode().IsShift(); + if ( pImpEditEngine->GetStatus().DoTabIndenting() && + ( aCurSel.Min().GetNode() != aCurSel.Max().GetNode() ) ) + { + pImpEditEngine->IndentBlock( pEditView, !bShift ); + } + else if ( !bShift ) + { + sal_Bool bSel = pEditView->HasSelection(); + if ( bSel ) + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + if ( pImpEditEngine->GetStatus().DoAutoCorrect() ) + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertTab( aCurSel ); + if ( bSel ) + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + bModified = sal_True; + } + } + else + bDone = sal_False; + } + break; + case KEY_RETURN: + { + if ( !bReadOnly ) + { + pEditView->pImpEditView->DrawSelection(); + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + if ( rKeyEvent.GetKeyCode().IsShift() ) + { + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertLineBreak( aCurSel ); + } + else + { + if ( !aAutoText.Len() ) + { + if ( pImpEditEngine->GetStatus().DoAutoCorrect() ) + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertParaBreak( aCurSel ); + } + else + { + DBG_ASSERT( !aCurSel.HasRange(), "Selektion bei Complete?!" ); + EditPaM aStart( pImpEditEngine->WordLeft( aCurSel.Max() ) ); + aCurSel = pImpEditEngine->InsertText( + EditSelection( aStart, aCurSel.Max() ), aAutoText ); + pImpEditEngine->SetAutoCompleteText( String(), sal_True ); + } + } + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + bModified = sal_True; + } + } + } + break; + case KEY_INSERT: + { + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + pEditView->SetInsertMode( !pEditView->IsInsertMode() ); + } + break; + default: + { + #if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL) + if ( ( nCode == KEY_W ) && rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + SfxItemSet aAttribs = pEditView->GetAttribs(); + const SvxFrameDirectionItem& rCurrentWritingMode = (const SvxFrameDirectionItem&)aAttribs.Get( EE_PARA_WRITINGDIR ); + SvxFrameDirectionItem aNewItem( FRMDIR_HORI_LEFT_TOP, EE_PARA_WRITINGDIR ); + if ( rCurrentWritingMode.GetValue() != FRMDIR_HORI_RIGHT_TOP ) + aNewItem.SetValue( FRMDIR_HORI_RIGHT_TOP ); + aAttribs.Put( aNewItem ); + pEditView->SetAttribs( aAttribs ); + } + #endif + if ( !bReadOnly && IsSimpleCharInput( rKeyEvent ) ) + { + xub_Unicode nCharCode = rKeyEvent.GetCharCode(); + pEditView->pImpEditView->DrawSelection(); + // Autokorrektur ? + if ( ( pImpEditEngine->GetStatus().DoAutoCorrect() ) && + SvxAutoCorrect::IsAutoCorrectChar( nCharCode ) ) + { + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, nCharCode, !pEditView->IsInsertMode() ); + } + else + { + aCurSel = pImpEditEngine->InsertText( (const EditSelection&)aCurSel, nCharCode, !pEditView->IsInsertMode(), sal_True ); + } + // AutoComplete ??? + if ( pImpEditEngine->GetStatus().DoAutoComplete() && ( nCharCode != ' ' ) ) + { + // Aber nur wenn Wort-Ende... + sal_uInt16 nIndex = aCurSel.Max().GetIndex(); + if ( ( nIndex >= aCurSel.Max().GetNode()->Len() ) || + ( pImpEditEngine->aWordDelimiters.Search( aCurSel.Max().GetNode()->GetChar( nIndex ) ) != STRING_NOTFOUND ) ) + { + EditPaM aStart( pImpEditEngine->WordLeft( aCurSel.Max() ) ); + String aWord = pImpEditEngine->GetSelected( EditSelection( aStart, aCurSel.Max() ) ); + if ( aWord.Len() >= 3 ) + { + String aComplete; + + LanguageType eLang = pImpEditEngine->GetLanguage( EditPaM( aStart.GetNode(), aStart.GetIndex()+1)); + lang::Locale aLocale( MsLangId::convertLanguageToLocale( eLang)); + + if (!pImpEditEngine->xLocaleDataWrapper.isInitialized()) + pImpEditEngine->xLocaleDataWrapper.init( SvtSysLocale().GetLocaleData().getServiceFactory(), aLocale, eLang); + else + pImpEditEngine->xLocaleDataWrapper.changeLocale( aLocale, eLang); + + if (!pImpEditEngine->xTransliterationWrapper.isInitialized()) + pImpEditEngine->xTransliterationWrapper.init( SvtSysLocale().GetLocaleData().getServiceFactory(), eLang, i18n::TransliterationModules_IGNORE_CASE); + else + pImpEditEngine->xTransliterationWrapper.changeLocale( eLang); + + const ::utl::TransliterationWrapper* pTransliteration = pImpEditEngine->xTransliterationWrapper.get(); + Sequence< i18n::CalendarItem > xItem = pImpEditEngine->xLocaleDataWrapper->getDefaultCalendarDays(); + sal_Int32 nCount = xItem.getLength(); + const i18n::CalendarItem* pArr = xItem.getArray(); + for( sal_Int32 n = 0; n <= nCount; ++n ) + { + const ::rtl::OUString& rDay = pArr[n].FullName; + if( pTransliteration->isMatch( aWord, rDay) ) + { + aComplete = rDay; + break; + } + } + + if ( !aComplete.Len() ) + { + xItem = pImpEditEngine->xLocaleDataWrapper->getDefaultCalendarMonths(); + sal_Int32 nMonthCount = xItem.getLength(); + const i18n::CalendarItem* pMonthArr = xItem.getArray(); + for( sal_Int32 n = 0; n <= nMonthCount; ++n ) + { + const ::rtl::OUString& rMon = pMonthArr[n].FullName; + if( pTransliteration->isMatch( aWord, rMon) ) + { + aComplete = rMon; + break; + } + } + } + + if( aComplete.Len() && ( ( aWord.Len() + 1 ) < aComplete.Len() ) ) + { + pImpEditEngine->SetAutoCompleteText( aComplete, sal_False ); + Point aPos = pImpEditEngine->PaMtoEditCursor( aCurSel.Max() ).TopLeft(); + aPos = pEditView->pImpEditView->GetWindowPos( aPos ); + aPos = pEditView->pImpEditView->GetWindow()->LogicToPixel( aPos ); + aPos = pEditView->GetWindow()->OutputToScreenPixel( aPos ); + aPos.Y() -= 3; + Help::ShowQuickHelp( pEditView->GetWindow(), Rectangle( aPos, Size( 1, 1 ) ), aComplete, QUICKHELP_BOTTOM|QUICKHELP_LEFT ); + } + } + } + } + bModified = sal_True; + } + else + bDone = sal_False; + } + } + } + + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pImpEditEngine->UpdateSelections(); + + if ( ( !IsVertical() && ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) || + ( IsVertical() && ( nCode != KEY_LEFT ) && ( nCode != KEY_RIGHT ) )) + { + pEditView->pImpEditView->nTravelXPos = TRAVEL_X_DONTKNOW; + } + + if ( /* ( nCode != KEY_HOME ) && ( nCode != KEY_END ) && */ + ( !IsVertical() && ( nCode != KEY_LEFT ) && ( nCode != KEY_RIGHT ) ) || + ( IsVertical() && ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )) + { + pEditView->pImpEditView->SetCursorBidiLevel( 0xFFFF ); + } + + if ( bSetCursorFlags ) + pEditView->pImpEditView->nExtraCursorFlags = nNewCursorFlags; + + if ( bModified ) + { + DBG_ASSERT( !bReadOnly, "ReadOnly but modified???" ); + // Idle-Formatter nur, wenn AnyInput. + if ( bAllowIdle && pImpEditEngine->GetStatus().UseIdleFormatter() + && Application::AnyInput( INPUT_KEYBOARD) ) + pImpEditEngine->IdleFormatAndUpdate( pEditView ); + else + pImpEditEngine->FormatAndUpdate( pEditView ); + } + else if ( bMoved ) + { + sal_Bool bGotoCursor = pEditView->pImpEditView->DoAutoScroll(); + pEditView->pImpEditView->ShowCursor( bGotoCursor, sal_True ); + pImpEditEngine->CallStatusHdl(); + } + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_INPUT_END ); + aNotify.pEditEngine = this; + pImpEditEngine->CallNotify( aNotify ); + } + + pImpEditEngine->LeaveBlockNotifications(); + + return bDone; +} + +sal_uInt32 EditEngine::GetTextHeight() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nHeight = !IsVertical() ? pImpEditEngine->GetTextHeight() : pImpEditEngine->CalcTextWidth( TRUE ); + return nHeight; +} + +sal_uInt32 EditEngine::CalcTextWidth() +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nWidth = !IsVertical() ? pImpEditEngine->CalcTextWidth( TRUE ) : pImpEditEngine->GetTextHeight(); + return nWidth; +} + +void EditEngine::SetUpdateMode( sal_Bool bUpdate ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetUpdateMode( bUpdate ); + if ( pImpEditEngine->pActiveView ) + pImpEditEngine->pActiveView->ShowCursor( sal_False, sal_False ); +} + +sal_Bool EditEngine::GetUpdateMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetUpdateMode(); +} + +void EditEngine::Clear() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->Clear(); +} + +void EditEngine::SetText( const XubString& rText ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetText( rText ); + if ( rText.Len() ) + pImpEditEngine->FormatAndUpdate(); +} + +ULONG EditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs /* = NULL */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bUndoEnabled = pImpEditEngine->IsUndoEnabled(); + pImpEditEngine->EnableUndo( sal_False ); + pImpEditEngine->SetText( XubString() ); + EditPaM aPaM( pImpEditEngine->GetEditDoc().GetStartPaM() ); + pImpEditEngine->Read( rInput, rBaseURL, eFormat, EditSelection( aPaM, aPaM ), pHTTPHeaderAttrs ); + pImpEditEngine->EnableUndo( bUndoEnabled ); + return rInput.GetError(); +} + +ULONG EditEngine::Write( SvStream& rOutput, EETextFormat eFormat ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditPaM aStartPaM( pImpEditEngine->GetEditDoc().GetStartPaM() ); + EditPaM aEndPaM( pImpEditEngine->GetEditDoc().GetEndPaM() ); + pImpEditEngine->Write( rOutput, eFormat, EditSelection( aStartPaM, aEndPaM ) ); + return rOutput.GetError(); +} + +EditTextObject* EditEngine::CreateTextObject() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->CreateTextObject(); +} + +EditTextObject* EditEngine::CreateTextObject( const ESelection& rESelection ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rESelection ) ); + return pImpEditEngine->CreateTextObject( aSel ); +} + +void EditEngine::SetText( const EditTextObject& rTextObject ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnterBlockNotifications(); + pImpEditEngine->SetText( rTextObject ); + pImpEditEngine->FormatAndUpdate(); + pImpEditEngine->LeaveBlockNotifications(); +} + +void EditEngine::ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ShowParagraph( nParagraph, bShow ); +} + +sal_Bool EditEngine::IsParagraphVisible( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsParagraphVisible( nParagraph ); +} + +void EditEngine::SetNotifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetNotifyHdl( rLink ); +} + +Link EditEngine::GetNotifyHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetNotifyHdl(); +} + +void EditEngine::SetStatusEventHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStatusEventHdl( rLink ); +} + +Link EditEngine::GetStatusEventHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatusEventHdl(); +} + +void EditEngine::SetImportHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aImportHdl = rLink; +} + +Link EditEngine::GetImportHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aImportHdl; +} + +void EditEngine::SetBeginMovingParagraphsHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aBeginMovingParagraphsHdl = rLink; +} + +void EditEngine::SetEndMovingParagraphsHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aEndMovingParagraphsHdl = rLink; +} + +void EditEngine::SetBeginPasteOrDropHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + pImpEditEngine->aBeginPasteOrDropHdl = rLink; +} + +void EditEngine::SetEndPasteOrDropHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aEndPasteOrDropHdl = rLink; +} + +EditTextObject* EditEngine::CreateTextObject( sal_uInt16 nPara, sal_uInt16 nParas ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( nPara < pImpEditEngine->GetEditDoc().Count(), "CreateTextObject: Startpara out of Range" ); + DBG_ASSERT( nPara+nParas-1 < pImpEditEngine->GetEditDoc().Count(), "CreateTextObject: Endpara out of Range" ); + + ContentNode* pStartNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + ContentNode* pEndNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara+nParas-1 ); + DBG_ASSERT( pStartNode, "Start-Absatz existiert nicht: CreateTextObject" ); + DBG_ASSERT( pEndNode, "End-Absatz existiert nicht: CreateTextObject" ); + + if ( pStartNode && pEndNode ) + { + EditSelection aTmpSel; + aTmpSel.Min() = EditPaM( pStartNode, 0 ); + aTmpSel.Max() = EditPaM( pEndNode, pEndNode->Len() ); + return pImpEditEngine->CreateTextObject( aTmpSel ); + } + return 0; +} + +void EditEngine::RemoveParagraph( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( pImpEditEngine->GetEditDoc().Count() > 1, "Der erste Absatz darf nicht geloescht werden!" ); + if( pImpEditEngine->GetEditDoc().Count() <= 1 ) + return; + + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + DBG_ASSERT( pPortion && pNode, "Absatz nicht gefunden: RemoveParagraph" ); + if ( pNode && pPortion ) + { + // Keine Undokappselung noetig. + pImpEditEngine->ImpRemoveParagraph( nPara ); + pImpEditEngine->InvalidateFromParagraph( nPara ); + pImpEditEngine->UpdateSelections(); + pImpEditEngine->FormatAndUpdate(); + } +} + +sal_uInt16 EditEngine::GetTextLen( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "Absatz nicht gefunden: GetTextLen" ); + if ( pNode ) + return pNode->Len(); + return 0; +} + +XubString EditEngine::GetText( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + XubString aStr; + if ( nPara < pImpEditEngine->GetEditDoc().Count() ) + aStr = pImpEditEngine->GetEditDoc().GetParaAsString( nPara ); + return aStr; +} + +void EditEngine::SetModifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyHdl( rLink ); +} + +Link EditEngine::GetModifyHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetModifyHdl(); +} + + +void EditEngine::ClearModifyFlag() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyFlag( sal_False ); +} + +void EditEngine::SetModified() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyFlag( sal_True ); +} + +sal_Bool EditEngine::IsModified() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsModified(); +} + +sal_Bool EditEngine::IsInSelectionMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return ( pImpEditEngine->IsInSelectionMode() || + pImpEditEngine->GetSelEngine().IsInSelection() ); +} + +void EditEngine::StopSelectionMode() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->StopSelectionMode(); +} + +void EditEngine::InsertParagraph( sal_uInt16 nPara, const EditTextObject& rTxtObj ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( nPara > GetParagraphCount() ) + { + DBG_ASSERTWARNING( nPara == USHRT_MAX, "AbsatzNr zu Gro???, aber nicht LIST_APPEND! " ); + nPara = GetParagraphCount(); + } + + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + + // Keine Undoklammerung noetig. + EditPaM aPaM( pImpEditEngine->InsertParagraph( nPara ) ); + // Bei einem InsertParagraph von aussen sollen keine Harten + // Attribute uebernommen werden ! + pImpEditEngine->RemoveCharAttribs( nPara ); + pImpEditEngine->InsertText( rTxtObj, EditSelection( aPaM, aPaM ) ); + + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + + pImpEditEngine->FormatAndUpdate(); +} + +void EditEngine::InsertParagraph( sal_uInt16 nPara, const XubString& rTxt ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( nPara > GetParagraphCount() ) + { + DBG_ASSERTWARNING( nPara == USHRT_MAX, "AbsatzNr zu Gro???, aber nicht LIST_APPEND! " ); + nPara = GetParagraphCount(); + } + + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM( pImpEditEngine->InsertParagraph( nPara ) ); + // Bei einem InsertParagraph von aussen sollen keine Harten + // Attribute uebernommen werden ! + pImpEditEngine->RemoveCharAttribs( nPara ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->ImpInsertText( EditSelection( aPaM, aPaM ), rTxt ); + pImpEditEngine->FormatAndUpdate(); +} + +void EditEngine::SetText( sal_uInt16 nPara, const EditTextObject& rTxtObj ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection* pSel = pImpEditEngine->SelectParagraph( nPara ); + if ( pSel ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + pImpEditEngine->InsertText( rTxtObj, *pSel ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->FormatAndUpdate(); + delete pSel; + } +} + +void EditEngine::SetText( sal_uInt16 nPara, const XubString& rTxt ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection* pSel = pImpEditEngine->SelectParagraph( nPara ); + if ( pSel ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + pImpEditEngine->ImpInsertText( *pSel, rTxt ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->FormatAndUpdate(); + delete pSel; + } +} + +void EditEngine::SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Keine Undoklammerung noetig. + pImpEditEngine->SetParaAttribs( nPara, rSet ); + pImpEditEngine->FormatAndUpdate(); +} + +const SfxItemSet& EditEngine::GetParaAttribs( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetParaAttribs( nPara ); +} + +sal_Bool EditEngine::HasParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasParaAttrib( nPara, nWhich ); +} + +const SfxPoolItem& EditEngine::GetParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetParaAttrib( nPara, nWhich ); +} + +void EditEngine::GetCharAttribs( sal_uInt16 nPara, EECharAttribArray& rLst ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetCharAttribs( nPara, rLst ); +} + +SfxItemSet EditEngine::GetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + return pImpEditEngine->GetAttribs( aSel, bOnlyHardAttrib ); +} + +SfxItemSet EditEngine::GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetAttribs( nPara, nStart, nEnd, nFlags ); +} + +void EditEngine::RemoveAttribs( const ESelection& rSelection, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + pImpEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS ); + EditSelection aSel( pImpEditEngine->ConvertSelection( rSelection.nStartPara, rSelection.nStartPos, rSelection.nEndPara, rSelection.nEndPos ) ); + pImpEditEngine->RemoveCharAttribs( aSel, bRemoveParaAttribs, nWhich ); + pImpEditEngine->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + pImpEditEngine->FormatAndUpdate(); +} + +// MT: Can be removed after 6.x? +Font EditEngine::GetStandardFont( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return GetStandardSvxFont( nPara ); +} + +SvxFont EditEngine::GetStandardSvxFont( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + return pNode->GetCharAttribs().GetDefFont(); +} + +void EditEngine::StripPortions() +{ + DBG_CHKTHIS( EditEngine, 0 ); + VirtualDevice aTmpDev; + Rectangle aBigRec( Point( 0, 0 ), Size( 0x7FFFFFFF, 0x7FFFFFFF ) ); + if ( IsVertical() ) + { + aBigRec.Right() = 0; + aBigRec.Left() = -0x7FFFFFFF; + } + pImpEditEngine->Paint( &aTmpDev, aBigRec, Point(), sal_True ); +} + +void EditEngine::GetPortions( sal_uInt16 nPara, SvUShorts& rList ) +{ + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatFullDoc(); + + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pParaPortion ) + { + sal_uInt16 nEnd = 0; + sal_uInt16 nTextPortions = pParaPortion->GetTextPortions().Count(); + for ( sal_uInt16 n = 0; n < nTextPortions; n++ ) + { + nEnd = nEnd + pParaPortion->GetTextPortions()[n]->GetLen(); + rList.Insert( nEnd, rList.Count() ); + } + } +} + +void EditEngine::SetFlatMode( sal_Bool bFlat) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetFlatMode( bFlat ); +} + +sal_Bool EditEngine::IsFlatMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return !( pImpEditEngine->aStatus.UseCharAttribs() ); +} + +void EditEngine::SetControlWord( sal_uInt32 nWord ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( nWord != pImpEditEngine->aStatus.GetControlWord() ) + { + sal_uInt32 nPrev = pImpEditEngine->aStatus.GetControlWord(); + pImpEditEngine->aStatus.GetControlWord() = nWord; + + sal_uInt32 nChanges = nPrev ^ nWord; + if ( pImpEditEngine->IsFormatted() ) + { + // ggf. neu formatieren: + if ( ( nChanges & EE_CNTRL_USECHARATTRIBS ) || + ( nChanges & EE_CNTRL_USEPARAATTRIBS ) || + ( nChanges & EE_CNTRL_ONECHARPERLINE ) || + ( nChanges & EE_CNTRL_STRETCHING ) || + ( nChanges & EE_CNTRL_OUTLINER ) || + ( nChanges & EE_CNTRL_NOCOLORS ) || + ( nChanges & EE_CNTRL_OUTLINER2 ) ) + { + if ( ( nChanges & EE_CNTRL_USECHARATTRIBS ) || + ( nChanges & EE_CNTRL_USEPARAATTRIBS ) ) + { + sal_Bool bUseCharAttribs = ( nWord & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False; + pImpEditEngine->GetEditDoc().CreateDefFont( bUseCharAttribs ); + } + + pImpEditEngine->FormatFullDoc(); + pImpEditEngine->UpdateViews( pImpEditEngine->GetActiveView() ); + } + } + + sal_Bool bSpellingChanged = nChanges & EE_CNTRL_ONLINESPELLING ? sal_True : sal_False; + + if ( bSpellingChanged ) + { + pImpEditEngine->StopOnlineSpellTimer(); + if ( bSpellingChanged && ( nWord & EE_CNTRL_ONLINESPELLING ) ) + { + // WrongListen anlegen, Timer starten... + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + pNode->CreateWrongList(); + } + pImpEditEngine->StartOnlineSpellTimer(); + } + else + { + long nY = 0; + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().GetObject( n ); + sal_Bool bWrongs = ( bSpellingChanged || ( nWord & EE_CNTRL_ONLINESPELLING ) ) ? pNode->GetWrongList()->HasWrongs() : sal_False; + if ( bSpellingChanged ) // Also aus + pNode->DestroyWrongList(); // => vorm Paint weghaun. + if ( bWrongs ) + { + pImpEditEngine->aInvalidRec.Left() = 0; + pImpEditEngine->aInvalidRec.Right() = pImpEditEngine->GetPaperSize().Width(); + pImpEditEngine->aInvalidRec.Top() = nY+1; + pImpEditEngine->aInvalidRec.Bottom() = nY+pPortion->GetHeight()-1; + pImpEditEngine->UpdateViews( pImpEditEngine->pActiveView ); + } + nY += pPortion->GetHeight(); + } + } + } + } +} + +sal_uInt32 EditEngine::GetControlWord() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aStatus.GetControlWord(); +} + +long EditEngine::GetFirstLineStartX( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + long nX = 0; + ParaPortion* pPPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + if ( pPPortion ) + { + DBG_ASSERT( pImpEditEngine->IsFormatted() || !pImpEditEngine->IsFormatting(), "GetFirstLineStartX: Doc not formatted - unable to format!" ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + EditLine* pFirstLine = pPPortion->GetLines()[0]; + nX = pFirstLine->GetStartPosX(); + } + return nX; +} + +Point EditEngine::GetDocPos( const Point& rPaperPos ) const +{ + Point aDocPos( rPaperPos ); + if ( IsVertical() ) + { + aDocPos.X() = rPaperPos.Y(); + aDocPos.Y() = GetPaperSize().Width() - rPaperPos.X(); + } + return aDocPos; +} + +Point EditEngine::GetDocPosTopLeft( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ParaPortion* pPPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetWindowPosTopLeft" ); + Point aPoint; + if ( pPPortion ) + { + // Falls jemand mit einer leeren Engine ein GetLineHeight() macht. + DBG_ASSERT( pImpEditEngine->IsFormatted() || !pImpEditEngine->IsFormatting(), "GetDocPosTopLeft: Doc not formatted - unable to format!" ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatAndUpdate(); + if ( pPPortion->GetLines().Count() ) + { + // So richtiger, falls grosses Bullet. + EditLine* pFirstLine = pPPortion->GetLines()[0]; + aPoint.X() = pFirstLine->GetStartPosX(); + } + else + { + const SvxLRSpaceItem& rLRItem = pImpEditEngine->GetLRSpaceItem( pPPortion->GetNode() ); +// TL_NF_LR aPoint.X() = pImpEditEngine->GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst()) ); + sal_Int32 nSpaceBefore = 0; + pImpEditEngine->GetSpaceBeforeAndMinLabelWidth( pPPortion->GetNode(), &nSpaceBefore ); + short nX = (short)(rLRItem.GetTxtLeft() + + rLRItem.GetTxtFirstLineOfst() + + nSpaceBefore); + aPoint.X() = pImpEditEngine->GetXValue( nX + ); + } + aPoint.Y() = pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + } + return aPoint; +} + +const SvxNumberFormat* EditEngine::GetNumberFormat( USHORT nPara ) const +{ + // derived objects may overload this function to give access to + // bullet information (see Outliner) + (void) nPara; + return 0; +} + +BOOL EditEngine::IsRightToLeft( USHORT nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsRightToLeft( nPara ); +} + +sal_Bool EditEngine::IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_Bool bTextPos = sal_False; + // #90780# take unrotated positions for calculation here + Point aDocPos = GetDocPos( rPaperPos ); + + if ( ( aDocPos.Y() > 0 ) && ( aDocPos.Y() < (long)pImpEditEngine->GetTextHeight() ) ) + { + EditPaM aPaM = pImpEditEngine->GetPaM( aDocPos, sal_False ); + if ( aPaM.GetNode() ) + { + ParaPortion* pParaPortion = pImpEditEngine->FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pParaPortion, "ParaPortion?" ); + + sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex() ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + Range aLineXPosStartEnd = pImpEditEngine->GetLineXPosStartEnd( pParaPortion, pLine ); + if ( ( aDocPos.X() >= aLineXPosStartEnd.Min() - nBorder ) && + ( aDocPos.X() <= aLineXPosStartEnd.Max() + nBorder ) ) + { + bTextPos = sal_True; + } + } + } + return bTextPos; +} + +void EditEngine::SetEditTextObjectPool( SfxItemPool* pPool ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetEditTextObjectPool( pPool ); +} + +SfxItemPool* EditEngine::GetEditTextObjectPool() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditTextObjectPool(); +} + +void EditEngine::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->SetAttribs( aSel, rSet ); +} + +void EditEngine::QuickMarkInvalid( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( rSel.nStartPara < pImpEditEngine->GetEditDoc().Count(), "MarkInvalid: Start out of Range!" ); + DBG_ASSERT( rSel.nEndPara < pImpEditEngine->GetEditDoc().Count(), "MarkInvalid: End out of Range!" ); + for ( sal_uInt16 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++ ) + { + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pPortion ) + pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->Len() ); + } +} + +void EditEngine::QuickInsertText( const XubString& rText, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpInsertText( aSel, rText ); +} + +void EditEngine::QuickDelete( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpDeleteSelection( aSel ); +} + +void EditEngine::QuickMarkToBeRepainted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pPortion ) + pPortion->SetMustRepaint( sal_True ); +} + +void EditEngine::QuickInsertLineBreak( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->InsertLineBreak( aSel ); +} + +void EditEngine::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpInsertFeature( aSel, rFld ); +} + +void EditEngine::QuickFormatDoc( sal_Bool bFull ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bFull ) + pImpEditEngine->FormatFullDoc(); + else + pImpEditEngine->FormatDoc(); + + // #111072# Don't pass active view, maybe selection is not updated yet... + pImpEditEngine->UpdateViews( NULL ); +} + +void EditEngine::QuickRemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->RemoveCharAttribs( nPara, nWhich ); +} + +void EditEngine::SetStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStyleSheet( nPara, pStyle ); +} + +SfxStyleSheet* EditEngine::GetStyleSheet( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStyleSheet( nPara ); +} + +void EditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStyleSheetPool( pSPool ); +} + +SfxStyleSheetPool* EditEngine::GetStyleSheetPool() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStyleSheetPool(); +} + +void EditEngine::SetWordDelimiters( const XubString& rDelimiters ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aWordDelimiters = rDelimiters; + if ( pImpEditEngine->aWordDelimiters.Search( CH_FEATURE ) == STRING_NOTFOUND ) + pImpEditEngine->aWordDelimiters.Insert( CH_FEATURE ); +} + +XubString EditEngine::GetWordDelimiters() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aWordDelimiters; +} + +void EditEngine::SetGroupChars( const XubString& rChars ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( ( rChars.Len() % 2 ) == 0, "SetGroupChars: Ungerade Anzahl!" ); + pImpEditEngine->aGroupChars = rChars; +} + +XubString EditEngine::GetGroupChars() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aGroupChars; +} + +void EditEngine::EnablePasteSpecial( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bEnable ) + pImpEditEngine->GetStatus().TurnOnFlags( EE_CNTRL_PASTESPECIAL ); + else + pImpEditEngine->GetStatus().TurnOffFlags( EE_CNTRL_PASTESPECIAL ); +} + +sal_Bool EditEngine::IsPasteSpecialEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatus().AllowPasteSpecial(); +} + +void EditEngine::EnableIdleFormatter( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bEnable ) + pImpEditEngine->GetStatus().TurnOnFlags( EE_CNTRL_DOIDLEFORMAT ); + else + pImpEditEngine->GetStatus().TurnOffFlags( EE_CNTRL_DOIDLEFORMAT); +} + +sal_Bool EditEngine::IsIdleFormatterEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatus().UseIdleFormatter(); +} + +void EditEngine::EraseVirtualDevice() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EraseVirtualDevice(); +} + +void EditEngine::SetSpeller( Reference< XSpellChecker1 > &xSpeller ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetSpeller( xSpeller ); +} +Reference< XSpellChecker1 > EditEngine::GetSpeller() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetSpeller(); +} +Reference< XHyphenator > EditEngine::GetHyphenator() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetHyphenator(); +} + +void EditEngine::SetHyphenator( Reference< XHyphenator > & xHyph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetHyphenator( xHyph ); +} + +void EditEngine::SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetForbiddenCharsTable( xForbiddenChars ); +} + +vos::ORef<SvxForbiddenCharactersTable> EditEngine::GetForbiddenCharsTable() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetForbiddenCharsTable( FALSE ); +} + + +void EditEngine::SetDefaultLanguage( LanguageType eLang ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetDefaultLanguage( eLang ); +} + +LanguageType EditEngine::GetDefaultLanguage() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetDefaultLanguage(); +} + +sal_Bool __EXPORT EditEngine::SpellNextDocument() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +EESpellState EditEngine::HasSpellErrors() +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return pImpEditEngine->HasSpellErrors(); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->StartSpelling(rEditView, bMultipleDoc); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::EndSpelling() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EndSpelling(); +} + +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool EditEngine::SpellSentence(EditView& rView, ::svx::SpellPortions& rToFill, bool bIsGrammarChecking ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->SpellSentence( rView, rToFill, bIsGrammarChecking ); +} +/*-- 08.09.2008 11:38:32--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::PutSpellingToSentenceStart( EditView& rEditView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->PutSpellingToSentenceStart( rEditView ); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool bIsGrammarChecking ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ApplyChangedSentence( rEditView, rNewPortions, bIsGrammarChecking ); +} + +sal_Bool EditEngine::HasConvertibleTextPortion( LanguageType nLang ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasConvertibleTextPortion( nLang ); +} + +sal_Bool __EXPORT EditEngine::ConvertNextDocument() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +sal_Bool EditEngine::HasText( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasText( rSearchItem ); +} + +void EditEngine::SetGlobalCharStretching( sal_uInt16 nX, sal_uInt16 nY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetCharStretching( nX, nY ); +} + +void EditEngine::GetGlobalCharStretching( sal_uInt16& rX, sal_uInt16& rY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetCharStretching( rX, rY ); +} + +void EditEngine::DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->DoStretchChars( nX, nY ); +} + +void EditEngine::SetBigTextObjectStart( sal_uInt16 nStartAtPortionCount ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetBigTextObjectStart( nStartAtPortionCount ); +} + +sal_uInt16 EditEngine::GetBigTextObjectStart() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetBigTextObjectStart(); +} + +sal_Bool EditEngine::ShouldCreateBigTextObject() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_uInt16 nTextPortions = 0; + sal_uInt16 nParas = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara]; + nTextPortions = nTextPortions + pParaPortion->GetTextPortions().Count(); + } + return ( nTextPortions >= pImpEditEngine->GetBigTextObjectStart() ) ? sal_True : sal_False; +} + +USHORT EditEngine::GetFieldCount( USHORT nPara ) const +{ + USHORT nFields = 0; + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + if ( pNode ) + { + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + nFields++; + } + } + + return nFields; +} + +EFieldInfo EditEngine::GetFieldInfo( USHORT nPara, USHORT nField ) const +{ + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + if ( pNode ) + { + USHORT nCurrentField = 0; + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + if ( nCurrentField == nField ) + { + EFieldInfo aInfo( *(const SvxFieldItem*)pAttr->GetItem(), nPara, pAttr->GetStart() ); + aInfo.aCurrentText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + return aInfo; + } + + nCurrentField++; + } + } + } + return EFieldInfo(); +} + + +sal_Bool EditEngine::UpdateFields() +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bChanges = pImpEditEngine->UpdateFields(); + if ( bChanges ) + pImpEditEngine->FormatAndUpdate(); + return bChanges; +} + +void EditEngine::RemoveFields( sal_Bool bKeepFieldText, TypeId aType ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( bKeepFieldText ) + pImpEditEngine->UpdateFields(); + + sal_uInt16 nParas = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( nPara ); + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + const EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + const SvxFieldData* pFldData = ((const SvxFieldItem*)pAttr->GetItem())->GetField(); + if ( pFldData && ( !aType || ( pFldData->IsA( aType ) ) ) ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + EditSelection aSel( EditPaM( pNode, pAttr->GetStart() ), EditPaM( pNode, pAttr->GetEnd() ) ); + String aFieldText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + pImpEditEngine->ImpInsertText( aSel, aFieldText ); + } + } + } + } +} + +sal_Bool EditEngine::HasOnlineSpellErrors() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + if ( pNode->GetWrongList() && pNode->GetWrongList()->Count() ) + return sal_True; + } + return sal_False; +} + +void EditEngine::CompleteOnlineSpelling() +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( pImpEditEngine->GetStatus().DoOnlineSpelling() ) + { + if( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatAndUpdate(); + + pImpEditEngine->StopOnlineSpellTimer(); + pImpEditEngine->DoOnlineSpelling( 0, sal_True, sal_False ); + } +} + +USHORT EditEngine::FindParagraph( long nDocPosY ) +{ + return pImpEditEngine->GetParaPortions().FindParagraph( nDocPosY ); +} + +EPosition EditEngine::FindDocPosition( const Point& rDocPos ) const +{ + EPosition aPos; + // From the point of the API, this is const.... + EditPaM aPaM = ((EditEngine*)this)->pImpEditEngine->GetPaM( rDocPos, FALSE ); + if ( aPaM.GetNode() ) + { + aPos.nPara = pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + aPos.nIndex = aPaM.GetIndex(); + } + return aPos; +} + +Rectangle EditEngine::GetCharacterBounds( const EPosition& rPos ) const +{ + Rectangle aBounds; + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( rPos.nPara ); + + // #109151# Check against index, not paragraph + if ( pNode && ( rPos.nIndex < pNode->Len() ) ) + { + aBounds = pImpEditEngine->PaMtoEditCursor( EditPaM( pNode, rPos.nIndex ), GETCRSR_TXTONLY ); + Rectangle aR2 = pImpEditEngine->PaMtoEditCursor( EditPaM( pNode, rPos.nIndex+1 ), GETCRSR_TXTONLY|GETCRSR_ENDOFLINE ); + if ( aR2.Right() > aBounds.Right() ) + aBounds.Right() = aR2.Right(); + } + return aBounds; +} + +ParagraphInfos EditEngine::GetParagraphInfos( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + // Funktioniert nur, wenn nicht bereits in der Formatierung... + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + ParagraphInfos aInfos; + aInfos.bValid = pImpEditEngine->IsFormatted(); + if ( pImpEditEngine->IsFormatted() ) + { + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara]; + EditLine* pLine = (pParaPortion && pParaPortion->GetLines().Count()) ? + pParaPortion->GetLines().GetObject( 0 ) : NULL; + DBG_ASSERT( pParaPortion && pLine, "GetParagraphInfos - Paragraph out of range" ); + if ( pParaPortion && pLine ) + { + aInfos.nParaHeight = (USHORT)pParaPortion->GetHeight(); + aInfos.nLines = pParaPortion->GetLines().Count(); + aInfos.nFirstLineStartX = pLine->GetStartPosX(); + aInfos.nFirstLineOffset = pParaPortion->GetFirstLineOffset(); + aInfos.nFirstLineHeight = pLine->GetHeight(); + aInfos.nFirstLineTextHeight = pLine->GetTxtHeight(); + aInfos.nFirstLineMaxAscent = pLine->GetMaxAscent(); + } + } + return aInfos; +} + +::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > + EditEngine::CreateTransferable( const ESelection& rSelection ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rSelection ) ); + return pImpEditEngine->CreateTransferable( aSel ); +} + +// ===================================================================== +// ====================== Virtuelle Methoden ======================= +// ===================================================================== +void __EXPORT EditEngine::DrawingText( const Point&, const XubString&, USHORT, USHORT, + const sal_Int32*, const SvxFont&, sal_uInt16, sal_uInt16, BYTE, + const EEngineData::WrongSpellVector*, const SvxFieldData*, bool, bool, bool, + const ::com::sun::star::lang::Locale*, const Color&, const Color&) + +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::PaintingFirstLine( sal_uInt16, const Point&, long, const Point&, short, OutputDevice* ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::ParagraphInserted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHINSERTED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} + +void __EXPORT EditEngine::ParagraphDeleted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHREMOVED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} +void EditEngine::ParagraphConnected( USHORT /*nLeftParagraph*/, USHORT /*nRightParagraph*/ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +sal_Bool __EXPORT EditEngine::FormattingParagraph( sal_uInt16 ) +{ + // return sal_True, wenn die Attribute geaendert wurden... + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +void __EXPORT EditEngine::ParaAttribsChanged( sal_uInt16 /* nParagraph */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::StyleSheetChanged( SfxStyleSheet* /* pStyle */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::ParagraphHeightChanged( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTHEIGHTCHANGED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} + +XubString __EXPORT EditEngine::GetUndoComment( sal_uInt16 nId ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + XubString aComment; + switch ( nId ) + { + case EDITUNDO_REMOVECHARS: + case EDITUNDO_CONNECTPARAS: + case EDITUNDO_REMOVEFEATURE: + case EDITUNDO_DELCONTENT: + case EDITUNDO_DELETE: + case EDITUNDO_CUT: + aComment = XubString( EditResId( RID_EDITUNDO_DEL ) ); + break; + case EDITUNDO_MOVEPARAGRAPHS: + case EDITUNDO_MOVEPARAS: + case EDITUNDO_DRAGANDDROP: + aComment = XubString( EditResId( RID_EDITUNDO_MOVE ) ); + break; + case EDITUNDO_INSERTFEATURE: + case EDITUNDO_SPLITPARA: + case EDITUNDO_INSERTCHARS: + case EDITUNDO_PASTE: + case EDITUNDO_INSERT: + case EDITUNDO_READ: + aComment = XubString( EditResId( RID_EDITUNDO_INSERT ) ); + break; + case EDITUNDO_SRCHANDREPL: + case EDITUNDO_REPLACEALL: + aComment = XubString( EditResId( RID_EDITUNDO_REPLACE ) ); + break; + case EDITUNDO_ATTRIBS: + case EDITUNDO_PARAATTRIBS: + case EDITUNDO_STRETCH: + aComment = XubString( EditResId( RID_EDITUNDO_SETATTRIBS ) ); + break; + case EDITUNDO_RESETATTRIBS: + aComment = XubString( EditResId( RID_EDITUNDO_RESETATTRIBS ) ); + break; + case EDITUNDO_STYLESHEET: + aComment = XubString( EditResId( RID_EDITUNDO_SETSTYLE ) ); + break; + case EDITUNDO_TRANSLITERATE: + aComment = XubString( EditResId( RID_EDITUNDO_TRANSLITERATE ) ); + break; + case EDITUNDO_INDENTBLOCK: + case EDITUNDO_UNINDENTBLOCK: + aComment = XubString( EditResId( RID_EDITUNDO_INDENT ) ); + break; + } + return aComment; +} + +Rectangle EditEngine::GetBulletArea( sal_uInt16 ) +{ + return Rectangle( Point(), Point() ); +} + +XubString __EXPORT EditEngine::CalcFieldValue( const SvxFieldItem&, sal_uInt16, sal_uInt16, Color*&, Color*& ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return ' '; +} + +void __EXPORT EditEngine::FieldClicked( const SvxFieldItem&, sal_uInt16, sal_uInt16 ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::FieldSelected( const SvxFieldItem&, sal_uInt16, sal_uInt16 ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +// ===================================================================== +// ====================== Statische Methoden ======================= +// ===================================================================== +SfxItemPool* EditEngine::CreatePool( sal_Bool bPersistentRefCounts ) +{ + SfxItemPool* pPool = new EditEngineItemPool( bPersistentRefCounts ); + return pPool; +} + +SfxItemPool& EditEngine::GetGlobalItemPool() +{ + if ( !pGlobalPool ) + pGlobalPool = CreatePool(); + return *pGlobalPool; +} + +sal_uInt32 EditEngine::RegisterClipboardFormatName() +{ + static sal_uInt32 nFormat = 0; + if ( !nFormat ) + nFormat = SotExchange::RegisterFormatName( String( RTL_CONSTASCII_USTRINGPARAM( "EditEngineFormat" ) ) ); + return nFormat; +} + +sal_uInt16 EditEngine::GetAvailableSearchOptions() +{ + return SEARCH_OPTIONS_SEARCH | SEARCH_OPTIONS_REPLACE | + SEARCH_OPTIONS_REPLACE_ALL | SEARCH_OPTIONS_WHOLE_WORDS | + SEARCH_OPTIONS_BACKWARDS | SEARCH_OPTIONS_REG_EXP | + SEARCH_OPTIONS_EXACT | SEARCH_OPTIONS_SELECTION; +} + +void EditEngine::SetFontInfoInItemSet( SfxItemSet& rSet, const Font& rFont ) +{ + SvxFont aSvxFont( rFont ); + SetFontInfoInItemSet( rSet, aSvxFont ); + +} + +void EditEngine::SetFontInfoInItemSet( SfxItemSet& rSet, const SvxFont& rFont ) +{ + rSet.Put( SvxLanguageItem( rFont.GetLanguage(), EE_CHAR_LANGUAGE ) ); + rSet.Put( SvxFontItem( rFont.GetFamily(), rFont.GetName(), XubString(), rFont.GetPitch(), rFont.GetCharSet(), EE_CHAR_FONTINFO ) ); + rSet.Put( SvxFontHeightItem( rFont.GetSize().Height(), 100, EE_CHAR_FONTHEIGHT ) ); + rSet.Put( SvxCharScaleWidthItem( 100, EE_CHAR_FONTWIDTH ) ); + rSet.Put( SvxShadowedItem( rFont.IsShadow(), EE_CHAR_SHADOW ) ); + rSet.Put( SvxEscapementItem( rFont.GetEscapement(), rFont.GetPropr(), EE_CHAR_ESCAPEMENT ) ); + rSet.Put( SvxWeightItem( rFont.GetWeight(), EE_CHAR_WEIGHT ) ); + rSet.Put( SvxColorItem( rFont.GetColor(), EE_CHAR_COLOR ) ); + rSet.Put( SvxUnderlineItem( rFont.GetUnderline(), EE_CHAR_UNDERLINE ) ); + rSet.Put( SvxOverlineItem( rFont.GetOverline(), EE_CHAR_OVERLINE ) ); + rSet.Put( SvxCrossedOutItem( rFont.GetStrikeout(), EE_CHAR_STRIKEOUT ) ); + rSet.Put( SvxPostureItem( rFont.GetItalic(), EE_CHAR_ITALIC ) ); + rSet.Put( SvxContourItem( rFont.IsOutline(), EE_CHAR_OUTLINE ) ); + rSet.Put( SvxAutoKernItem( rFont.IsKerning(), EE_CHAR_PAIRKERNING ) ); + rSet.Put( SvxKerningItem( rFont.GetFixKerning(), EE_CHAR_KERNING ) ); + rSet.Put( SvxWordLineModeItem( rFont.IsWordLineMode(), EE_CHAR_WLM ) ); + rSet.Put( SvxEmphasisMarkItem( rFont.GetEmphasisMark(), EE_CHAR_EMPHASISMARK ) ); + rSet.Put( SvxCharReliefItem( rFont.GetRelief(), EE_CHAR_RELIEF ) ); +} + +Font EditEngine::CreateFontFromItemSet( const SfxItemSet& rItemSet, USHORT nScriptType ) +{ + SvxFont aFont; + CreateFont( aFont, rItemSet, true, nScriptType ); + return aFont; +} + +// Maybe we can remove the next two methods, check after 6.x +Font EditEngine::CreateFontFromItemSet( const SfxItemSet& rItemSet ) +{ + return CreateSvxFontFromItemSet( rItemSet ); +} + +SvxFont EditEngine::CreateSvxFontFromItemSet( const SfxItemSet& rItemSet ) +{ + SvxFont aFont; + CreateFont( aFont, rItemSet ); + return aFont; +} + +sal_Bool EditEngine::DoesKeyMoveCursor( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDoesMove = sal_False; + + switch ( rKeyEvent.GetKeyCode().GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_HOME: + case KEY_END: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + { + if ( !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesMove = sal_True; + } + break; + } + return bDoesMove; +} + +sal_Bool EditEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDoesChange = sal_False; + + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_UNDO: + case KEYFUNC_REDO: + case KEYFUNC_CUT: + case KEYFUNC_PASTE: bDoesChange = sal_True; + break; + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( rKeyEvent.GetKeyCode().GetCode() ) + { + case KEY_DELETE: + case KEY_BACKSPACE: bDoesChange = sal_True; + break; + case KEY_RETURN: + case KEY_TAB: + { + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesChange = sal_True; + } + break; + default: + { + bDoesChange = IsSimpleCharInput( rKeyEvent ); + } + } + } + return bDoesChange; +} + +sal_Bool EditEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) +{ + if( EditEngine::IsPrintable( rKeyEvent.GetCharCode() ) && + ( KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT ) ) && + ( KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT ) ) ) + { + return sal_True; + } + return sal_False; +} + +// Mal in den Outliner schieben... +void EditEngine::ImportBulletItem( SvxNumBulletItem& /*rNumBullet*/, sal_uInt16 /*nLevel*/, + const SvxBulletItem* /*pOldBullet*/, const SvxLRSpaceItem* /*pOldLRSpace*/ ) +{ +/* TL_NFLR + if ( pOldBullet || pOldLRSpace ) + { + // Numberformat dynamisch, weil Zuweisungsoperator nicht implementiert. + + // Altes NumBulletItem nur uebernehmen, wenn kein altes BulletItem + const SvxNumberFormat* pFmt = ( !pOldBullet && ( rNumBullet.GetNumRule()->GetLevelCount() > nLevel ) ) ? + rNumBullet.GetNumRule()->Get( nLevel ) : NULL; + SvxNumberFormat* pNumberFormat = pFmt + ? new SvxNumberFormat( *pFmt ) + : new SvxNumberFormat( SVX_NUM_NUMBER_NONE ); + if ( pOldBullet ) + { + // Style + SvxExtNumType eNumType; + switch( pOldBullet->GetStyle() ) + { + case BS_BMP: eNumType = SVX_NUM_BITMAP; break; + case BS_BULLET: eNumType = SVX_NUM_CHAR_SPECIAL; break; + case BS_ROMAN_BIG: eNumType = SVX_NUM_ROMAN_UPPER; break; + case BS_ROMAN_SMALL: eNumType = SVX_NUM_ROMAN_LOWER; break; + case BS_ABC_BIG: eNumType = SVX_NUM_CHARS_UPPER_LETTER; break; + case BS_ABC_SMALL: eNumType = SVX_NUM_CHARS_LOWER_LETTER; break; + case BS_123: eNumType = SVX_NUM_ARABIC; break; + default: eNumType = SVX_NUM_NUMBER_NONE; break; + } + pNumberFormat->SetNumberingType( + sal::static_int_cast< sal_Int16 >( eNumType ) ); + + // Justification + SvxAdjust eAdjust; + switch( pOldBullet->GetJustification() & (BJ_HRIGHT|BJ_HCENTER|BJ_HLEFT) ) + { + case BJ_HRIGHT: eAdjust = SVX_ADJUST_RIGHT; break; + case BJ_HCENTER: eAdjust = SVX_ADJUST_CENTER; break; + default: eAdjust = SVX_ADJUST_LEFT; break; + } + pNumberFormat->SetNumAdjust(eAdjust); + + // Prefix/Suffix + pNumberFormat->SetPrefix( pOldBullet->GetPrevText() ); + pNumberFormat->SetSuffix( pOldBullet->GetFollowText() ); + + //Font + if ( eNumType != SVX_NUM_BITMAP ) + { + Font aTmpFont = pOldBullet->GetFont(); + pNumberFormat->SetBulletFont( &aTmpFont ); + } + + // Color + pNumberFormat->SetBulletColor( pOldBullet->GetFont().GetColor() ); + + // Start + pNumberFormat->SetStart( pOldBullet->GetStart() ); + + // Scale + pNumberFormat->SetBulletRelSize( pOldBullet->GetScale() ); + + // Bullet/Bitmap + if( eNumType == SVX_NUM_CHAR_SPECIAL ) + { + pNumberFormat->SetBulletChar( pOldBullet->GetSymbol() ); + } + else if( eNumType == SVX_NUM_BITMAP ) + { + SvxBrushItem aBItem( Graphic( pOldBullet->GetBitmap() ), GPOS_NONE, SID_ATTR_BRUSH ); + pNumberFormat->SetGraphicBrush( &aBItem ); + } + } + + // Einzug und Erstzeileneinzug +//TL_NFLR if ( pOldLRSpace ) +//TL_NFLR { +//TL_NFLR short nLSpace = (short)pOldLRSpace->GetTxtLeft(); +//TL_NFLR pNumberFormat->SetLSpace( nLSpace ); +//TL_NFLR pNumberFormat->SetAbsLSpace( nLSpace ); +//TL_NFLR pNumberFormat->SetFirstLineOffset( pOldLRSpace->GetTxtFirstLineOfst() ); +//TL_NFLR } + + rNumBullet.GetNumRule()->SetLevel( nLevel, *pNumberFormat ); + delete pNumberFormat; + } +*/ +} + +BOOL EditEngine::HasValidData( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& rTransferable ) +{ + BOOL bValidData = FALSE; + + if ( rTransferable.is() ) + { + // Every application that copies rtf or any other text format also copies plain text into the clipboard.... + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + bValidData = rTransferable->isDataFlavorSupported( aFlavor ); + } + + return bValidData; +} + +/** sets a link that is called at the beginning of a drag operation at an edit view */ +void EditEngine::SetBeginDropHdl( const Link& rLink ) +{ + pImpEditEngine->SetBeginDropHdl( rLink ); +} + +Link EditEngine::GetBeginDropHdl() const +{ + return pImpEditEngine->GetBeginDropHdl(); +} + +/** sets a link that is called at the end of a drag operation at an edit view */ +void EditEngine::SetEndDropHdl( const Link& rLink ) +{ + pImpEditEngine->SetEndDropHdl( rLink ); +} + +Link EditEngine::GetEndDropHdl() const +{ + return pImpEditEngine->GetEndDropHdl(); +} + +void EditEngine::SetFirstWordCapitalization( BOOL bCapitalize ) +{ + pImpEditEngine->SetFirstWordCapitalization( bCapitalize ); +} + +BOOL EditEngine::IsFirstWordCapitalization() const +{ + return pImpEditEngine->IsFirstWordCapitalization(); +} + + +// --------------------------------------------------- + + +EFieldInfo::EFieldInfo() +{ + pFieldItem = NULL; +} + + +EFieldInfo::EFieldInfo( const SvxFieldItem& rFieldItem, USHORT nPara, USHORT nPos ) : aPosition( nPara, nPos ) +{ + pFieldItem = new SvxFieldItem( rFieldItem ); +} + +EFieldInfo::~EFieldInfo() +{ + delete pFieldItem; +} + +EFieldInfo::EFieldInfo( const EFieldInfo& rFldInfo ) +{ + *this = rFldInfo; +} + +EFieldInfo& EFieldInfo::operator= ( const EFieldInfo& rFldInfo ) +{ + if( this == &rFldInfo ) + return *this; + + pFieldItem = rFldInfo.pFieldItem ? new SvxFieldItem( *rFldInfo.pFieldItem ) : 0; + aCurrentText = rFldInfo.aCurrentText; + aPosition = rFldInfo.aPosition; + + return *this; +} diff --git a/editeng/source/editeng/editeng.src b/editeng/source/editeng/editeng.src new file mode 100644 index 000000000000..b65f20c36583 --- /dev/null +++ b/editeng/source/editeng/editeng.src @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <editeng.hrc> +#include <helpid.hrc> + +String RID_EDITUNDO_DEL +{ + Text [ en-US ] = "Delete" ; +}; + +String RID_EDITUNDO_MOVE +{ + Text [ en-US ] = "Move" ; +}; + +String RID_EDITUNDO_INSERT +{ + Text [ en-US ] = "Insert" ; +}; + +String RID_EDITUNDO_REPLACE +{ + Text [ en-US ] = "Replace" ; +}; + +String RID_EDITUNDO_SETATTRIBS +{ + Text [ en-US ] = "Apply attributes" ; +}; + +String RID_EDITUNDO_RESETATTRIBS +{ + Text [ en-US ] = "Reset attributes" ; +}; + +String RID_EDITUNDO_INDENT +{ + Text [ en-US ] = "Indent" ; +}; + +String RID_EDITUNDO_SETSTYLE +{ + Text [ en-US ] = "Apply Styles" ; +}; + +String RID_EDITUNDO_TRANSLITERATE +{ + Text [ en-US ] = "Case/Characters"; +}; + + +Menu RID_MENU_SPELL +{ + ItemList = + { + MenuItem + { + Identifier = MN_SPELLING ; + HelpId = HID_EDITENG_SPELLER_START; + Text [ en-US ] = "~Spellcheck..." ; + }; + MenuItem + { + Identifier = MN_INSERT ; + HelpId = HID_EDITENG_SPELLER_ADDWORD; + SubMenu = Menu + { + }; + Text [ en-US ] = "~Add" ; + }; + MenuItem + { + Identifier = MN_IGNORE ; + HelpId = HID_EDITENG_SPELLER_IGNORE; + Text [ en-US ] = "Ignore All" ; + }; + MenuItem + { + Identifier = MN_AUTOCORR ; + HelpId = HID_EDITENG_SPELLER_AUTOCORRECT; + SubMenu = Menu + { + }; + Text [ en-US ] = "AutoCorrect" ; + }; + }; +}; + + +String RID_STR_WORD +{ + Text [ en-US ] = "Word is %x"; +}; + +String RID_STR_PARAGRAPH +{ + Text [ en-US ] = "Paragraph is %x"; +}; + diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx new file mode 100644 index 000000000000..7cd009cc52be --- /dev/null +++ b/editeng/source/editeng/editobj.cxx @@ -0,0 +1,1725 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#define ENABLE_STRING_STREAM_OPERATORS +#include <tools/stream.hxx> + +#include <editobj2.hxx> +#include <editeng/editdata.hxx> +#include <editattr.hxx> +#include <editeng/editeng.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/brshitem.hxx> +#include <vcl/graph.hxx> +#include <svl/intitem.hxx> +#include <unotools/fontcvt.hxx> +#include <tools/tenccvt.hxx> + +DBG_NAME( EE_EditTextObject ) +DBG_NAME( XEditAttribute ) + +//-------------------------------------------------------------- + +BOOL lcl_CreateBulletItem( const SvxNumBulletItem& rNumBullet, USHORT nLevel, SvxBulletItem& rBullet ) +{ + const SvxNumberFormat* pFmt = rNumBullet.GetNumRule()->Get( nLevel ); + if ( pFmt ) + { + rBullet.SetWidth( (-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance() ); + rBullet.SetSymbol( pFmt->GetBulletChar() ); + rBullet.SetPrevText( pFmt->GetPrefix() ); + rBullet.SetFollowText( pFmt->GetSuffix() ); + rBullet.SetStart( pFmt->GetStart() ); + rBullet.SetScale( pFmt->GetBulletRelSize() ); + + Font aBulletFont( rBullet.GetFont() ); + if ( pFmt->GetBulletFont() ) + aBulletFont = *pFmt->GetBulletFont(); + aBulletFont.SetColor( pFmt->GetBulletColor() ); + rBullet.SetFont( aBulletFont ); + + if ( pFmt->GetBrush() && pFmt->GetBrush()->GetGraphic() ) + { + Bitmap aBmp( pFmt->GetBrush()->GetGraphic()->GetBitmap() ); + aBmp.SetPrefSize( pFmt->GetGraphicSize() ); + aBmp.SetPrefMapMode( MAP_100TH_MM ); + rBullet.SetBitmap( aBmp ); + } + + switch ( pFmt->GetNumberingType() ) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: + rBullet.SetStyle( BS_ABC_BIG ); + break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: + rBullet.SetStyle( BS_ABC_SMALL ); + break; + case SVX_NUM_ROMAN_UPPER: + rBullet.SetStyle( BS_ROMAN_BIG ); + break; + case SVX_NUM_ROMAN_LOWER: + rBullet.SetStyle( BS_ROMAN_SMALL ); + break; + case SVX_NUM_ARABIC: + rBullet.SetStyle( BS_123 ); + break; + case SVX_NUM_NUMBER_NONE: + rBullet.SetStyle( BS_NONE ); + break; + case SVX_NUM_CHAR_SPECIAL: + rBullet.SetStyle( BS_BULLET ); + break; + case SVX_NUM_PAGEDESC: + DBG_ERROR( "Unknown: SVX_NUM_PAGEDESC" ); + rBullet.SetStyle( BS_BULLET ); + break; + case SVX_NUM_BITMAP: + rBullet.SetStyle( BS_BMP ); + break; + default: + DBG_ERROR( "Unknown NumType" ); + } + + switch ( pFmt->GetNumAdjust() ) + { + case SVX_ADJUST_LEFT: + rBullet.SetJustification( BJ_VCENTER|BJ_HLEFT ); + break; + case SVX_ADJUST_RIGHT: + rBullet.SetJustification( BJ_VCENTER|BJ_HRIGHT ); + break; + case SVX_ADJUST_CENTER: + rBullet.SetJustification( BJ_VCENTER|BJ_HCENTER ); + break; + default: + DBG_ERROR( "Unknown or invalid NumAdjust" ); + } + } + return pFmt ? TRUE : FALSE; +} + + +XEditAttribute* MakeXEditAttribute( SfxItemPool& rPool, const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ) +{ + // das neue Attribut im Pool anlegen + const SfxPoolItem& rNew = rPool.Put( rItem ); + + XEditAttribute* pNew = new XEditAttribute( rNew, nStart, nEnd ); + return pNew; +} + + +XEditAttribute::XEditAttribute( const SfxPoolItem& rAttr ) +{ + DBG_CTOR( XEditAttribute, 0 ); + pItem = &rAttr; + nStart = 0; + nEnd = 0; +} + +XEditAttribute::XEditAttribute( const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) +{ + DBG_CTOR( XEditAttribute, 0 ); + pItem = &rAttr; + nStart = nS; + nEnd = nE; +} + +XEditAttribute::~XEditAttribute() +{ + DBG_DTOR( XEditAttribute, 0 ); + pItem = 0; // Gehoert dem Pool. +} + +XEditAttribute* XEditAttributeList::FindAttrib( USHORT _nWhich, USHORT nChar ) const +{ + for ( USHORT n = Count(); n; ) + { + XEditAttribute* pAttr = GetObject( --n ); + if( ( pAttr->GetItem()->Which() == _nWhich ) && ( pAttr->GetStart() <= nChar ) && ( pAttr->GetEnd() > nChar ) ) + return pAttr; + } + return NULL; +} + +ContentInfo::ContentInfo( SfxItemPool& rPool ) : aParaAttribs( rPool, EE_PARA_START, EE_CHAR_END ) +{ + eFamily = SFX_STYLE_FAMILY_PARA; + pWrongs = NULL; +/* cl removed because not needed anymore since binfilter + pTempLoadStoreInfos = NULL; +*/ +} + +// Richtiger CopyCTOR unsinning, weil ich mit einem anderen Pool arbeiten muss! +ContentInfo::ContentInfo( const ContentInfo& rCopyFrom, SfxItemPool& rPoolToUse ) + : aParaAttribs( rPoolToUse, EE_PARA_START, EE_CHAR_END ) +{ + pWrongs = NULL; +/* cl removed because not needed anymore since binfilter + pTempLoadStoreInfos = NULL; +*/ + if ( rCopyFrom.GetWrongList() ) + pWrongs = rCopyFrom.GetWrongList()->Clone(); + // So sollten die Items im richtigen Pool landen! + aParaAttribs.Set( rCopyFrom.GetParaAttribs() ); + aText = rCopyFrom.GetText(); + aStyle = rCopyFrom.GetStyle(); + eFamily = rCopyFrom.GetFamily(); + + // Attribute kopieren... + for ( USHORT n = 0; n < rCopyFrom.GetAttribs().Count(); n++ ) + { + XEditAttribute* pAttr = rCopyFrom.GetAttribs().GetObject( n ); + XEditAttribute* pMyAttr = MakeXEditAttribute( rPoolToUse, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + aAttribs.Insert( pMyAttr, aAttribs.Count() ); + } + + // Wrongs + pWrongs = NULL; +#ifndef SVX_LIGHT + if ( rCopyFrom.GetWrongList() ) + pWrongs = rCopyFrom.GetWrongList()->Clone(); +#endif // !SVX_LIGHT +} + +ContentInfo::~ContentInfo() +{ + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + XEditAttribute* pAttr = aAttribs.GetObject(nAttr); + // Item aus Pool entfernen! + aParaAttribs.GetPool()->Remove( *pAttr->GetItem() ); + delete pAttr; + } + aAttribs.Remove( 0, aAttribs.Count() ); +#ifndef SVX_LIGHT + delete pWrongs; +#endif +} + +/* cl removed because not needed anymore since binfilter +void ContentInfo::CreateLoadStoreTempInfos() +{ + delete pTempLoadStoreInfos; + pTempLoadStoreInfos = new LoadStoreTempInfos; +} + +void ContentInfo::DestroyLoadStoreTempInfos() +{ + delete pTempLoadStoreInfos; + pTempLoadStoreInfos = NULL; +} +*/ + +// #i102062# +bool ContentInfo::isWrongListEqual(const ContentInfo& rCompare) const +{ + if(GetWrongList() == rCompare.GetWrongList()) + return true; + + if(!GetWrongList() || !rCompare.GetWrongList()) + return false; + + return (*GetWrongList() == *rCompare.GetWrongList()); +} + +bool ContentInfo::operator==( const ContentInfo& rCompare ) const +{ + if( (aText == rCompare.aText) && + (aStyle == rCompare.aStyle ) && + (aAttribs.Count() == rCompare.aAttribs.Count() ) && + (eFamily == rCompare.eFamily ) && + (aParaAttribs == rCompare.aParaAttribs ) ) + { + const USHORT nCount = aAttribs.Count(); + if( nCount == rCompare.aAttribs.Count() ) + { + USHORT n; + for( n = 0; n < nCount; n++ ) + { + if( !(*aAttribs.GetObject(n) == *rCompare.aAttribs.GetObject(n)) ) + return false; + } + + return true; + } + } + + return false; +} + +EditTextObject::EditTextObject( USHORT n) +{ + DBG_CTOR( EE_EditTextObject, 0 ); + nWhich = n; +} + +EditTextObject::EditTextObject( const EditTextObject& r ) +{ + DBG_CTOR( EE_EditTextObject, 0 ); + nWhich = r.nWhich; +} + +__EXPORT EditTextObject::~EditTextObject() +{ + DBG_DTOR( EE_EditTextObject, 0 ); +} + +USHORT EditTextObject::GetParagraphCount() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +XubString EditTextObject::GetText( USHORT /* nParagraph */ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return XubString(); +} + +void EditTextObject::Insert( const EditTextObject& /* rObj */, USHORT /* nPara */) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +EditTextObject* EditTextObject::CreateTextObject( USHORT /*nPara*/, USHORT /*nParas*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::RemoveParagraph( USHORT /*nPara*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::HasPortionInfo() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::ClearPortionInfo() +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::HasOnlineSpellErrors() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::HasCharAttribs( USHORT ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::GetCharAttribs( USHORT /*nPara*/, EECharAttribArray& /*rLst*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +void EditTextObject::MergeParaAttribs( const SfxItemSet& /*rAttribs*/, USHORT /*nStart*/, USHORT /*nEnd*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::IsFieldObject() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +const SvxFieldItem* EditTextObject::GetField() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +BOOL EditTextObject::HasField( TypeId /*aType*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +SfxItemSet EditTextObject::GetParaAttribs( USHORT /*nPara*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return SfxItemSet( *(SfxItemPool*)NULL ); +} + +void EditTextObject::SetParaAttribs( USHORT /*nPara*/, const SfxItemSet& /*rAttribs*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::RemoveCharAttribs( USHORT /*nWhich*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::RemoveParaAttribs( USHORT /*nWhich*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::HasStyleSheet( const XubString& /*rName*/, SfxStyleFamily /*eFamily*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::GetStyleSheet( USHORT /*nPara*/, XubString& /*rName*/, SfxStyleFamily& /*eFamily*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +void EditTextObject::SetStyleSheet( USHORT /*nPara*/, const XubString& /*rName*/, const SfxStyleFamily& /*eFamily*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL __EXPORT EditTextObject::ChangeStyleSheets( const XubString&, SfxStyleFamily, + const XubString&, SfxStyleFamily ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void __EXPORT EditTextObject::ChangeStyleSheetName( SfxStyleFamily /*eFamily*/, + const XubString& /*rOldName*/, const XubString& /*rNewName*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +USHORT EditTextObject::GetUserType() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::SetUserType( USHORT ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +ULONG EditTextObject::GetObjectSettings() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::SetObjectSettings( ULONG ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::IsVertical() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::SetVertical( BOOL bVertical ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + ((BinTextObject*)this)->SetVertical( bVertical ); +} + +USHORT EditTextObject::GetScriptType() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return ((const BinTextObject*)this)->GetScriptType(); +} + + +BOOL EditTextObject::Store( SvStream& rOStream ) const +{ + if ( rOStream.GetError() ) + return FALSE; + + // Vorspann: + sal_Size nStartPos = rOStream.Tell(); + + rOStream << (USHORT)Which(); + + sal_uInt32 nStructSz = 0; + rOStream << nStructSz; + + // Eigene Daten: + StoreData( rOStream ); + + // Nachspann: + sal_Size nEndPos = rOStream.Tell(); + nStructSz = nEndPos - nStartPos - sizeof( nWhich ) - sizeof( nStructSz ); + rOStream.Seek( nStartPos + sizeof( nWhich ) ); + rOStream << nStructSz; + rOStream.Seek( nEndPos ); + + return rOStream.GetError() ? FALSE : TRUE; +} + +EditTextObject* EditTextObject::Create( SvStream& rIStream, SfxItemPool* pGlobalTextObjectPool ) +{ + ULONG nStartPos = rIStream.Tell(); + + // Ertmal sehen, was fuer ein Object... + USHORT nWhich; + rIStream >> nWhich; + + sal_uInt32 nStructSz; + rIStream >> nStructSz; + + DBG_ASSERT( ( nWhich == 0x22 /*EE_FORMAT_BIN300*/ ) || ( nWhich == EE_FORMAT_BIN ), "CreateTextObject: Unbekanntes Objekt!" ); + + if ( rIStream.GetError() ) + return NULL; + + EditTextObject* pTxtObj = NULL; + switch ( nWhich ) + { + case 0x22 /*BIN300*/: pTxtObj = new BinTextObject( 0 ); + ((BinTextObject*)pTxtObj)->CreateData300( rIStream ); + break; + case EE_FORMAT_BIN: pTxtObj = new BinTextObject( pGlobalTextObjectPool ); + pTxtObj->CreateData( rIStream ); + break; + default: + { + // Wenn ich das Format nicht kenne, ueberlese ich den Inhalt: + rIStream.SetError( EE_READWRITE_WRONGFORMAT ); + } + } + + // Sicherstellen, dass der Stream an der richtigen Stelle hinterlassen wird. + sal_Size nFullSz = sizeof( nWhich ) + sizeof( nStructSz ) + nStructSz; + rIStream.Seek( nStartPos + nFullSz ); + return pTxtObj; +} + +void EditTextObject::Skip( SvStream& rIStream ) +{ + sal_Size nStartPos = rIStream.Tell(); + + USHORT _nWhich; + rIStream >> _nWhich; + + sal_uInt32 nStructSz; + rIStream >> nStructSz; + + sal_Size nFullSz = sizeof( _nWhich ) + sizeof( nStructSz ) + nStructSz; + rIStream.Seek( nStartPos + nFullSz ); +} + +void __EXPORT EditTextObject::StoreData( SvStream& ) const +{ + DBG_ERROR( "StoreData: Basisklasse!" ); +} + +void __EXPORT EditTextObject::CreateData( SvStream& ) +{ + DBG_ERROR( "CreateData: Basisklasse!" ); +} + +USHORT EditTextObject::GetVersion() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +bool EditTextObject::operator==( const EditTextObject& rCompare ) const +{ + return static_cast< const BinTextObject* >( this )->operator==( static_cast< const BinTextObject& >( rCompare ) ); +} + +// #i102062# +bool EditTextObject::isWrongListEqual(const EditTextObject& rCompare) const +{ + return static_cast< const BinTextObject* >(this)->isWrongListEqual(static_cast< const BinTextObject& >(rCompare)); +} + +// from SfxItemPoolUser +void BinTextObject::ObjectInDestruction(const SfxItemPool& rSfxItemPool) +{ + if(!bOwnerOfPool && pPool && pPool == &rSfxItemPool) + { + // The pool we are based on gets destructed; get owner of pool by creating own one. + // No need to call RemoveSfxItemPoolUser(), this is done from the pool's destructor + // Base new pool on EditEnginePool; it would also be possible to clone the used + // pool if needed, but only text attributes should be used. + SfxItemPool* pNewPool = EditEngine::CreatePool(); + + if(pPool) + { + pNewPool->SetDefaultMetric(pPool->GetMetric(DEF_METRIC)); + } + + for(sal_uInt16 n(0); n < aContents.Count(); n++) + { + // clone ContentInfos for new pool + ContentInfo* pOrg = aContents.GetObject(n); + DBG_ASSERT(pOrg, "NULL-Pointer in ContentList!"); + + ContentInfo* pNew = new ContentInfo(*pOrg, *pNewPool); + aContents.Replace(pNew, n); + delete pOrg; + } + + // set local variables + pPool = pNewPool; + bOwnerOfPool = TRUE; + } +} + +EditEngineItemPool* getEditEngineItemPool(SfxItemPool* pPool) +{ + EditEngineItemPool* pRetval = dynamic_cast< EditEngineItemPool* >(pPool); + + while(!pRetval && pPool && pPool->GetSecondaryPool()) + { + pPool = pPool->GetSecondaryPool(); + + if(pPool) + { + pRetval = dynamic_cast< EditEngineItemPool* >(pPool); + } + } + + return pRetval; +} + +BinTextObject::BinTextObject( SfxItemPool* pP ) : + EditTextObject( EE_FORMAT_BIN ), + SfxItemPoolUser() +{ + nVersion = 0; + nMetric = 0xFFFF; + nUserType = 0; + nObjSettings = 0; + pPortionInfo = 0; + + // #i101239# ensure target is a EditEngineItemPool, else + // fallback to pool ownership. This is needed to ensure that at + // pool destruction time of an alien pool, the pool is still alive. + // When registering would happen at an alien pool which just uses an + // EditEngineItemPool as some sub-pool, that pool could already + // be decoupled and deleted whcih would lead to crashes. + pPool = getEditEngineItemPool(pP); + + if ( pPool ) + { + bOwnerOfPool = FALSE; + } + else + { + pPool = EditEngine::CreatePool(); + bOwnerOfPool = TRUE; + } + + if(!bOwnerOfPool && pPool) + { + // it is sure now that the pool is an EditEngineItemPool + pPool->AddSfxItemPoolUser(*this); + } + + bVertical = FALSE; + bStoreUnicodeStrings = FALSE; + nScriptType = 0; +} + +BinTextObject::BinTextObject( const BinTextObject& r ) : + EditTextObject( r ), + SfxItemPoolUser() +{ + nVersion = r.nVersion; + nMetric = r.nMetric; + nUserType = r.nUserType; + nObjSettings = r.nObjSettings; + bVertical = r.bVertical; + nScriptType = r.nScriptType; + pPortionInfo = NULL; // PortionInfo nicht kopieren + bStoreUnicodeStrings = FALSE; + + if ( !r.bOwnerOfPool ) + { + // reuse alien pool; this must be a EditEngineItemPool + // since there is no other way to construct a BinTextObject + // than it's regular constructor where that is ensured + pPool = r.pPool; + bOwnerOfPool = FALSE; + } + else + { + pPool = EditEngine::CreatePool(); + bOwnerOfPool = TRUE; + + } + + if(!bOwnerOfPool && pPool) + { + // it is sure now that the pool is an EditEngineItemPool + pPool->AddSfxItemPoolUser(*this); + } + + if ( bOwnerOfPool && pPool && r.pPool ) + pPool->SetDefaultMetric( r.pPool->GetMetric( DEF_METRIC ) ); + + for ( USHORT n = 0; n < r.aContents.Count(); n++ ) + { + ContentInfo* pOrg = r.aContents.GetObject( n ); + DBG_ASSERT( pOrg, "NULL-Pointer in ContentList!" ); + ContentInfo* pNew = new ContentInfo( *pOrg, *pPool ); + aContents.Insert( pNew, aContents.Count() ); + } +} + +__EXPORT BinTextObject::~BinTextObject() +{ + if(!bOwnerOfPool && pPool) + { + pPool->RemoveSfxItemPoolUser(*this); + } + + ClearPortionInfo(); + DeleteContents(); + if ( bOwnerOfPool ) + { + // Nicht mehr, wegen 1xDefItems. + // siehe auch ~EditDoc(). +// pPool->ReleaseDefaults( TRUE /* bDelete */ ); + SfxItemPool::Free(pPool); + } +} + +USHORT BinTextObject::GetUserType() const +{ + return nUserType; +} + +void BinTextObject::SetUserType( USHORT n ) +{ + nUserType = n; +} + +ULONG BinTextObject::GetObjectSettings() const +{ + return nObjSettings; +} + +void BinTextObject::SetObjectSettings( ULONG n ) +{ + nObjSettings = n; +} + +BOOL BinTextObject::IsVertical() const +{ + return bVertical; +} + +void BinTextObject::SetVertical( BOOL b ) +{ + if ( b != bVertical ) + { + bVertical = b; + ClearPortionInfo(); + } +} + +USHORT BinTextObject::GetScriptType() const +{ + return nScriptType; +} + +void BinTextObject::SetScriptType( USHORT nType ) +{ + nScriptType = nType; +} + + +void BinTextObject::DeleteContents() +{ + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* p = aContents.GetObject( n ); + DBG_ASSERT( p, "NULL-Pointer in ContentList!" ); + delete p; + } + aContents.Remove( 0, aContents.Count() ); +} + +EditTextObject* __EXPORT BinTextObject::Clone() const +{ + return new BinTextObject( *this ); +} + +XEditAttribute* BinTextObject::CreateAttrib( const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ) +{ + return MakeXEditAttribute( *pPool, rItem, nStart, nEnd ); +} + +void BinTextObject::DestroyAttrib( XEditAttribute* pAttr ) +{ + pPool->Remove( *pAttr->GetItem() ); + delete pAttr; +} + +ContentInfo* BinTextObject::CreateAndInsertContent() +{ + ContentInfo* pC = new ContentInfo( *pPool ); + aContents.Insert( pC, aContents.Count() ); + return pC; +} + +USHORT BinTextObject::GetParagraphCount() const +{ + return aContents.Count(); +} + +XubString BinTextObject::GetText( USHORT nPara ) const +{ + DBG_ASSERT( nPara < aContents.Count(), "BinTextObject::GetText: Absatz existiert nicht!" ); + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + return pC->GetText(); + } + return XubString(); +} + +void BinTextObject::Insert( const EditTextObject& rObj, USHORT nDestPara ) +{ + DBG_ASSERT( rObj.Which() == EE_FORMAT_BIN, "UTO: Unbekanntes Textobjekt" ); + + const BinTextObject& rBinObj = (const BinTextObject&)rObj; + + if ( nDestPara > aContents.Count() ) + nDestPara = aContents.Count(); + + const USHORT nParas = rBinObj.GetContents().Count(); + for ( USHORT nP = 0; nP < nParas; nP++ ) + { + ContentInfo* pC = rBinObj.GetContents()[ nP ]; + ContentInfo* pNew = new ContentInfo( *pC, *GetPool() ); + aContents.Insert( pNew, nDestPara+nP ); + } + ClearPortionInfo(); +} + +EditTextObject* BinTextObject::CreateTextObject( USHORT nPara, USHORT nParas ) const +{ + if ( ( nPara >= aContents.Count() ) || !nParas ) + return NULL; + + // Pool nur teilen, wenn von aussen eingestellter Pool. + BinTextObject* pObj = new BinTextObject( bOwnerOfPool ? 0 : pPool ); + if ( bOwnerOfPool && pPool ) + pObj->GetPool()->SetDefaultMetric( pPool->GetMetric( DEF_METRIC ) ); + + // If complete text is only one ScriptType, this is valid. + // If text contains different ScriptTypes, this shouldn't be a problem... + pObj->nScriptType = nScriptType; + + const USHORT nEndPara = nPara+nParas-1; + for ( USHORT nP = nPara; nP <= nEndPara; nP++ ) + { + ContentInfo* pC = aContents[ nP ]; + ContentInfo* pNew = new ContentInfo( *pC, *pObj->GetPool() ); + pObj->GetContents().Insert( pNew, pObj->GetContents().Count() ); + } + return pObj; +} + +void BinTextObject::RemoveParagraph( USHORT nPara ) +{ + DBG_ASSERT( nPara < aContents.Count(), "BinTextObject::GetText: Absatz existiert nicht!" ); + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + aContents.Remove( nPara ); + delete pC; + ClearPortionInfo(); + } +} + +BOOL BinTextObject::HasPortionInfo() const +{ + return pPortionInfo ? TRUE : FALSE; +} + +void BinTextObject::ClearPortionInfo() +{ + if ( pPortionInfo ) + { + for ( USHORT n = pPortionInfo->Count(); n; ) + delete pPortionInfo->GetObject( --n ); + delete pPortionInfo; + pPortionInfo = NULL; + } +} + +BOOL BinTextObject::HasOnlineSpellErrors() const +{ +#ifndef SVX_LIGHT + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* p = aContents.GetObject( n ); + if ( p->GetWrongList() && p->GetWrongList()->Count() ) + return TRUE; + } +#endif // !SVX_LIGHT + return FALSE; + +} + +BOOL BinTextObject::HasCharAttribs( USHORT _nWhich ) const +{ + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + USHORT nAttribs = pC->GetAttribs().Count(); + if ( nAttribs && !_nWhich ) + return TRUE; + + for ( USHORT nAttr = nAttribs; nAttr; ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( --nAttr ); + if ( pX->GetItem()->Which() == _nWhich ) + return TRUE; + } + } + return FALSE; +} + +void BinTextObject::GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const +{ + rLst.Remove( 0, rLst.Count() ); + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( pC ) + { + for ( USHORT nAttr = 0; nAttr < pC->GetAttribs().Count(); nAttr++ ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( nAttr ); + EECharAttrib aEEAttr; + aEEAttr.pAttr = pAttr->GetItem(); + aEEAttr.nPara = nPara; + aEEAttr.nStart = pAttr->GetStart(); + aEEAttr.nEnd = pAttr->GetEnd(); + rLst.Insert( aEEAttr, rLst.Count() ); + } + } +} + +void BinTextObject::MergeParaAttribs( const SfxItemSet& rAttribs, USHORT nStart, USHORT nEnd ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + for ( USHORT nW = nStart; nW <= nEnd; nW++ ) + { + if ( ( pC->GetParaAttribs().GetItemState( nW, FALSE ) != SFX_ITEM_ON ) + && ( rAttribs.GetItemState( nW, FALSE ) == SFX_ITEM_ON ) ) + { + pC->GetParaAttribs().Put( rAttribs.Get( nW ) ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); +} + +BOOL BinTextObject::IsFieldObject() const +{ + return BinTextObject::GetField() ? TRUE : FALSE; +} + +const SvxFieldItem* BinTextObject::GetField() const +{ + if ( GetContents().Count() == 1 ) + { + ContentInfo* pC = GetContents()[0]; + if ( pC->GetText().Len() == 1 ) + { + USHORT nAttribs = pC->GetAttribs().Count(); + for ( USHORT nAttr = nAttribs; nAttr; ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( --nAttr ); + if ( pX->GetItem()->Which() == EE_FEATURE_FIELD ) + return (const SvxFieldItem*)pX->GetItem(); + } + } + } + return 0; +} + +BOOL BinTextObject::HasField( TypeId aType ) const +{ + USHORT nParagraphs = GetContents().Count(); + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nAttrs = pC->GetAttribs().Count(); + for ( USHORT nAttr = 0; nAttr < nAttrs; nAttr++ ) + { + XEditAttribute* pAttr = pC->GetAttribs()[nAttr]; + if ( pAttr->GetItem()->Which() == EE_FEATURE_FIELD ) + { + if ( !aType ) + return TRUE; + + const SvxFieldData* pFldData = ((const SvxFieldItem*)pAttr->GetItem())->GetField(); + if ( pFldData && pFldData->IsA( aType ) ) + return TRUE; + } + } + } + return FALSE; +} + +SfxItemSet BinTextObject::GetParaAttribs( USHORT nPara ) const +{ + ContentInfo* pC = GetContents().GetObject( nPara ); + return pC->GetParaAttribs(); +} + +void BinTextObject::SetParaAttribs( USHORT nPara, const SfxItemSet& rAttribs ) +{ + ContentInfo* pC = GetContents().GetObject( nPara ); + pC->GetParaAttribs().Set( rAttribs ); + ClearPortionInfo(); +} + +BOOL BinTextObject::RemoveCharAttribs( USHORT _nWhich ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + for ( USHORT nAttr = pC->GetAttribs().Count(); nAttr; ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( --nAttr ); + if ( !_nWhich || ( pAttr->GetItem()->Which() == _nWhich ) ) + { + pC->GetAttribs().Remove( nAttr ); + DestroyAttrib( pAttr ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); + + return bChanged; +} + +BOOL BinTextObject::RemoveParaAttribs( USHORT _nWhich ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + if ( !_nWhich ) + { + if( pC->GetParaAttribs().Count() ) + bChanged = TRUE; + pC->GetParaAttribs().ClearItem(); + } + else + { + if ( pC->GetParaAttribs().GetItemState( _nWhich ) == SFX_ITEM_ON ) + { + pC->GetParaAttribs().ClearItem( _nWhich ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); + + return bChanged; +} + +BOOL BinTextObject::HasStyleSheet( const XubString& rName, SfxStyleFamily eFamily ) const +{ + USHORT nParagraphs = GetContents().Count(); + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( ( pC->GetFamily() == eFamily ) && ( pC->GetStyle() == rName ) ) + return TRUE; + } + return FALSE; +} + +void BinTextObject::GetStyleSheet( USHORT nPara, XubString& rName, SfxStyleFamily& rFamily ) const +{ + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + rName = pC->GetStyle(); + rFamily = pC->GetFamily(); + } +} + +void BinTextObject::SetStyleSheet( USHORT nPara, const XubString& rName, const SfxStyleFamily& rFamily ) +{ + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + pC->GetStyle() = rName; + pC->GetFamily() = rFamily; + } +} + +BOOL BinTextObject::ImpChangeStyleSheets( + const XubString& rOldName, SfxStyleFamily eOldFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily ) +{ + const USHORT nParagraphs = GetContents().Count(); + BOOL bChanges = FALSE; + + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( pC->GetFamily() == eOldFamily ) + { + if ( pC->GetStyle() == rOldName ) + { + pC->GetStyle() = rNewName; + pC->GetFamily() = eNewFamily; + bChanges = TRUE; + } + } + } + return bChanges; +} + +BOOL __EXPORT BinTextObject::ChangeStyleSheets( + const XubString& rOldName, SfxStyleFamily eOldFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily ) +{ + BOOL bChanges = ImpChangeStyleSheets( rOldName, eOldFamily, rNewName, eNewFamily ); + if ( bChanges ) + ClearPortionInfo(); + + return bChanges; +} + +void __EXPORT BinTextObject::ChangeStyleSheetName( SfxStyleFamily eFamily, + const XubString& rOldName, const XubString& rNewName ) +{ + ImpChangeStyleSheets( rOldName, eFamily, rNewName, eFamily ); +} + +void __EXPORT BinTextObject::StoreData( SvStream& rOStream ) const +{ + USHORT nVer = 602; + rOStream << nVer; + + rOStream << bOwnerOfPool; + + // Erst den Pool speichern, spaeter nur noch Surregate + if ( bOwnerOfPool ) + { + GetPool()->SetFileFormatVersion( SOFFICE_FILEFORMAT_50 ); + GetPool()->Store( rOStream ); + } + + // Aktuelle Zeichensatz speichern... + // #90477# GetSOStoreTextEncoding: Bug in 5.2, when default char set is multi byte text encoding + rtl_TextEncoding eEncoding = GetSOStoreTextEncoding( gsl_getSystemTextEncoding(), (USHORT) rOStream.GetVersion() ); + rOStream << (USHORT) eEncoding; + + // Die Anzahl der Absaetze... + USHORT nParagraphs = GetContents().Count(); + rOStream << nParagraphs; + + char cFeatureConverted = ByteString( CH_FEATURE, eEncoding ).GetChar(0); + + // Die einzelnen Absaetze... + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + + // Text... + ByteString aText( pC->GetText(), eEncoding ); + + // Symbols? + BOOL bSymbolPara = FALSE; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + if ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + { + aText = ByteString( pC->GetText(), RTL_TEXTENCODING_SYMBOL ); + bSymbolPara = TRUE; + } + } + for ( USHORT nA = 0; nA < pC->GetAttribs().Count(); nA++ ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( nA ); + + if ( pAttr->GetItem()->Which() == EE_CHAR_FONTINFO ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)*pAttr->GetItem(); + if ( ( !bSymbolPara && ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + || ( bSymbolPara && ( rFontItem.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) ) + { + // Not correctly converted + String aPart( pC->GetText(), pAttr->GetStart(), pAttr->GetEnd() - pAttr->GetStart() ); + ByteString aNew( aPart, rFontItem.GetCharSet() ); + aText.Erase( pAttr->GetStart(), pAttr->GetEnd() - pAttr->GetStart() ); + aText.Insert( aNew, pAttr->GetStart() ); + } + + // #88414# Convert StarSymbol back to StarBats + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + // Don't create a new Attrib with StarBats font, MBR changed the + // SvxFontItem::Store() to store StarBats instead of StarSymbol! + for ( USHORT nChar = pAttr->GetStart(); nChar < pAttr->GetEnd(); nChar++ ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + char cConv = ByteString::ConvertFromUnicode( ConvertFontToSubsFontChar( hConv, cOld ), RTL_TEXTENCODING_SYMBOL ); + if ( cConv ) + aText.SetChar( nChar, cConv ); + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + // #88414# Convert StarSymbol back to StarBats + // StarSymbol as paragraph attribute or in StyleSheet? + + FontToSubsFontConverter hConv = NULL; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + hConv = CreateFontToSubsFontConverter( ((const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO )).GetFamilyName(), FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + } +/* cl removed because not needed anymore since binfilter + + else if ( pC->GetStyle().Len() && pC->GetLoadStoreTempInfos() ) + { + hConv = pC->GetLoadStoreTempInfos()->hOldSymbolConv_Store; + } +*/ + if ( hConv ) + { + for ( USHORT nChar = 0; nChar < pC->GetText().Len(); nChar++ ) + { + if ( !pC->GetAttribs().FindAttrib( EE_CHAR_FONTINFO, nChar ) ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + char cConv = ByteString::ConvertFromUnicode( ConvertFontToSubsFontChar( hConv, cOld ), RTL_TEXTENCODING_SYMBOL ); + if ( cConv ) + aText.SetChar( nChar, cConv ); + } + } + + DestroyFontToSubsFontConverter( hConv ); + + } + + + // Convert CH_FEATURE to CH_FEATURE_OLD + aText.SearchAndReplaceAll( cFeatureConverted, CH_FEATURE_OLD ); + rOStream.WriteByteString( aText ); + + // StyleName und Family... + rOStream.WriteByteString( ByteString( pC->GetStyle(), eEncoding ) ); + rOStream << (USHORT)pC->GetFamily(); + + // Absatzattribute... + pC->GetParaAttribs().Store( rOStream ); + + // Die Anzahl der Attribute... + USHORT nAttribs = pC->GetAttribs().Count(); + rOStream << nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); + + rOStream << pX->GetItem()->Which(); + GetPool()->StoreSurrogate( rOStream, pX->GetItem() ); + rOStream << pX->GetStart(); + rOStream << pX->GetEnd(); + } + } + + // Ab 400: + rOStream << nMetric; + + // Ab 600 + rOStream << nUserType; + rOStream << nObjSettings; + + // Ab 601 + rOStream << bVertical; + + // Ab 602 + rOStream << nScriptType; + + rOStream << bStoreUnicodeStrings; + if ( bStoreUnicodeStrings ) + { + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nL = pC->GetText().Len(); + rOStream << nL; + rOStream.Write( pC->GetText().GetBuffer(), nL*sizeof(sal_Unicode) ); + + // #91575# StyleSheetName must be Unicode too! + // Copy/Paste from EA3 to BETA or from BETA to EA3 not possible, not needed... + // If needed, change nL back to ULONG and increase version... + nL = pC->GetStyle().Len(); + rOStream << nL; + rOStream.Write( pC->GetStyle().GetBuffer(), nL*sizeof(sal_Unicode) ); + } + } +} + +void __EXPORT BinTextObject::CreateData( SvStream& rIStream ) +{ + rIStream >> nVersion; + + // Das Textobject wurde erstmal mit der aktuellen Einstellung + // von pTextObjectPool erzeugt. + BOOL bOwnerOfCurrent = bOwnerOfPool; + rIStream >> bOwnerOfPool; + + if ( bOwnerOfCurrent && !bOwnerOfPool ) + { + // Es wurde ein globaler Pool verwendet, mir jetzt nicht uebergeben, + // aber ich brauche ihn! + DBG_ERROR( "Man gebe mir den globalen TextObjectPool!" ); + return; + } + else if ( !bOwnerOfCurrent && bOwnerOfPool ) + { + // Es soll ein globaler Pool verwendet werden, aber dieses + // Textobject hat einen eigenen. + pPool = EditEngine::CreatePool(); + } + + if ( bOwnerOfPool ) + GetPool()->Load( rIStream ); + + // CharSet, in dem gespeichert wurde: + USHORT nCharSet; + rIStream >> nCharSet; + + rtl_TextEncoding eSrcEncoding = GetSOLoadTextEncoding( (rtl_TextEncoding)nCharSet, (USHORT)rIStream.GetVersion() ); + + // Die Anzahl der Absaetze... + USHORT nParagraphs; + rIStream >> nParagraphs; + + // Die einzelnen Absaetze... + for ( ULONG nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = CreateAndInsertContent(); + + // Der Text... + ByteString aByteString; + rIStream.ReadByteString( aByteString ); + pC->GetText() = String( aByteString, eSrcEncoding ); + + // StyleName und Family... + rIStream.ReadByteString( pC->GetStyle(), eSrcEncoding ); + USHORT nStyleFamily; + rIStream >> nStyleFamily; + pC->GetFamily() = (SfxStyleFamily)nStyleFamily; + + // Absatzattribute... + pC->GetParaAttribs().Load( rIStream ); + + // Die Anzahl der Attribute... + USHORT nAttribs; + rIStream >> nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + USHORT nAttr; + for ( nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + USHORT _nWhich, nStart, nEnd; + const SfxPoolItem* pItem; + + rIStream >> _nWhich; + _nWhich = pPool->GetNewWhich( _nWhich ); + pItem = pPool->LoadSurrogate( rIStream, _nWhich, 0 ); + rIStream >> nStart; + rIStream >> nEnd; + if ( pItem ) + { + if ( pItem->Which() == EE_FEATURE_NOTCONV ) + { + pC->GetText().SetChar( nStart, ByteString::ConvertToUnicode( aByteString.GetChar( nStart ), ((SvxCharSetColorItem*)pItem)->GetCharSet() ) ); + } + else + { + XEditAttribute* pAttr = new XEditAttribute( *pItem, nStart, nEnd ); + pC->GetAttribs().Insert( pAttr, pC->GetAttribs().Count() ); + + if ( ( _nWhich >= EE_FEATURE_START ) && ( _nWhich <= EE_FEATURE_END ) ) + { + // Convert CH_FEATURE to CH_FEATURE_OLD + DBG_ASSERT( (BYTE) aByteString.GetChar( nStart ) == CH_FEATURE_OLD, "CreateData: CH_FEATURE expected!" ); + if ( (BYTE) aByteString.GetChar( nStart ) == CH_FEATURE_OLD ) + pC->GetText().SetChar( nStart, CH_FEATURE ); + } + } + } + } + + // But check for paragraph and character symbol attribs here, + // FinishLoad will not be called in OpenOffice Calc, no StyleSheets... + + BOOL bSymbolPara = FALSE; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + if ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + { + pC->GetText() = String( aByteString, RTL_TEXTENCODING_SYMBOL ); + bSymbolPara = TRUE; + } + } + + for ( nAttr = pC->GetAttribs().Count(); nAttr; ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( --nAttr ); + if ( pAttr->GetItem()->Which() == EE_CHAR_FONTINFO ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)*pAttr->GetItem(); + if ( ( !bSymbolPara && ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + || ( bSymbolPara && ( rFontItem.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) ) + { + // Not correctly converted + ByteString aPart( aByteString, pAttr->GetStart(), pAttr->GetEnd()-pAttr->GetStart() ); + String aNew( aPart, rFontItem.GetCharSet() ); + pC->GetText().Erase( pAttr->GetStart(), pAttr->GetEnd()-pAttr->GetStart() ); + pC->GetText().Insert( aNew, pAttr->GetStart() ); + } + + // #88414# Convert StarMath and StarBats to StarSymbol + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + SvxFontItem aNewFontItem( rFontItem ); + aNewFontItem.GetFamilyName() = GetFontToSubsFontName( hConv ); + + pC->GetAttribs().Remove( nAttr ); + XEditAttribute* pNewAttr = CreateAttrib( aNewFontItem, pAttr->GetStart(), pAttr->GetEnd() ); + pC->GetAttribs().Insert( pNewAttr, nAttr ); + DestroyAttrib( pAttr ); + + for ( USHORT nChar = pNewAttr->GetStart(); nChar < pNewAttr->GetEnd(); nChar++ ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + DBG_ASSERT( cOld >= 0xF000, "cOld not converted?!" ); + sal_Unicode cConv = ConvertFontToSubsFontChar( hConv, cOld ); + if ( cConv ) + pC->GetText().SetChar( nChar, cConv ); + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + + // #88414# Convert StarMath and StarBats to StarSymbol + // Maybe old symbol font as paragraph attribute? + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + SvxFontItem aNewFontItem( rFontItem ); + aNewFontItem.GetFamilyName() = GetFontToSubsFontName( hConv ); + pC->GetParaAttribs().Put( aNewFontItem ); + + for ( USHORT nChar = 0; nChar < pC->GetText().Len(); nChar++ ) + { + if ( !pC->GetAttribs().FindAttrib( EE_CHAR_FONTINFO, nChar ) ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + DBG_ASSERT( cOld >= 0xF000, "cOld not converted?!" ); + sal_Unicode cConv = ConvertFontToSubsFontChar( hConv, cOld ); + if ( cConv ) + pC->GetText().SetChar( nChar, cConv ); + } + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + // Ab 400 auch die DefMetric: + if ( nVersion >= 400 ) + { + USHORT nTmpMetric; + rIStream >> nTmpMetric; + if ( nVersion >= 401 ) + { + // In der 400 gab es noch einen Bug bei Textobjekten mit eigenem + // Pool, deshalb erst ab 401 auswerten. + nMetric = nTmpMetric; + if ( bOwnerOfPool && pPool && ( nMetric != 0xFFFF ) ) + pPool->SetDefaultMetric( (SfxMapUnit)nMetric ); + } + } + + if ( nVersion >= 600 ) + { + rIStream >> nUserType; + rIStream >> nObjSettings; + } + + if ( nVersion >= 601 ) + { + rIStream >> bVertical; + } + + if ( nVersion >= 602 ) + { + rIStream >> nScriptType; + + BOOL bUnicodeStrings; + rIStream >> bUnicodeStrings; + if ( bUnicodeStrings ) + { + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nL; + + // Text + rIStream >> nL; + if ( nL ) + { + pC->GetText().AllocBuffer( nL ); + rIStream.Read( pC->GetText().GetBufferAccess(), nL*sizeof(sal_Unicode) ); + pC->GetText().ReleaseBufferAccess( (USHORT)nL ); + } + + // StyleSheetName + rIStream >> nL; + if ( nL ) + { + pC->GetStyle().AllocBuffer( nL ); + rIStream.Read( pC->GetStyle().GetBufferAccess(), nL*sizeof(sal_Unicode) ); + pC->GetStyle().ReleaseBufferAccess( (USHORT)nL ); + } + } + } + } + + + // Ab 500 werden die Tabs anders interpretiert: TabPos + LI, vorher nur TabPos. + // Wirkt nur wenn auch Tab-Positionen eingestellt wurden, nicht beim DefTab. + if ( nVersion < 500 ) + { + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* pC = aContents.GetObject( n ); + const SvxLRSpaceItem& rLRSpace = (const SvxLRSpaceItem&) pC->GetParaAttribs().Get( EE_PARA_LRSPACE ); + if ( rLRSpace.GetTxtLeft() && ( pC->GetParaAttribs().GetItemState( EE_PARA_TABS ) == SFX_ITEM_ON ) ) + { + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) pC->GetParaAttribs().Get( EE_PARA_TABS ); + SvxTabStopItem aNewTabs( 0, 0, SVX_TAB_ADJUST_LEFT, EE_PARA_TABS ); + for ( USHORT t = 0; t < rTabs.Count(); t++ ) + { + const SvxTabStop& rT = rTabs[ t ]; + aNewTabs.Insert( SvxTabStop( rT.GetTabPos() - rLRSpace.GetTxtLeft(), + rT.GetAdjustment(), rT.GetDecimal(), rT.GetFill() ) ); + } + pC->GetParaAttribs().Put( aNewTabs ); + } + } + } +} + +USHORT BinTextObject::GetVersion() const +{ + return nVersion; +} + +bool BinTextObject::operator==( const BinTextObject& rCompare ) const +{ + if( this == &rCompare ) + return true; + + if( ( aContents.Count() != rCompare.aContents.Count() ) || + ( pPool != rCompare.pPool ) || + ( nMetric != rCompare.nMetric ) || + ( nUserType!= rCompare.nUserType ) || + ( nScriptType != rCompare.nScriptType ) || + ( bVertical != rCompare.bVertical ) ) + return false; + + USHORT n; + for( n = 0; n < aContents.Count(); n++ ) + { + if( !( *aContents.GetObject( n ) == *rCompare.aContents.GetObject( n ) ) ) + return false; + } + + return true; +} + +// #i102062# +bool BinTextObject::isWrongListEqual(const BinTextObject& rCompare) const +{ + if(GetContents().Count() != rCompare.GetContents().Count()) + { + return false; + } + + for(USHORT a(0); a < GetContents().Count(); a++) + { + const ContentInfo& rCandA(*GetContents().GetObject(a)); + const ContentInfo& rCandB(*rCompare.GetContents().GetObject(a)); + + if(!rCandA.isWrongListEqual(rCandB)) + { + return false; + } + } + + return true; +} + +#define CHARSETMARKER 0x9999 + +void __EXPORT BinTextObject::CreateData300( SvStream& rIStream ) +{ + // Fuer Aufwaertskompatibilitaet. + + // Erst den Pool laden... + // Ist in der 300 immer gespeichert worden! + GetPool()->Load( rIStream ); + + // Die Anzahl der Absaetze... + sal_uInt32 nParagraphs; + rIStream >> nParagraphs; + + // Die einzelnen Absaetze... + for ( ULONG nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = CreateAndInsertContent(); + + // Der Text... + rIStream.ReadByteString( pC->GetText() ); + + // StyleName und Family... + rIStream.ReadByteString( pC->GetStyle() ); + USHORT nStyleFamily; + rIStream >> nStyleFamily; + pC->GetFamily() = (SfxStyleFamily)nStyleFamily; + + // Absatzattribute... + pC->GetParaAttribs().Load( rIStream ); + + // Die Anzahl der Attribute... + sal_uInt32 nAttribs; + rIStream >> nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + for ( ULONG nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + USHORT _nWhich, nStart, nEnd; + const SfxPoolItem* pItem; + + rIStream >> _nWhich; + _nWhich = pPool->GetNewWhich( _nWhich ); + pItem = pPool->LoadSurrogate( rIStream, _nWhich, 0 ); + rIStream >> nStart; + rIStream >> nEnd; + if ( pItem ) + { + XEditAttribute* pAttr = new XEditAttribute( *pItem, nStart, nEnd ); + pC->GetAttribs().Insert( pAttr, pC->GetAttribs().Count() ); + } + } + } + + // Prueffen, ob ein Zeichensatz gespeichert wurde + USHORT nCharSetMarker; + rIStream >> nCharSetMarker; + if ( nCharSetMarker == CHARSETMARKER ) + { + USHORT nCharSet; + rIStream >> nCharSet; + } +} diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx new file mode 100644 index 000000000000..6ef3ce359d49 --- /dev/null +++ b/editeng/source/editeng/editobj2.hxx @@ -0,0 +1,309 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITOBJ2_HXX +#define _EDITOBJ2_HXX + +#include <editeng/editobj.hxx> +#include <editdoc.hxx> + +#include <unotools/fontcvt.hxx> + + +class SfxStyleSheetPool; + +class XEditAttribute +{ + friend class ContentInfo; // fuer DTOR + friend class BinTextObject; // fuer DTOR + +private: + const SfxPoolItem* pItem; + USHORT nStart; + USHORT nEnd; + + XEditAttribute(); + XEditAttribute( const XEditAttribute& rCopyFrom ); + + ~XEditAttribute(); + +public: + XEditAttribute( const SfxPoolItem& rAttr ); + XEditAttribute( const SfxPoolItem& rAttr, USHORT nStart, USHORT nEnd ); + + const SfxPoolItem* GetItem() const { return pItem; } + + USHORT& GetStart() { return nStart; } + USHORT& GetEnd() { return nEnd; } + + USHORT GetStart() const { return nStart; } + USHORT GetEnd() const { return nEnd; } + + USHORT GetLen() const { return nEnd-nStart; } + + inline BOOL IsFeature(); + + inline bool operator==( const XEditAttribute& rCompare ); +}; + +inline bool XEditAttribute::operator==( const XEditAttribute& rCompare ) +{ + return (nStart == rCompare.nStart) && + (nEnd == rCompare.nEnd) && + ( (pItem == rCompare.pItem) || + ( pItem->Which() != rCompare.pItem->Which()) || + (*pItem == *rCompare.pItem)); +} + +inline BOOL XEditAttribute::IsFeature() +{ + USHORT nWhich = pItem->Which(); + return ( ( nWhich >= EE_FEATURE_START ) && + ( nWhich <= EE_FEATURE_END ) ); +} + +typedef XEditAttribute* XEditAttributePtr; +SV_DECL_PTRARR( XEditAttributeListImpl, XEditAttributePtr, 0, 4 ) + +class XEditAttributeList : public XEditAttributeListImpl +{ +public: + XEditAttribute* FindAttrib( USHORT nWhich, USHORT nChar ) const; +}; + +struct XParaPortion +{ + long nHeight; + USHORT nFirstLineOffset; + + EditLineList aLines; + TextPortionList aTextPortions; +}; + +typedef XParaPortion* XParaPortionPtr; +SV_DECL_PTRARR( XBaseParaPortionList, XParaPortionPtr, 0, 4 ) + +class XParaPortionList : public XBaseParaPortionList +{ + ULONG nRefDevPtr; + OutDevType eRefDevType; + MapMode aRefMapMode; + ULONG nPaperWidth; + + +public: + XParaPortionList( OutputDevice* pRefDev, ULONG nPW ) : + aRefMapMode( pRefDev->GetMapMode() ) + { + nRefDevPtr = (ULONG)pRefDev; nPaperWidth = nPW; + eRefDevType = pRefDev->GetOutDevType(); + } + + ULONG GetRefDevPtr() const { return nRefDevPtr; } + ULONG GetPaperWidth() const { return nPaperWidth; } + OutDevType GetRefDevType() const { return eRefDevType; } + const MapMode& GetRefMapMode() const { return aRefMapMode; } +}; + +/* cl removed because not needed anymore since binfilter +struct LoadStoreTempInfos +{ + ByteString aOrgString_Load; + + FontToSubsFontConverter hOldSymbolConv_Store; + BOOL bSymbolParagraph_Store; + + + LoadStoreTempInfos() { bSymbolParagraph_Store = FALSE; hOldSymbolConv_Store = NULL; } +}; +*/ + +class ContentInfo +{ + friend class BinTextObject; + +private: + String aText; + String aStyle; + XEditAttributeList aAttribs; + SfxStyleFamily eFamily; + SfxItemSet aParaAttribs; + WrongList* pWrongs; + +/* cl removed because not needed anymore since binfilter + LoadStoreTempInfos* pTempLoadStoreInfos; +*/ + + ContentInfo( SfxItemPool& rPool ); + ContentInfo( const ContentInfo& rCopyFrom, SfxItemPool& rPoolToUse ); + +public: + ~ContentInfo(); + + const String& GetText() const { return aText; } + const String& GetStyle() const { return aStyle; } + const XEditAttributeList& GetAttribs() const { return aAttribs; } + const SfxItemSet& GetParaAttribs() const { return aParaAttribs; } + SfxStyleFamily GetFamily() const { return eFamily; } + + String& GetText() { return aText; } + String& GetStyle() { return aStyle; } + XEditAttributeList& GetAttribs() { return aAttribs; } + SfxItemSet& GetParaAttribs() { return aParaAttribs; } + SfxStyleFamily& GetFamily() { return eFamily; } + + WrongList* GetWrongList() const { return pWrongs; } + void SetWrongList( WrongList* p ) { pWrongs = p; } + bool operator==( const ContentInfo& rCompare ) const; + + // #i102062# + bool isWrongListEqual(const ContentInfo& rCompare) const; +}; + +typedef ContentInfo* ContentInfoPtr; +SV_DECL_PTRARR( ContentInfoList, ContentInfoPtr, 1, 4 ) + +// MT 05/00: Sollte mal direkt EditTextObjekt werden => keine virtuellen Methoden mehr. + +class BinTextObject : public EditTextObject, public SfxItemPoolUser +{ + using EditTextObject::operator==; + using EditTextObject::isWrongListEqual; + +private: + ContentInfoList aContents; + SfxItemPool* pPool; + BOOL bOwnerOfPool; + XParaPortionList* pPortionInfo; + + sal_uInt32 nObjSettings; + USHORT nMetric; + USHORT nVersion; + USHORT nUserType; + USHORT nScriptType; + + BOOL bVertical; + BOOL bStoreUnicodeStrings; + +protected: + void DeleteContents(); + virtual void StoreData( SvStream& rOStream ) const; + virtual void CreateData( SvStream& rIStream ); + BOOL ImpChangeStyleSheets( const String& rOldName, SfxStyleFamily eOldFamily, + const String& rNewName, SfxStyleFamily eNewFamily ); + +public: + BinTextObject( SfxItemPool* pPool ); + BinTextObject( const BinTextObject& ); + virtual ~BinTextObject(); + + virtual EditTextObject* Clone() const; + + USHORT GetUserType() const; + void SetUserType( USHORT n ); + + ULONG GetObjectSettings() const; + void SetObjectSettings( ULONG n ); + + BOOL IsVertical() const; + void SetVertical( BOOL b ); + + USHORT GetScriptType() const; + void SetScriptType( USHORT nType ); + + USHORT GetVersion() const; // Solange der Outliner keine Recordlaenge speichert + + ContentInfo* CreateAndInsertContent(); + XEditAttribute* CreateAttrib( const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ); + void DestroyAttrib( XEditAttribute* pAttr ); + + ContentInfoList& GetContents() { return aContents; } + const ContentInfoList& GetContents() const { return aContents; } + SfxItemPool* GetPool() const { return pPool; } + XParaPortionList* GetPortionInfo() const { return pPortionInfo; } + void SetPortionInfo( XParaPortionList* pP ) + { pPortionInfo = pP; } + + virtual USHORT GetParagraphCount() const; + virtual String GetText( USHORT nParagraph ) const; + virtual void Insert( const EditTextObject& rObj, USHORT nPara ); + virtual EditTextObject* CreateTextObject( USHORT nPara, USHORT nParas = 1 ) const; + virtual void RemoveParagraph( USHORT nPara ); + + virtual BOOL HasPortionInfo() const; + virtual void ClearPortionInfo(); + + virtual BOOL HasOnlineSpellErrors() const; + + virtual BOOL HasCharAttribs( USHORT nWhich = 0 ) const; + virtual void GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const; + + virtual BOOL RemoveCharAttribs( USHORT nWhich = 0 ); + virtual BOOL RemoveParaAttribs( USHORT nWhich = 0 ); + + virtual void MergeParaAttribs( const SfxItemSet& rAttribs, USHORT nStart, USHORT nEnd ); + + virtual BOOL IsFieldObject() const; + virtual const SvxFieldItem* GetField() const; + virtual BOOL HasField( TypeId Type = NULL ) const; + + SfxItemSet GetParaAttribs( USHORT nPara ) const; + void SetParaAttribs( USHORT nPara, const SfxItemSet& rAttribs ); + + virtual BOOL HasStyleSheet( const XubString& rName, SfxStyleFamily eFamily ) const; + virtual void GetStyleSheet( USHORT nPara, XubString& rName, SfxStyleFamily& eFamily ) const; + virtual void SetStyleSheet( USHORT nPara, const XubString& rName, const SfxStyleFamily& eFamily ); + virtual BOOL ChangeStyleSheets( const XubString& rOldName, SfxStyleFamily eOldFamily, + const String& rNewName, SfxStyleFamily eNewFamily ); + virtual void ChangeStyleSheetName( SfxStyleFamily eFamily, const XubString& rOldName, const XubString& rNewName ); + + void CreateData300( SvStream& rIStream ); + + BOOL HasMetric() const { return nMetric != 0xFFFF; } + USHORT GetMetric() const { return nMetric; } + void SetMetric( USHORT n ) { nMetric = n; } + + BOOL IsOwnerOfPool() const { return bOwnerOfPool; } + void StoreUnicodeStrings( BOOL b ) { bStoreUnicodeStrings = b; } + +/* cl removed because not needed anymore since binfilter + void PrepareStore( SfxStyleSheetPool* pStyleSheetPool ); + void FinishStore(); + void FinishLoad( SfxStyleSheetPool* pStyleSheetPool ); +*/ + + bool operator==( const BinTextObject& rCompare ) const; + + // #i102062# + bool isWrongListEqual(const BinTextObject& rCompare) const; + + // from SfxItemPoolUser + virtual void ObjectInDestruction(const SfxItemPool& rSfxItemPool); +}; + +#endif // _EDITOBJ2_HXX + diff --git a/editeng/source/editeng/editsel.cxx b/editeng/source/editeng/editsel.cxx new file mode 100644 index 000000000000..3ea9e9b3e290 --- /dev/null +++ b/editeng/source/editeng/editsel.cxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <editsel.hxx> +#include <impedit.hxx> +#include <editeng/editview.hxx> + +// ---------------------------------------------------------------------- +// class EditSelFunctionSet +// ---------------------------------------------------------------------- +EditSelFunctionSet::EditSelFunctionSet() +{ + pCurView = NULL; +} + +void __EXPORT EditSelFunctionSet::CreateAnchor() +{ + if ( pCurView ) + pCurView->pImpEditView->CreateAnchor(); +} + +void __EXPORT EditSelFunctionSet::DestroyAnchor() +{ + // Nur bei Mehrfachselektion +} + +BOOL __EXPORT EditSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, BOOL ) +{ + if ( pCurView ) + return pCurView->pImpEditView->SetCursorAtPoint( rPointPixel ); + + return FALSE; +} + +BOOL __EXPORT EditSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) +{ + if ( pCurView ) + return pCurView->pImpEditView->IsSelectionAtPoint( rPointPixel ); + + return FALSE; +} + +void __EXPORT EditSelFunctionSet::DeselectAtPoint( const Point& ) +{ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// ! Implementieren, wenn Mehrfachselektion moeglich ! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +} + +void __EXPORT EditSelFunctionSet::BeginDrag() +{ + // Nur bei Mehrfachselektion +} + + +void __EXPORT EditSelFunctionSet::DeselectAll() +{ + if ( pCurView ) + pCurView->pImpEditView->DeselectAll(); +} + +// ---------------------------------------------------------------------- +// class EditSelectionEngine +// ---------------------------------------------------------------------- +EditSelectionEngine::EditSelectionEngine() : SelectionEngine( (Window*)0 ) +{ + // Wegen Bug OV: (1994) + // 1995: RangeSelection lassen, SingleSelection nur fuer ListBoxen geeignet! + SetSelectionMode( RANGE_SELECTION ); + EnableDrag( TRUE ); +} + +void EditSelectionEngine::SetCurView( EditView* pNewView ) +{ + if ( GetFunctionSet() ) + ((EditSelFunctionSet*)GetFunctionSet())->SetCurView( pNewView ); + + if ( pNewView ) + SetWindow( pNewView->GetWindow() ); + else + SetWindow( (Window*)0 ); +} + +EditView* EditSelectionEngine::GetCurView() +{ + EditView* pView = 0; + if ( GetFunctionSet() ) + pView = ((EditSelFunctionSet*)GetFunctionSet())->GetCurView(); + + return pView; +} + diff --git a/editeng/source/editeng/editsel.hxx b/editeng/source/editeng/editsel.hxx new file mode 100644 index 000000000000..e4d5b9d71b05 --- /dev/null +++ b/editeng/source/editeng/editsel.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITSEL_HXX +#define _EDITSEL_HXX + +#include <vcl/seleng.hxx> + +class EditView; + +// ---------------------------------------------------------------------- +// class EditSelFunctionSet +// ---------------------------------------------------------------------- +class EditSelFunctionSet: public FunctionSet +{ +private: + EditView* pCurView; + +public: + EditSelFunctionSet(); + + virtual void BeginDrag(); + + virtual void CreateAnchor(); + virtual void DestroyAnchor(); + + virtual BOOL SetCursorAtPoint( const Point& rPointPixel, BOOL bDontSelectAtCursor = FALSE ); + + virtual BOOL IsSelectionAtPoint( const Point& rPointPixel ); + virtual void DeselectAtPoint( const Point& rPointPixel ); + virtual void DeselectAll(); + + void SetCurView( EditView* pView ) { pCurView = pView; } + EditView* GetCurView() { return pCurView; } +}; + +// ---------------------------------------------------------------------- +// class EditSelectionEngine +// ---------------------------------------------------------------------- +class EditSelectionEngine : public SelectionEngine +{ +private: + +public: + EditSelectionEngine(); + + void SetCurView( EditView* pNewView ); + EditView* GetCurView(); +}; + +#endif // _EDITSEL_HXX diff --git a/editeng/source/editeng/editstt2.hxx b/editeng/source/editeng/editstt2.hxx new file mode 100644 index 000000000000..40c53634b5ce --- /dev/null +++ b/editeng/source/editeng/editstt2.hxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITSTT2_HXX +#define _EDITSTT2_HXX + +#include <editeng/editstat.hxx> + +class InternalEditStatus : public EditStatus +{ + +public: + InternalEditStatus() { ; } + + void TurnOnFlags( ULONG nFlags ) + { nControlBits |= nFlags; } + + void TurnOffFlags( ULONG nFlags ) + { nControlBits &= ~nFlags; } + + void TurnOnStatusBits( ULONG nBits ) + { nStatusBits |= nBits; } + + void TurnOffStatusBits( ULONG nBits ) + { nStatusBits &= ~nBits; } + + + BOOL UseCharAttribs() const + { return ( ( nControlBits & EE_CNTRL_USECHARATTRIBS ) != 0 ); } + + BOOL NotifyCursorMovements() const + { return ( ( nControlBits & EE_CNTRL_CRSRLEFTPARA ) != 0 ); } + + BOOL UseIdleFormatter() const + { return ( ( nControlBits & EE_CNTRL_DOIDLEFORMAT) != 0 ); } + + BOOL AllowPasteSpecial() const + { return ( ( nControlBits & EE_CNTRL_PASTESPECIAL ) != 0 ); } + + BOOL DoAutoIndenting() const + { return ( ( nControlBits & EE_CNTRL_AUTOINDENTING ) != 0 ); } + + BOOL DoUndoAttribs() const + { return ( ( nControlBits & EE_CNTRL_UNDOATTRIBS ) != 0 ); } + + BOOL OneCharPerLine() const + { return ( ( nControlBits & EE_CNTRL_ONECHARPERLINE ) != 0 ); } + + BOOL IsOutliner() const + { return ( ( nControlBits & EE_CNTRL_OUTLINER ) != 0 ); } + + BOOL IsOutliner2() const + { return ( ( nControlBits & EE_CNTRL_OUTLINER2 ) != 0 ); } + + BOOL IsAnyOutliner() const + { return IsOutliner() || IsOutliner2(); } + + BOOL DoNotUseColors() const + { return ( ( nControlBits & EE_CNTRL_NOCOLORS ) != 0 ); } + + BOOL AllowBigObjects() const + { return ( ( nControlBits & EE_CNTRL_ALLOWBIGOBJS ) != 0 ); } + + BOOL DoOnlineSpelling() const + { return ( ( nControlBits & EE_CNTRL_ONLINESPELLING ) != 0 ); } + + BOOL DoStretch() const + { return ( ( nControlBits & EE_CNTRL_STRETCHING ) != 0 ); } + + BOOL AutoPageSize() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZE ) != 0 ); } + BOOL AutoPageWidth() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZEX ) != 0 ); } + BOOL AutoPageHeight() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZEY ) != 0 ); } + + BOOL MarkFields() const + { return ( ( nControlBits & EE_CNTRL_MARKFIELDS ) != 0 ); } + + BOOL DoRestoreFont() const + { return ( ( nControlBits & EE_CNTRL_RESTOREFONT ) != 0 ); } + + BOOL DoImportRTFStyleSheets() const + { return ( ( nControlBits & EE_CNTRL_RTFSTYLESHEETS ) != 0 ); } + + BOOL DoAutoCorrect() const + { return ( ( nControlBits & EE_CNTRL_AUTOCORRECT ) != 0 ); } + + BOOL DoAutoComplete() const + { return ( ( nControlBits & EE_CNTRL_AUTOCOMPLETE ) != 0 ); } + + BOOL DoTabIndenting() const + { return ( ( nControlBits & EE_CNTRL_TABINDENTING ) != 0 ); } + + BOOL DoFormat100() const + { return ( ( nControlBits & EE_CNTRL_FORMAT100 ) != 0 ); } + + BOOL ULSpaceSummation() const + { return ( ( nControlBits & EE_CNTRL_ULSPACESUMMATION ) != 0 ); } + + BOOL ULSpaceFirstParagraph() const + { return ( ( nControlBits & EE_CNTRL_ULSPACEFIRSTPARA ) != 0 ); } +}; + +#endif // _EDITSTT2_HXX + diff --git a/editeng/source/editeng/editundo.cxx b/editeng/source/editeng/editundo.cxx new file mode 100644 index 000000000000..054971c240fd --- /dev/null +++ b/editeng/source/editeng/editundo.cxx @@ -0,0 +1,750 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editundo.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> + +DBG_NAME( EditUndo ) + +#define MAX_UNDOS 100 // ab dieser Menge darf geloescht werden.... +#define MIN_UNDOS 50 // soviel muss stehen bleiben... + +#define NO_UNDO 0xFFFF +#define GROUP_NOTFOUND 0xFFFF + +TYPEINIT1( EditUndo, SfxUndoAction ); +TYPEINIT1( EditUndoDelContent, EditUndo ); +TYPEINIT1( EditUndoConnectParas, EditUndo ); +TYPEINIT1( EditUndoSplitPara, EditUndo ); +TYPEINIT1( EditUndoInsertChars, EditUndo ); +TYPEINIT1( EditUndoRemoveChars, EditUndo ); +TYPEINIT1( EditUndoInsertFeature, EditUndo ); +TYPEINIT1( EditUndoMoveParagraphs, EditUndo ); +TYPEINIT1( EditUndoSetStyleSheet, EditUndo ); +TYPEINIT1( EditUndoSetParaAttribs, EditUndo ); +TYPEINIT1( EditUndoSetAttribs, EditUndo ); +TYPEINIT1( EditUndoTransliteration, EditUndo ); +TYPEINIT1( EditUndoMarkSelection, EditUndo ); + +void lcl_DoSetSelection( EditView* pView, USHORT nPara ) +{ + EPaM aEPaM( nPara, 0 ); + EditPaM aPaM( pView->GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + aPaM.SetIndex( aPaM.GetNode()->Len() ); + EditSelection aSel( aPaM, aPaM ); + pView->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoManager +// ------------------------------------------------------------------------ +EditUndoManager::EditUndoManager( ImpEditEngine* p ) +{ + pImpEE = p; +} + +BOOL __EXPORT EditUndoManager::Undo( USHORT nCount ) +{ + if ( GetUndoActionCount() == 0 ) + return FALSE; + + DBG_ASSERT( pImpEE->GetActiveView(), "Active View?" ); + + if ( !pImpEE->GetActiveView() ) + { + if ( pImpEE->GetEditViews().Count() ) + pImpEE->SetActiveView( pImpEE->GetEditViews().GetObject(0) ); + else + { + DBG_ERROR( "Undo in Engine ohne View nicht moeglich!" ); + return FALSE; + } + } + + pImpEE->GetActiveView()->GetImpEditView()->DrawSelection(); // alte Selektion entfernen + + pImpEE->SetUndoMode( TRUE ); + BOOL bDone = SfxUndoManager::Undo( nCount ); + pImpEE->SetUndoMode( FALSE ); + + EditSelection aNewSel( pImpEE->GetActiveView()->GetImpEditView()->GetEditSelection() ); + DBG_ASSERT( !aNewSel.IsInvalid(), "Ungueltige Selektion nach Undo()" ); + DBG_ASSERT( !aNewSel.DbgIsBuggy( pImpEE->GetEditDoc() ), "Kaputte Selektion nach Undo()" ); + + aNewSel.Min() = aNewSel.Max(); + pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); + pImpEE->FormatAndUpdate( pImpEE->GetActiveView() ); + + return bDone; +} + +BOOL __EXPORT EditUndoManager::Redo( USHORT nCount ) +{ + if ( GetRedoActionCount() == 0 ) + return FALSE; + + DBG_ASSERT( pImpEE->GetActiveView(), "Active View?" ); + + if ( !pImpEE->GetActiveView() ) + { + if ( pImpEE->GetEditViews().Count() ) + pImpEE->SetActiveView( pImpEE->GetEditViews().GetObject(0) ); + else + { + DBG_ERROR( "Redo in Engine ohne View nicht moeglich!" ); + return FALSE; + } + } + + pImpEE->GetActiveView()->GetImpEditView()->DrawSelection(); // alte Selektion entfernen + + pImpEE->SetUndoMode( TRUE ); + BOOL bDone = SfxUndoManager::Redo( nCount ); + pImpEE->SetUndoMode( FALSE ); + + EditSelection aNewSel( pImpEE->GetActiveView()->GetImpEditView()->GetEditSelection() ); + DBG_ASSERT( !aNewSel.IsInvalid(), "Ungueltige Selektion nach Undo()" ); + DBG_ASSERT( !aNewSel.DbgIsBuggy( pImpEE->GetEditDoc() ), "Kaputte Selektion nach Redo()" ); + + aNewSel.Min() = aNewSel.Max(); + pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); + pImpEE->FormatAndUpdate( pImpEE->GetActiveView() ); + + return bDone; +} + +// ----------------------------------------------------------------------- +// EditUndo +// ------------------------------------------------------------------------ +EditUndo::EditUndo( USHORT nI, ImpEditEngine* p ) +{ + DBG_CTOR( EditUndo, 0 ); + nId = nI; + pImpEE = p; +} + +EditUndo::~EditUndo() +{ + DBG_DTOR( EditUndo, 0 ); +} + +USHORT __EXPORT EditUndo::GetId() const +{ + DBG_CHKTHIS( EditUndo, 0 ); + return nId; +} + +BOOL __EXPORT EditUndo::CanRepeat(SfxRepeatTarget&) const +{ + return FALSE; +} + +XubString __EXPORT EditUndo::GetComment() const +{ + XubString aComment; + if ( pImpEE ) + { + EditEngine* pEditEng = pImpEE->GetEditEnginePtr(); + aComment = pEditEng->GetUndoComment( GetId() ); + } + return aComment; +} + +// ----------------------------------------------------------------------- +// EditUndoDelContent +// ------------------------------------------------------------------------ +EditUndoDelContent::EditUndoDelContent( ImpEditEngine* _pImpEE, ContentNode* pNode, USHORT n ) + : EditUndo( EDITUNDO_DELCONTENT, _pImpEE ) +{ + pContentNode = pNode; + nNode = n; + bDelObject = TRUE; +} + +EditUndoDelContent::~EditUndoDelContent() +{ + if ( bDelObject ) + delete pContentNode; +} + +void __EXPORT EditUndoDelContent::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->InsertContent( pContentNode, nNode ); + bDelObject = FALSE; // gehoert wieder der Engine + EditSelection aSel( EditPaM( pContentNode, 0 ), EditPaM( pContentNode, pContentNode->Len() ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoDelContent::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + // pNode stimmt nicht mehr, falls zwischendurch Undos, in denen + // Absaetze verschmolzen sind. + pContentNode = _pImpEE->GetEditDoc().SaveGetObject( nNode ); + DBG_ASSERT( pContentNode, "EditUndoDelContent::Redo(): Node?!" ); + + delete _pImpEE->GetParaPortions()[nNode]; + _pImpEE->GetParaPortions().Remove( nNode ); + + // Node nicht loeschen, haengt im Undo! + _pImpEE->GetEditDoc().Remove( nNode ); + if( _pImpEE->IsCallParaInsertedOrDeleted() ) + _pImpEE->GetEditEnginePtr()->ParagraphDeleted( nNode ); + + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pContentNode, nNode ); + _pImpEE->aDeletedNodes.Insert( pInf, _pImpEE->aDeletedNodes.Count() ); + _pImpEE->UpdateSelections(); + + ContentNode* pN = ( nNode < _pImpEE->GetEditDoc().Count() ) + ? _pImpEE->GetEditDoc().SaveGetObject( nNode ) + : _pImpEE->GetEditDoc().SaveGetObject( nNode-1 ); + DBG_ASSERT( pN && ( pN != pContentNode ), "?! RemoveContent !? " ); + EditPaM aPaM( pN, pN->Len() ); + + bDelObject = TRUE; // gehoert wieder dem Undo + + _pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoConnectParas +// ------------------------------------------------------------------------ +EditUndoConnectParas::EditUndoConnectParas( ImpEditEngine* _pImpEE, USHORT nN, USHORT nSP, + const SfxItemSet& rLeftParaAttribs, const SfxItemSet& rRightParaAttribs, + const SfxStyleSheet* pLeftStyle, const SfxStyleSheet* pRightStyle, BOOL bBkwrd ) + : EditUndo( EDITUNDO_CONNECTPARAS, _pImpEE ), + aLeftParaAttribs( rLeftParaAttribs ), + aRightParaAttribs( rRightParaAttribs ) +{ + nNode = nN; + nSepPos = nSP; + + if ( pLeftStyle ) + { + aLeftStyleName = pLeftStyle->GetName(); + eLeftStyleFamily = pLeftStyle->GetFamily(); + } + if ( pRightStyle ) + { + aRightStyleName = pRightStyle->GetName(); + eRightStyleFamily = pRightStyle->GetFamily(); + } + + bBackward = bBkwrd; +} + +EditUndoConnectParas::~EditUndoConnectParas() +{ +} + +void __EXPORT EditUndoConnectParas::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + // Bei SplitContent darf noch kein ParagraphInserted gerufen werden, + // weil der Outliner sich auf die Attribute verlaesst um die Tiefe + // des Absatzes zu initialisieren + + BOOL bCall = GetImpEditEngine()->IsCallParaInsertedOrDeleted(); + GetImpEditEngine()->SetCallParaInsertedOrDeleted( FALSE ); + + EditPaM aPaM = GetImpEditEngine()->SplitContent( nNode, nSepPos ); + GetImpEditEngine()->SetParaAttribs( nNode, aLeftParaAttribs ); + GetImpEditEngine()->SetParaAttribs( nNode+1, aRightParaAttribs ); + + GetImpEditEngine()->SetCallParaInsertedOrDeleted( bCall ); + if ( GetImpEditEngine()->IsCallParaInsertedOrDeleted() ) + GetImpEditEngine()->GetEditEnginePtr()->ParagraphInserted( nNode+1 ); + + if ( GetImpEditEngine()->GetStyleSheetPool() ) + { + if ( aLeftStyleName.Len() ) + GetImpEditEngine()->SetStyleSheet( (USHORT)nNode, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aLeftStyleName, eLeftStyleFamily ) ); + if ( aRightStyleName.Len() ) + GetImpEditEngine()->SetStyleSheet( nNode+1, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aRightStyleName, eRightStyleFamily ) ); + } + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +void __EXPORT EditUndoConnectParas::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->ConnectContents( nNode, bBackward ); + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoSplitPara +// ------------------------------------------------------------------------ +EditUndoSplitPara::EditUndoSplitPara( ImpEditEngine* _pImpEE, USHORT nN, USHORT nSP ) + : EditUndo( EDITUNDO_SPLITPARA, _pImpEE ) +{ + nNode = nN; + nSepPos = nSP; +} + +EditUndoSplitPara::~EditUndoSplitPara() +{ +} + +void __EXPORT EditUndoSplitPara::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->ConnectContents( nNode, FALSE ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +void __EXPORT EditUndoSplitPara::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->SplitContent( nNode, nSepPos ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoInsertChars +// ------------------------------------------------------------------------ +EditUndoInsertChars::EditUndoInsertChars( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const XubString& rStr ) + : EditUndo( EDITUNDO_INSERTCHARS, _pImpEE ), + aEPaM( rEPaM ), aText( rStr ) +{ +} + +void __EXPORT EditUndoInsertChars::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + EditPaM aNewPaM( GetImpEditEngine()->ImpDeleteSelection( aSel ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aNewPaM, aNewPaM ) ); +} + +void __EXPORT EditUndoInsertChars::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + GetImpEditEngine()->ImpInsertText( EditSelection( aPaM, aPaM ), aText ); + EditPaM aNewPaM( aPaM ); + aNewPaM.GetIndex() = aNewPaM.GetIndex() + aText.Len(); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aNewPaM ) ); +} + +BOOL __EXPORT EditUndoInsertChars::Merge( SfxUndoAction* pNextAction ) +{ + if ( !pNextAction->ISA( EditUndoInsertChars ) ) + return FALSE; + + EditUndoInsertChars* pNext = (EditUndoInsertChars*)pNextAction; + + if ( aEPaM.nPara != pNext->aEPaM.nPara ) + return FALSE; + + if ( ( aEPaM.nIndex + aText.Len() ) == pNext->aEPaM.nIndex ) + { + aText += pNext->aText; + return TRUE; + } + return FALSE; +} + +// ----------------------------------------------------------------------- +// EditUndoRemoveChars +// ------------------------------------------------------------------------ +EditUndoRemoveChars::EditUndoRemoveChars( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const XubString& rStr ) + : EditUndo( EDITUNDO_REMOVECHARS, _pImpEE ), + aEPaM( rEPaM ), aText( rStr ) +{ +} + +void __EXPORT EditUndoRemoveChars::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + GetImpEditEngine()->ImpInsertText( aSel, aText ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoRemoveChars::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + EditPaM aNewPaM = GetImpEditEngine()->ImpDeleteSelection( aSel ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewPaM ); +} + +// ----------------------------------------------------------------------- +// EditUndoInsertFeature +// ------------------------------------------------------------------------ +EditUndoInsertFeature::EditUndoInsertFeature( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const SfxPoolItem& rFeature) + : EditUndo( EDITUNDO_INSERTFEATURE, _pImpEE ), aEPaM( rEPaM ) +{ + pFeature = rFeature.Clone(); + DBG_ASSERT( pFeature, "Feature konnte nicht dupliziert werden: EditUndoInsertFeature" ); +} + +EditUndoInsertFeature::~EditUndoInsertFeature() +{ + delete pFeature; +} + +void __EXPORT EditUndoInsertFeature::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + // Attribute werden dort implizit vom Dokument korrigiert... + aSel.Max().GetIndex()++; + EditPaM aNewPaM = GetImpEditEngine()->ImpDeleteSelection( aSel ); + aSel.Max().GetIndex()--; // Fuer Selektion + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoInsertFeature::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + GetImpEditEngine()->ImpInsertFeature( aSel, *pFeature ); + if ( pFeature->Which() == EE_FEATURE_FIELD ) + GetImpEditEngine()->UpdateFields(); + aSel.Max().GetIndex()++; + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoMoveParagraphs +// ------------------------------------------------------------------------ +EditUndoMoveParagraphs::EditUndoMoveParagraphs + ( ImpEditEngine* _pImpEE, const Range& rParas, USHORT n ) + : EditUndo( EDITUNDO_MOVEPARAGRAPHS, _pImpEE ), + nParagraphs( rParas ) +{ + nDest = n; +} + +EditUndoMoveParagraphs::~EditUndoMoveParagraphs() +{ +} + +void __EXPORT EditUndoMoveParagraphs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + Range aTmpRange( nParagraphs ); + long nTmpDest = aTmpRange.Min(); + + long nDiff = ( nDest - aTmpRange.Min() ); + aTmpRange.Min() += nDiff; + aTmpRange.Max() += nDiff; + + if ( nParagraphs.Min() < (long)nDest ) + { + long nLen = aTmpRange.Len(); + aTmpRange.Min() -= nLen; + aTmpRange.Max() -= nLen; + } + else + nTmpDest += aTmpRange.Len(); + + EditSelection aNewSel( GetImpEditEngine()->MoveParagraphs( aTmpRange, (USHORT)nTmpDest, 0 ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +void __EXPORT EditUndoMoveParagraphs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditSelection aNewSel( GetImpEditEngine()->MoveParagraphs( nParagraphs, nDest, 0 ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetStyleSheet +// ------------------------------------------------------------------------ +EditUndoSetStyleSheet::EditUndoSetStyleSheet( ImpEditEngine* _pImpEE, USHORT nP, + const XubString& rPrevName, SfxStyleFamily ePrevFam, + const XubString& rNewName, SfxStyleFamily eNewFam, + const SfxItemSet& rPrevParaAttribs ) + : EditUndo( EDITUNDO_STYLESHEET, _pImpEE ), aPrevName( rPrevName ), aNewName( rNewName ), + aPrevParaAttribs( rPrevParaAttribs ) +{ + ePrevFamily = ePrevFam; + eNewFamily = eNewFam; + nPara = nP; +} + +EditUndoSetStyleSheet::~EditUndoSetStyleSheet() +{ +} + +void __EXPORT EditUndoSetStyleSheet::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetStyleSheet( nPara, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aPrevName, ePrevFamily ) ); + GetImpEditEngine()->SetParaAttribs( nPara, aPrevParaAttribs ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +void __EXPORT EditUndoSetStyleSheet::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetStyleSheet( nPara, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aNewName, eNewFamily ) ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetParaAttribs +// ------------------------------------------------------------------------ +EditUndoSetParaAttribs::EditUndoSetParaAttribs( ImpEditEngine* _pImpEE, USHORT nP, const SfxItemSet& rPrevItems, const SfxItemSet& rNewItems ) + : EditUndo( EDITUNDO_PARAATTRIBS, _pImpEE ), + aPrevItems( rPrevItems ), + aNewItems(rNewItems ) +{ + nPara = nP; +} + +EditUndoSetParaAttribs::~EditUndoSetParaAttribs() +{ +} + +void __EXPORT EditUndoSetParaAttribs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetParaAttribs( nPara, aPrevItems ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +void __EXPORT EditUndoSetParaAttribs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetParaAttribs( nPara, aNewItems ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetAttribs +// ------------------------------------------------------------------------ +EditUndoSetAttribs::EditUndoSetAttribs( ImpEditEngine* _pImpEE, const ESelection& rESel, const SfxItemSet& rNewItems ) + : EditUndo( EDITUNDO_ATTRIBS, _pImpEE ), + aESel( rESel ), + aNewAttribs( rNewItems ) +{ + // Wenn das EditUndoSetAttribs eigentlich ein RemoveAttribs ist, koennte + // man das eigentlich an einem leeren ItemSet erkennen, aber dann muesste + // an einigen Stellen abgefangen werden, das ggf. ein SetAttribs mit einem + // leeren ItemSet gemacht wird. + // => Ich habe lieber diesen Member spendiert... + bSetIsRemove = FALSE; + bRemoveParaAttribs = FALSE; + nRemoveWhich = 0; + nSpecial = 0; +} + +EditUndoSetAttribs::~EditUndoSetAttribs() +{ + // Items aus Pool holen... + SfxItemPool* pPool = aNewAttribs.GetPool(); + USHORT nContents = aPrevAttribs.Count(); + for ( USHORT n = 0; n < nContents; n++ ) + { + ContentAttribsInfo* pInf = aPrevAttribs[n]; + DBG_ASSERT( pInf, "Undo_DTOR (SetAttribs): pInf = NULL!" ); + for ( USHORT nAttr = 0; nAttr < pInf->GetPrevCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pX = pInf->GetPrevCharAttribs()[nAttr]; + DBG_ASSERT( pX, "Undo_DTOR (SetAttribs): pX = NULL!" ); + pPool->Remove( *pX->GetItem() ); + delete pX; + } + delete pInf; + } +} + +void __EXPORT EditUndoSetAttribs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + BOOL bFields = FALSE; + for ( USHORT nPara = aESel.nStartPara; nPara <= aESel.nEndPara; nPara++ ) + { + ContentAttribsInfo* pInf = aPrevAttribs[ (USHORT)(nPara-aESel.nStartPara) ]; + DBG_ASSERT( pInf, "Undo (SetAttribs): pInf = NULL!" ); + + // erstmal die Absatzattribute... + _pImpEE->SetParaAttribs( nPara, pInf->GetPrevParaAttribs() ); + + // Dann die Zeichenattribute... + // Alle Attribute inkl. Features entfernen, werden wieder neu eingestellt. + _pImpEE->RemoveCharAttribs( nPara, 0, TRUE ); + DBG_ASSERT( _pImpEE->GetEditDoc().SaveGetObject( nPara ), "Undo (SetAttribs): pNode = NULL!" ); + ContentNode* pNode = _pImpEE->GetEditDoc().GetObject( nPara ); + for ( USHORT nAttr = 0; nAttr < pInf->GetPrevCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pX = pInf->GetPrevCharAttribs()[nAttr]; + DBG_ASSERT( pX, "Redo (SetAttribs): pX = NULL!" ); + // wird autom. 'eingepoolt'. + _pImpEE->GetEditDoc().InsertAttrib( pNode, pX->GetStart(), pX->GetEnd(), *pX->GetItem() ); + if ( pX->Which() == EE_FEATURE_FIELD ) + bFields = TRUE; + } + } + if ( bFields ) + _pImpEE->UpdateFields(); + ImpSetSelection( GetImpEditEngine()->GetActiveView() ); +} + +void __EXPORT EditUndoSetAttribs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aESel ) ); + if ( !bSetIsRemove ) + _pImpEE->SetAttribs( aSel, aNewAttribs, nSpecial ); + else + _pImpEE->RemoveCharAttribs( aSel, bRemoveParaAttribs, nRemoveWhich ); + + ImpSetSelection( GetImpEditEngine()->GetActiveView() ); +} + +void EditUndoSetAttribs::ImpSetSelection( EditView* /*pView*/ ) +{ + ImpEditEngine* _pImpEE = GetImpEditEngine(); + EditSelection aSel( _pImpEE->CreateSel( aESel ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoTransliteration +// ------------------------------------------------------------------------ +EditUndoTransliteration::EditUndoTransliteration( ImpEditEngine* _pImpEE, const ESelection& rESel, sal_Int32 nM ) + : EditUndo( EDITUNDO_TRANSLITERATE, _pImpEE ), aOldESel( rESel ) +{ + nMode = nM; + pTxtObj = NULL; +} + +EditUndoTransliteration::~EditUndoTransliteration() +{ + delete pTxtObj; +} + +void __EXPORT EditUndoTransliteration::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aNewESel ) ); + + // Insert text, but don't expand Atribs at the current position: + aSel = _pImpEE->DeleteSelected( aSel ); + EditSelection aDelSel( aSel ); + aSel = _pImpEE->InsertParaBreak( aSel ); + aDelSel.Max() = aSel.Min(); + aDelSel.Max().GetNode()->GetCharAttribs().DeleteEmptyAttribs( _pImpEE->GetEditDoc().GetItemPool() ); + EditSelection aNewSel; + if ( pTxtObj ) + { + aNewSel = _pImpEE->InsertText( *pTxtObj, aSel ); + } + else + { + aNewSel = _pImpEE->InsertText( aSel, aText ); + } + if ( aNewSel.Min().GetNode() == aDelSel.Max().GetNode() ) + { + aNewSel.Min().SetNode( aDelSel.Min().GetNode() ); + aNewSel.Min().GetIndex() = + aNewSel.Min().GetIndex() + aDelSel.Min().GetIndex(); + } + if ( aNewSel.Max().GetNode() == aDelSel.Max().GetNode() ) + { + aNewSel.Max().SetNode( aDelSel.Min().GetNode() ); + aNewSel.Max().GetIndex() = + aNewSel.Max().GetIndex() + aDelSel.Min().GetIndex(); + } + _pImpEE->DeleteSelected( aDelSel ); + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +void __EXPORT EditUndoTransliteration::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aOldESel ) ); + EditSelection aNewSel = _pImpEE->TransliterateText( aSel, nMode ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoMarkSelection +// ------------------------------------------------------------------------ +EditUndoMarkSelection::EditUndoMarkSelection( ImpEditEngine* _pImpEE, const ESelection& rSel ) + : EditUndo( EDITUNDO_MARKSELECTION, _pImpEE ), aSelection( rSel ) +{ +} + +EditUndoMarkSelection::~EditUndoMarkSelection() +{ +} + +void __EXPORT EditUndoMarkSelection::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + if ( GetImpEditEngine()->GetActiveView() ) + { + if ( GetImpEditEngine()->IsFormatted() ) + GetImpEditEngine()->GetActiveView()->SetSelection( aSelection ); + else + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( GetImpEditEngine()->CreateSel( aSelection ) ); + } +} + +void __EXPORT EditUndoMarkSelection::Redo() +{ + // Fuer Redo unwichtig, weil am Anfang der Undo-Klammerung +} + diff --git a/editeng/source/editeng/editundo.hxx b/editeng/source/editeng/editundo.hxx new file mode 100644 index 000000000000..4c54c553c353 --- /dev/null +++ b/editeng/source/editeng/editundo.hxx @@ -0,0 +1,315 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITUNDO_HXX +#define _EDITUNDO_HXX + +#include <editdoc.hxx> +#include <editeng/editund2.hxx> +#include <editeng/editdata.hxx> + +#define UNDO_NOACTION 0 +#define UNDO_NEWUNDO 1 +#define UNDO_UNDOSDELETED 2 +#define UNDO_EMPTYGROUPDELETED 3 +#define UNDO_INVALIDEND 4 + +class ImpEditEngine; +class EditView; + +// ----------------------------------------------------------------------- +// EditUndoDelContent +// ------------------------------------------------------------------------ +class EditUndoDelContent : public EditUndo +{ +private: + BOOL bDelObject; + USHORT nNode; + ContentNode* pContentNode; // Zeigt auf das gueltige, + // nicht zerstoerte Objekt! + +public: + TYPEINFO(); + EditUndoDelContent( ImpEditEngine* pImpEE, ContentNode* pNode, USHORT nPortio ); + ~EditUndoDelContent(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoConnectParas +// ------------------------------------------------------------------------ +class EditUndoConnectParas : public EditUndo +{ +private: + USHORT nNode; + USHORT nSepPos; + SfxItemSet aLeftParaAttribs; + SfxItemSet aRightParaAttribs; + + // 2 Pointer waeren schoener, aber dann muesste es ein SfxListener sein. + String aLeftStyleName; + String aRightStyleName; + SfxStyleFamily eLeftStyleFamily; + SfxStyleFamily eRightStyleFamily; + + BOOL bBackward; + +public: + TYPEINFO(); + EditUndoConnectParas( ImpEditEngine* pImpEE, USHORT nNode, USHORT nSepPos, + const SfxItemSet& rLeftParaAttribs, const SfxItemSet& rRightParaAttribs, + const SfxStyleSheet* pLeftStyle, const SfxStyleSheet* pRightStyle, BOOL bBackward ); + ~EditUndoConnectParas(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSplitPara +// ------------------------------------------------------------------------ +class EditUndoSplitPara : public EditUndo +{ +private: + USHORT nNode; + USHORT nSepPos; + +public: + TYPEINFO(); + EditUndoSplitPara( ImpEditEngine* pImpEE, USHORT nNode, USHORT nSepPos ); + ~EditUndoSplitPara(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoInsertChars +// ------------------------------------------------------------------------ +class EditUndoInsertChars : public EditUndo +{ +private: + EPaM aEPaM; + String aText; + +public: + TYPEINFO(); + EditUndoInsertChars( ImpEditEngine* pImpEE, const EPaM& rEPaM, const String& rStr ); + + const EPaM& GetEPaM() { return aEPaM; } + String& GetStr() { return aText; } + + virtual void Undo(); + virtual void Redo(); + + virtual BOOL Merge( SfxUndoAction *pNextAction ); +}; + +// ----------------------------------------------------------------------- +// EditUndoRemoveChars +// ------------------------------------------------------------------------ +class EditUndoRemoveChars : public EditUndo +{ +private: + EPaM aEPaM; + String aText; + +public: + TYPEINFO(); + EditUndoRemoveChars( ImpEditEngine* pImpEE, const EPaM& rEPaM, const String& rStr ); + + const EPaM& GetEPaM() { return aEPaM; } + String& GetStr() { return aText; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoInsertFeature +// ------------------------------------------------------------------------ +class EditUndoInsertFeature : public EditUndo +{ +private: + EPaM aEPaM; + SfxPoolItem* pFeature; + +public: + TYPEINFO(); + EditUndoInsertFeature( ImpEditEngine* pImpEE, const EPaM& rEPaM, + const SfxPoolItem& rFeature); + ~EditUndoInsertFeature(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoMoveParagraphs +// ------------------------------------------------------------------------ +class EditUndoMoveParagraphs: public EditUndo +{ +private: + Range nParagraphs; + USHORT nDest; + +public: + TYPEINFO(); + EditUndoMoveParagraphs( ImpEditEngine* pImpEE, const Range& rParas, USHORT nDest ); + ~EditUndoMoveParagraphs(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetStyleSheet +// ------------------------------------------------------------------------ +class EditUndoSetStyleSheet: public EditUndo +{ +private: + USHORT nPara; + XubString aPrevName; + XubString aNewName; + SfxStyleFamily ePrevFamily; + SfxStyleFamily eNewFamily; + SfxItemSet aPrevParaAttribs; + +public: + TYPEINFO(); + + EditUndoSetStyleSheet( ImpEditEngine* pImpEE, USHORT nPara, + const XubString& rPrevName, SfxStyleFamily ePrevFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily, + const SfxItemSet& rPrevParaAttribs ); + ~EditUndoSetStyleSheet(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetParaAttribs +// ------------------------------------------------------------------------ +class EditUndoSetParaAttribs: public EditUndo +{ +private: + USHORT nPara; + SfxItemSet aPrevItems; + SfxItemSet aNewItems; + +public: + TYPEINFO(); + EditUndoSetParaAttribs( ImpEditEngine* pImpEE, USHORT nPara, const SfxItemSet& rPrevItems, const SfxItemSet& rNewItems ); + ~EditUndoSetParaAttribs(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetAttribs +// ------------------------------------------------------------------------ +class EditUndoSetAttribs: public EditUndo +{ +private: + ESelection aESel; + SfxItemSet aNewAttribs; + ContentInfoArray aPrevAttribs; + + BYTE nSpecial; + BOOL bSetIsRemove; + BOOL bRemoveParaAttribs; + USHORT nRemoveWhich; + + void ImpSetSelection( EditView* pView ); + + +public: + TYPEINFO(); + EditUndoSetAttribs( ImpEditEngine* pImpEE, const ESelection& rESel, const SfxItemSet& rNewItems ); + ~EditUndoSetAttribs(); + + ContentInfoArray& GetContentInfos() { return aPrevAttribs; } + SfxItemSet& GetNewAttribs() { return aNewAttribs; } + + void SetSpecial( BYTE n ) { nSpecial = n; } + void SetRemoveAttribs( BOOL b ) { bSetIsRemove = b; } + void SetRemoveParaAttribs( BOOL b ) { bRemoveParaAttribs = b; } + void SetRemoveWhich( USHORT n ) { nRemoveWhich = n; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoTransliteration +// ------------------------------------------------------------------------ +class EditUndoTransliteration: public EditUndo +{ +private: + ESelection aOldESel; + ESelection aNewESel; + + sal_Int32 nMode; + EditTextObject* pTxtObj; + String aText; + +public: + TYPEINFO(); + EditUndoTransliteration( ImpEditEngine* pImpEE, const ESelection& rESel, sal_Int32 nMode ); + ~EditUndoTransliteration(); + + void SetText( const String& rText ) { aText = rText; } + void SetText( EditTextObject* pObj ) { pTxtObj = pObj; } + void SetNewSelection( const ESelection& rSel ) { aNewESel = rSel; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoMarkSelection +// ------------------------------------------------------------------------ +class EditUndoMarkSelection: public EditUndo +{ +private: + ESelection aSelection; + +public: + TYPEINFO(); + EditUndoMarkSelection( ImpEditEngine* pImpEE, const ESelection& rSel ); + ~EditUndoMarkSelection(); + + virtual void Undo(); + virtual void Redo(); +}; + + +#endif // _EDITUNDO_HXX diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx new file mode 100644 index 000000000000..766023a0038c --- /dev/null +++ b/editeng/source/editeng/editview.cxx @@ -0,0 +1,1595 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <com/sun/star/i18n/WordType.hpp> +#include <vcl/metric.hxx> + +#include <i18npool/mslangid.hxx> +#include <svl/languageoptions.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/langtab.hxx> + +#include <svl/srchitem.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/flditem.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/langitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <editeng.hrc> +#include <helpid.hrc> +#include <i18npool/lang.h> +#include <vcl/menu.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/unolingu.hxx> +#include <editeng/fontitem.hxx> + +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/beans/PropertyValues.hdl> +#include <com/sun/star/lang/Locale.hpp> +#include <linguistic/lngprops.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <unotools/lingucfg.hxx> + +using ::rtl::OUString; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::linguistic2; + + +DBG_NAME( EditView ) + + +// From SW => Create common method +LanguageType lcl_CheckLanguage( + const OUString &rText, + Reference< XSpellChecker1 > xSpell, + Reference< linguistic2::XLanguageGuessing > xLangGuess, + sal_Bool bIsParaText ) +{ + LanguageType nLang = LANGUAGE_NONE; + if (bIsParaText) // check longer texts with language-guessing... + { + if (!xLangGuess.is()) + return nLang; + + lang::Locale aLocale( xLangGuess->guessPrimaryLanguage( rText, 0, rText.getLength()) ); + + // get language as from "Tools/Options - Language Settings - Languages: Locale setting" + LanguageType nTmpLang = Application::GetSettings().GetLanguage(); + + // if the result from language guessing does not provide a 'Country' part + // try to get it by looking up the locale setting of the office. + if (aLocale.Country.getLength() == 0) + { + lang::Locale aTmpLocale = SvxCreateLocale( nTmpLang ); + if (aTmpLocale.Language == aLocale.Language) + nLang = nTmpLang; + } + if (nLang == LANGUAGE_NONE) // language not found by looking up the sytem language... + nLang = MsLangId::convertLocaleToLanguageWithFallback( aLocale ); + if (nLang == LANGUAGE_SYSTEM) + nLang = nTmpLang; + if (nLang == LANGUAGE_DONTKNOW) + nLang = LANGUAGE_NONE; + } + else // check single word + { + if (!xSpell.is()) + return nLang; + + // + // build list of languages to check + // + LanguageType aLangList[4]; + const AllSettings& rSettings = Application::GetSettings(); + SvtLinguOptions aLinguOpt; + SvtLinguConfig().GetOptions( aLinguOpt ); + // The default document language from "Tools/Options - Language Settings - Languages: Western" + aLangList[0] = aLinguOpt.nDefaultLanguage; + // The one from "Tools/Options - Language Settings - Languages: User interface" + aLangList[1] = rSettings.GetUILanguage(); + // The one from "Tools/Options - Language Settings - Languages: Locale setting" + aLangList[2] = rSettings.GetLanguage(); + // en-US + aLangList[3] = LANGUAGE_ENGLISH_US; +#ifdef DEBUG + lang::Locale a0( SvxCreateLocale( aLangList[0] ) ); + lang::Locale a1( SvxCreateLocale( aLangList[1] ) ); + lang::Locale a2( SvxCreateLocale( aLangList[2] ) ); + lang::Locale a3( SvxCreateLocale( aLangList[3] ) ); +#endif + + INT32 nCount = sizeof(aLangList) / sizeof(aLangList[0]); + for (INT32 i = 0; i < nCount; i++) + { + INT16 nTmpLang = aLangList[i]; + if (nTmpLang != LANGUAGE_NONE && nTmpLang != LANGUAGE_DONTKNOW) + { + if (xSpell->hasLanguage( nTmpLang ) && + xSpell->isValid( rText, nTmpLang, Sequence< PropertyValue >() )) + { + nLang = nTmpLang; + break; + } + } + } + } + + return nLang; +} + + +// ---------------------------------------------------------------------- +// class EditView +// ---------------------------------------------------------------------- +EditView::EditView( EditEngine* pEng, Window* pWindow ) +{ + DBG_CTOR( EditView, 0 ); + pImpEditView = new ImpEditView( this, pEng, pWindow ); +} + +EditView::~EditView() +{ + DBG_DTOR( EditView, 0 ); + delete pImpEditView; +} + +ImpEditEngine* EditView::GetImpEditEngine() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pEditEngine->pImpEditEngine; +} + +EditEngine* EditView::GetEditEngine() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->pEditEngine; +} + +void EditView::Invalidate() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !pImpEditView->DoInvalidateMore() ) + pImpEditView->GetWindow()->Invalidate( pImpEditView->aOutArea ); + else + { + Rectangle aRect( pImpEditView->aOutArea ); + long nMore = pImpEditView->GetWindow()->PixelToLogic( Size( pImpEditView->GetInvalidateMore(), 0 ) ).Width(); + aRect.Left() -= nMore; + aRect.Right() += nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + pImpEditView->GetWindow()->Invalidate( aRect ); + } +} + +void EditView::SetReadOnly( sal_Bool bReadOnly ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->bReadOnly = bReadOnly; +} + +sal_Bool EditView::IsReadOnly() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->bReadOnly; +} + +void EditView::SetSelection( const ESelection& rESel ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + // Falls jemand gerade ein leeres Attribut hinterlassen hat, + // und dann der Outliner die Selektion manipulitert: + if ( !pImpEditView->GetEditSelection().HasRange() ) + { + ContentNode* pNode = pImpEditView->GetEditSelection().Max().GetNode(); + PIMPEE->CursorMoved( pNode ); + } + EditSelection aNewSelection( PIMPEE->ConvertSelection( rESel.nStartPara, rESel.nStartPos, rESel.nEndPara, rESel.nEndPos ) ); + + // Wenn nach einem KeyInput die Selection manipuliert wird: + PIMPEE->CheckIdleFormatter(); + + // Selektion darf nicht bei einem unsichtbaren Absatz Starten/Enden: + ParaPortion* pPortion = PIMPEE->FindParaPortion( aNewSelection.Min().GetNode() ); + if ( !pPortion->IsVisible() ) + { + pPortion = PIMPEE->GetPrevVisPortion( pPortion ); + ContentNode* pNode = pPortion ? pPortion->GetNode() : PIMPEE->GetEditDoc().GetObject( 0 ); + aNewSelection.Min() = EditPaM( pNode, pNode->Len() ); + } + pPortion = PIMPEE->FindParaPortion( aNewSelection.Max().GetNode() ); + if ( !pPortion->IsVisible() ) + { + pPortion = PIMPEE->GetPrevVisPortion( pPortion ); + ContentNode* pNode = pPortion ? pPortion->GetNode() : PIMPEE->GetEditDoc().GetObject( 0 ); + aNewSelection.Max() = EditPaM( pNode, pNode->Len() ); + } + + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( aNewSelection ); + pImpEditView->DrawSelection(); + sal_Bool bGotoCursor = pImpEditView->DoAutoScroll(); + ShowCursor( bGotoCursor ); +} + +ESelection EditView::GetSelection() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ESelection aSelection; + + aSelection.nStartPara = PIMPEE->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Min().GetNode() ); + aSelection.nEndPara = PIMPEE->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Max().GetNode() ); + + aSelection.nStartPos = pImpEditView->GetEditSelection().Min().GetIndex(); + aSelection.nEndPos = pImpEditView->GetEditSelection().Max().GetIndex(); + + return aSelection; +} + +sal_Bool EditView::HasSelection() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->HasSelection(); +} + +void EditView::DeleteSelected() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->DeleteSelected(); +} + +USHORT EditView::GetSelectedScriptType() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetScriptType( pImpEditView->GetEditSelection() ); +} + +void EditView::Paint( const Rectangle& rRect ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Paint( pImpEditView, rRect ); +} + +void EditView::SetEditEngine( EditEngine* pEditEng ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->pEditEngine = pEditEng; + EditSelection aStartSel; + aStartSel = PIMPEE->GetEditDoc().GetStartPaM(); + pImpEditView->SetEditSelection( aStartSel ); +} + +void EditView::SetWindow( Window* pWin ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->pOutWin = pWin; + PIMPEE->GetSelEngine().Reset(); +} + +Window* EditView::GetWindow() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pOutWin; +} + +void EditView::SetVisArea( const Rectangle& rRec ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetVisDocStartPos( rRec.TopLeft() ); +} + +const Rectangle& EditView::GetVisArea() const +{ + DBG_CHKTHIS( EditView, 0 ); + // Change return value to Rectangle in next incompatible build !!! + static Rectangle aRect; + aRect = pImpEditView->GetVisDocArea(); + return aRect; +} + +void EditView::SetOutputArea( const Rectangle& rRec ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetOutputArea( rRec ); + + // Rest nur hier, wenn API-Aufruf: + pImpEditView->CalcAnchorPoint(); + if ( PIMPEE->GetStatus().AutoPageSize() ) + pImpEditView->RecalcOutputArea(); + pImpEditView->ShowCursor( sal_False, sal_False ); +} + +const Rectangle& EditView::GetOutputArea() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetOutputArea(); +} + +void EditView::SetPointer( const Pointer& rPointer ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetPointer( rPointer ); +} + +const Pointer& EditView::GetPointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetPointer(); +} + +void EditView::SetCursor( const Cursor& rCursor ) +{ + DBG_CHKTHIS( EditView, 0 ); + delete pImpEditView->pCursor; + pImpEditView->pCursor = new Cursor( rCursor ); +} + +Cursor* EditView::GetCursor() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pCursor; +} + +void EditView::InsertText( const XubString& rStr, sal_Bool bSelect ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ImpEditEngine* pImpEE = PIMPEE; + pImpEditView->DrawSelection(); + + EditPaM aPaM1; + if ( bSelect ) + { + EditSelection aTmpSel( pImpEditView->GetEditSelection() ); + aTmpSel.Adjust( pImpEE->GetEditDoc() ); + aPaM1 = aTmpSel.Min(); + } + + pImpEE->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM2( pImpEE->InsertText( pImpEditView->GetEditSelection(), rStr ) ); + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); + + if ( bSelect ) + { + DBG_ASSERT( !aPaM1.DbgIsBuggy( pImpEE->GetEditDoc() ), "Insert: PaM kaputt" ); + pImpEditView->SetEditSelection( EditSelection( aPaM1, aPaM2 ) ); + } + else + pImpEditView->SetEditSelection( EditSelection( aPaM2, aPaM2 ) ); + + pImpEE->FormatAndUpdate( this ); +} + +sal_Bool EditView::PostKeyEvent( const KeyEvent& rKeyEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->PostKeyEvent( rKeyEvent ); +} + +sal_Bool EditView::MouseButtonUp( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseButtonUp( rMouseEvent ); +} + +sal_Bool EditView::MouseButtonDown( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseButtonDown( rMouseEvent ); +} + +sal_Bool EditView::MouseMove( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseMove( rMouseEvent ); +} + +void EditView::Command( const CommandEvent& rCEvt ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->Command( rCEvt ); +} + +void EditView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + +// Draw vertraegt die Assertion nicht, spaeter mal aktivieren +// DBG_ASSERT( pImpEditView->pEditEngine->HasView( this ), "ShowCursor - View nicht angemeldet!" ); +// DBG_ASSERT( !GetWindow()->IsInPaint(), "ShowCursor - Why in Paint ?!" ); + + if ( pImpEditView->pEditEngine->HasView( this ) ) + { + // Das ControlWord hat mehr Gewicht: + if ( !pImpEditView->DoAutoScroll() ) + bGotoCursor = sal_False; + pImpEditView->ShowCursor( bGotoCursor, bForceVisCursor ); + } +} + +void EditView::HideCursor() +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->GetCursor()->Hide(); +} + +Pair EditView::Scroll( long ndX, long ndY, BYTE nRangeCheck ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->Scroll( ndX, ndY, nRangeCheck ); +} + +const SfxItemSet& EditView::GetEmptyItemSet() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetEmptyItemSet(); +} + +void EditView::SetAttribs( const SfxItemSet& rSet ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blinde Selection in ...." ); + + // Kein Undo-Kappseln noetig... + pImpEditView->DrawSelection(); + PIMPEE->SetAttribs( pImpEditView->GetEditSelection(), rSet, ATTRSPECIAL_WHOLEWORD ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::SetParaAttribs( const SfxItemSet& rSet, sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + // Kein Undo-Kappseln noetig... + PIMPEE->SetParaAttribs( nPara, rSet ); + // Beim Aendern von Absatzattributen muss immer formatiert werden... + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveAttribsKeepLanguages( sal_Bool bRemoveParaAttribs ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + EditSelection aSelection( pImpEditView->GetEditSelection() ); + + for (sal_uInt16 nWID = EE_ITEMS_START; nWID <= EE_ITEMS_END; ++nWID) + { + bool bIsLang = EE_CHAR_LANGUAGE == nWID || + EE_CHAR_LANGUAGE_CJK == nWID || + EE_CHAR_LANGUAGE_CTL == nWID; + if (!bIsLang) + PIMPEE->RemoveCharAttribs( aSelection, bRemoveParaAttribs, nWID ); + } + + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveAttribs( sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + PIMPEE->RemoveCharAttribs( pImpEditView->GetEditSelection(), bRemoveParaAttribs, nWhich ); + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + PIMPEE->RemoveCharAttribs( nPara, nWhich ); + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +SfxItemSet EditView::GetAttribs() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blinde Selection in ...." ); + return PIMPEE->GetAttribs( pImpEditView->GetEditSelection() ); +} + +void EditView::Undo() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Undo( this ); +} + +void EditView::Redo() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Redo( this ); +} + +ULONG EditView::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, sal_Bool bSelect, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aOldSel( pImpEditView->GetEditSelection() ); + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_READ ); + EditPaM aEndPaM = PIMPEE->Read( rInput, rBaseURL, eFormat, aOldSel, pHTTPHeaderAttrs ); + PIMPEE->UndoActionEnd( EDITUNDO_READ ); + EditSelection aNewSel( aEndPaM, aEndPaM ); + if ( bSelect ) + { + aOldSel.Adjust( PIMPEE->GetEditDoc() ); + aNewSel.Min() = aOldSel.Min(); + } + + pImpEditView->SetEditSelection( aNewSel ); + sal_Bool bGotoCursor = pImpEditView->DoAutoScroll(); + ShowCursor( bGotoCursor ); + + return rInput.GetError(); +} + +#ifndef SVX_LIGHT +ULONG EditView::Write( SvStream& rOutput, EETextFormat eFormat ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Write( rOutput, eFormat, pImpEditView->GetEditSelection() ); + ShowCursor(); + return rOutput.GetError(); +} +#endif + +void EditView::Cut() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->CutCopy( aClipBoard, sal_True ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > EditView::GetTransferable() +{ + uno::Reference< datatransfer::XTransferable > xData = GetEditEngine()->pImpEditEngine->CreateTransferable( pImpEditView->GetEditSelection() ); + return xData; +} + +void EditView::Copy() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->CutCopy( aClipBoard, sal_False ); +} + +void EditView::Paste() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->Paste( aClipBoard, sal_False ); +} + +void EditView::PasteSpecial() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->Paste(aClipBoard, sal_True ); +} + +void EditView::EnablePaste( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->EnablePaste( bEnable ); +} + +sal_Bool EditView::IsPasteEnabled() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->IsPasteEnabled(); +} + +Point EditView::GetWindowPosTopLeft( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aDocPos( pImpEditView->pEditEngine->GetDocPosTopLeft( nParagraph ) ); + return pImpEditView->GetWindowPos( aDocPos ); +} + +sal_uInt16 EditView::GetParagraph( const Point& rMousePosPixel ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aMousePos( rMousePosPixel ); + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + Point aDocPos( pImpEditView->GetDocPos( aMousePos ) ); + sal_uInt16 nParagraph = PIMPEE->GetParaPortions().FindParagraph( aDocPos.Y() ); + return nParagraph; +} + +void EditView::IndentBlock() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->IndentBlock( this, sal_True ); +} + +void EditView::UnindentBlock() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->IndentBlock( this, sal_False ); +} + +EESelectionMode EditView::GetSelectionMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetSelectionMode(); +} + +void EditView::SetSelectionMode( EESelectionMode eMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetSelectionMode( eMode ); +} + +XubString EditView::GetSelected() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetSelected( pImpEditView->GetEditSelection() ); +} + +void EditView::MoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->UndoActionStart( EDITUNDO_MOVEPARAS ); + PIMPEE->MoveParagraphs( aParagraphs, nNewPos, this ); + PIMPEE->UndoActionEnd( EDITUNDO_MOVEPARAS ); +} + +void EditView::MoveParagraphs( long nDiff ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + ESelection aSel = GetSelection(); + Range aRange( aSel.nStartPara, aSel.nEndPara ); + aRange.Justify(); + long nDest = ( nDiff > 0 ? aRange.Max() : aRange.Min() ) + nDiff; + if ( nDiff > 0 ) + nDest++; + DBG_ASSERT( ( nDest >= 0 ) && ( nDest <= pImpEditView->pEditEngine->GetParagraphCount() ), "MoveParagraphs - wrong Parameters!" ); + MoveParagraphs( aRange, + sal::static_int_cast< USHORT >( nDest ) ); +} + +void EditView::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->SetBackgroundColor( rColor ); +} + +Color EditView::GetBackgroundColor() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->GetBackgroundColor(); +} + +void EditView::SetControlWord( sal_uInt32 nWord ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->nControl = nWord; +} + +sal_uInt32 EditView::GetControlWord() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->nControl; +} + +EditTextObject* EditView::CreateTextObject() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->CreateTextObject( pImpEditView->GetEditSelection() ); +} + +void EditView::InsertText( const EditTextObject& rTextObject ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->DrawSelection(); + + PIMPEE->UndoActionStart( EDITUNDO_INSERT ); + EditSelection aTextSel( PIMPEE->InsertText( rTextObject, pImpEditView->GetEditSelection() ) ); + PIMPEE->UndoActionEnd( EDITUNDO_INSERT ); + + aTextSel.Min() = aTextSel.Max(); // Selektion nicht behalten. + pImpEditView->SetEditSelection( aTextSel ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::InsertText( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > xDataObj, const String& rBaseURL, BOOL bUseSpecial ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->UndoActionStart( EDITUNDO_INSERT ); + pImpEditView->DeleteSelected(); + EditSelection aTextSel( PIMPEE->InsertText( xDataObj, rBaseURL, pImpEditView->GetEditSelection().Max(), bUseSpecial ) ); + PIMPEE->UndoActionEnd( EDITUNDO_INSERT ); + + aTextSel.Min() = aTextSel.Max(); // Selektion nicht behalten. + pImpEditView->SetEditSelection( aTextSel ); + PIMPEE->FormatAndUpdate( this ); +} + +sal_Bool EditView::Drop( const DropEvent& ) +{ + return FALSE; +} + +ESelection EditView::GetDropPos() +{ + DBG_ERROR( "GetDropPos - Why?!" ); + return ESelection(); +} + +sal_Bool EditView::QueryDrop( DropEvent& ) +{ + return FALSE; +} + +void EditView::SetEditEngineUpdateMode( sal_Bool bUpdate ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->SetUpdateMode( bUpdate, this ); +} + +void EditView::ForceUpdate() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->SetUpdateMode( sal_True, this, sal_True ); +} + +void EditView::SetStyleSheet( SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + EditSelection aSel( pImpEditView->GetEditSelection() ); + PIMPEE->UndoActionStart( EDITUNDO_STYLESHEET ); + PIMPEE->SetStyleSheet( aSel, pStyle ); + PIMPEE->UndoActionEnd( EDITUNDO_STYLESHEET ); +} + +SfxStyleSheet* EditView::GetStyleSheet() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( PIMPEE->GetEditDoc() ); + sal_uInt16 nStartPara = PIMPEE->GetEditDoc().GetPos( aSel.Min().GetNode() ); + sal_uInt16 nEndPara = PIMPEE->GetEditDoc().GetPos( aSel.Max().GetNode() ); + + SfxStyleSheet* pStyle = NULL; + for ( sal_uInt16 n = nStartPara; n <= nEndPara; n++ ) + { + SfxStyleSheet* pTmpStyle = PIMPEE->GetStyleSheet( n ); + if ( ( n != nStartPara ) && ( pStyle != pTmpStyle ) ) + return NULL; // Nicht eindeutig. + pStyle = pTmpStyle; + } + return pStyle; +} + +sal_Bool EditView::IsInsertMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->IsInsertMode(); +} + +void EditView::SetInsertMode( sal_Bool bInsert ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetInsertMode( bInsert ); +} + +void EditView::SetAnchorMode( EVAnchorMode eMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetAnchorMode( eMode ); +} + +EVAnchorMode EditView::GetAnchorMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetAnchorMode(); +} + +void EditView::TransliterateText( sal_Int32 nTransliterationMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + EditSelection aOldSel( pImpEditView->GetEditSelection() ); + EditSelection aNewSel = PIMPEE->TransliterateText( pImpEditView->GetEditSelection(), nTransliterationMode ); + if ( aNewSel != aOldSel ) + { + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( aNewSel ); + pImpEditView->DrawSelection(); + } +} + + +sal_Bool EditView::MatchGroup() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aNewSel( PIMPEE->MatchGroup( pImpEditView->GetEditSelection() ) ); + if ( aNewSel.HasRange() ) + { + pImpEditView->DrawSelection(); + pImpEditView->SetEditSelection( aNewSel ); + pImpEditView->DrawSelection(); + ShowCursor(); + return sal_True; + } + return sal_False; +} + +void EditView::CompleteAutoCorrect() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !pImpEditView->HasSelection() && PIMPEE->GetStatus().DoAutoCorrect() ) + { + pImpEditView->DrawSelection(); + EditSelection aSel = pImpEditView->GetEditSelection(); + aSel = PIMPEE->EndOfWord( aSel.Max() ); + // MT 06/00: Why pass EditSelection to AutoCorrect, not EditPaM?! + aSel = PIMPEE->AutoCorrect( aSel, 0, !IsInsertMode() ); + pImpEditView->SetEditSelection( aSel ); + if ( PIMPEE->IsModified() ) + PIMPEE->FormatAndUpdate( this ); + } +} + +EESpellState EditView::StartSpeller( sal_Bool bMultipleDoc ) +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !PIMPEE->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return PIMPEE->Spell( this, bMultipleDoc ); +#endif +} + +EESpellState EditView::StartThesaurus() +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !PIMPEE->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return PIMPEE->StartThesaurus( this ); +#endif +} + + +void EditView::StartTextConversion( + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, BOOL bIsInteractive, BOOL bMultipleDoc ) +{ +#ifdef SVX_LIGHT +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Convert( this, nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc ); +#endif +} + + +sal_uInt16 EditView::StartSearchAndReplace( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->StartSearchAndReplace( this, rSearchItem ); +} + +sal_Bool EditView::IsCursorAtWrongSpelledWord( sal_Bool bMarkIfWrong ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + sal_Bool bIsWrong = sal_False; + if ( !HasSelection() ) + { + EditPaM aPaM = pImpEditView->GetEditSelection().Max(); + bIsWrong = pImpEditView->IsWrongSpelledWord( aPaM, bMarkIfWrong ); + } + return bIsWrong; +} + +sal_Bool EditView::IsWrongSpelledWordAtPos( const Point& rPosPixel, sal_Bool bMarkIfWrong ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) ); + aPos = pImpEditView->GetDocPos( aPos ); + EditPaM aPaM = pImpEditView->pEditEngine->pImpEditEngine->GetPaM( aPos, sal_False ); + return pImpEditView->IsWrongSpelledWord( aPaM , bMarkIfWrong ); +} + +void EditView::ExecuteSpellPopup( const Point& rPosPixel, Link* pCallBack ) +{ +#ifndef SVX_LIGHT + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) ); + aPos = pImpEditView->GetDocPos( aPos ); + EditPaM aPaM = pImpEditView->pEditEngine->pImpEditEngine->GetPaM( aPos, sal_False ); + Reference< XSpellChecker1 > xSpeller( PIMPEE->GetSpeller() ); + ESelection aOldSel = GetSelection(); + if ( xSpeller.is() && pImpEditView->IsWrongSpelledWord( aPaM, sal_True ) ) + { + PopupMenu aPopupMenu( EditResId( RID_MENU_SPELL ) ); + PopupMenu *pAutoMenu = aPopupMenu.GetPopupMenu( MN_AUTOCORR ); + PopupMenu *pInsertMenu = aPopupMenu.GetPopupMenu( MN_INSERT ); + + EditPaM aPaM2( aPaM ); + aPaM2.GetIndex()++; + + // Gibt es Replace-Vorschlaege? + String aSelected( GetSelected() ); + // + // restrict the maximal number of suggestions displayed + // in the context menu. + // Note: That could of course be done by clipping the + // resulting sequence but the current third party + // implementations result differs greatly if the number of + // suggestions to be retuned gets changed. Statistically + // it gets much better if told to return e.g. only 7 strings + // than returning e.g. 16 suggestions and using only the + // first 7. Thus we hand down the value to use to that + // implementation here by providing an additional parameter. + Sequence< PropertyValue > aPropVals(1); + PropertyValue &rVal = aPropVals.getArray()[0]; + rVal.Name = OUString::createFromAscii( UPN_MAX_NUMBER_OF_SUGGESTIONS ); + rVal.Value <<= (INT16) 7; + // + // Gibt es Replace-Vorschlaege? + Reference< XSpellAlternatives > xSpellAlt = + xSpeller->spell( aSelected, PIMPEE->GetLanguage( aPaM2 ), aPropVals ); + + Reference< XLanguageGuessing > xLangGuesser( EE_DLL()->GetGlobalData()->GetLanguageGuesser() ); + + // check if text might belong to a different language... + LanguageType nGuessLangWord = LANGUAGE_NONE; + LanguageType nGuessLangPara = LANGUAGE_NONE; + if (xSpellAlt.is() && xLangGuesser.is()) + { + String aParaText; + ContentNode *pNode = aPaM.GetNode(); + if (pNode) + { + aParaText = *pNode; + } + else + { + DBG_ERROR( "content node is NULL" ); + } + + nGuessLangWord = lcl_CheckLanguage( xSpellAlt->getWord(), xSpeller, xLangGuesser, sal_False ); + nGuessLangPara = lcl_CheckLanguage( aParaText, xSpeller, xLangGuesser, sal_True ); + } + if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE) + { + // make sure LANGUAGE_NONE gets not used as menu entry + if (nGuessLangWord == LANGUAGE_NONE) + nGuessLangWord = nGuessLangPara; + if (nGuessLangPara == LANGUAGE_NONE) + nGuessLangPara = nGuessLangWord; + + aPopupMenu.InsertSeparator(); + String aTmpWord( SvtLanguageTable::GetLanguageString( nGuessLangWord ) ); + String aTmpPara( SvtLanguageTable::GetLanguageString( nGuessLangPara ) ); + String aWordStr( EditResId( RID_STR_WORD ) ); + aWordStr.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "%x" ) ), aTmpWord ); + String aParaStr( EditResId( RID_STR_PARAGRAPH ) ); + aParaStr.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "%x" ) ), aTmpPara ); + aPopupMenu.InsertItem( MN_WORDLANGUAGE, aWordStr ); + aPopupMenu.SetHelpId( MN_WORDLANGUAGE, HID_EDITENG_SPELLER_WORDLANGUAGE ); + aPopupMenu.InsertItem( MN_PARALANGUAGE, aParaStr ); + aPopupMenu.SetHelpId( MN_PARALANGUAGE, HID_EDITENG_SPELLER_PARALANGUAGE ); + } + + // ## Create mnemonics here + if ( Application::IsAutoMnemonicEnabled() ) + { + aPopupMenu.CreateAutoMnemonics(); + aPopupMenu.SetMenuFlags( aPopupMenu.GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); + } + + // Replace suggestions... + Sequence< OUString > aAlt; + if (xSpellAlt.is()) + aAlt = xSpellAlt->getAlternatives(); + const OUString *pAlt = aAlt.getConstArray(); + sal_uInt16 nWords = (USHORT) aAlt.getLength(); + if ( nWords ) + { + for ( sal_uInt16 nW = 0; nW < nWords; nW++ ) + { + String aAlternate( pAlt[nW] ); + aPopupMenu.InsertItem( MN_ALTSTART+nW, aAlternate, 0, nW ); + pAutoMenu->InsertItem( MN_AUTOSTART+nW, aAlternate, 0, nW ); + } + aPopupMenu.InsertSeparator( nWords ); + } + else + aPopupMenu.RemoveItem( MN_AUTOCORR ); // Loeschen? + + Reference< XDictionaryList > xDicList( SvxGetDictionaryList() ); + + Sequence< Reference< XDictionary > > aDics; + if (xDicList.is()) + aDics = xDicList->getDictionaries(); + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_uInt16 nLanguage = PIMPEE->GetLanguage( aPaM2 ); + sal_uInt16 nDicCount = (USHORT)aDics.getLength(); + for ( sal_uInt16 i = 0; i < nDicCount; i++ ) + { + Reference< XDictionary > xDic( pDic[i], UNO_QUERY ); + if (xDic.is()) + { + sal_uInt16 nActLanguage = SvxLocaleToLanguage( xDic->getLocale() ); + if( xDic->isActive() && + xDic->getDictionaryType() == DictionaryType_POSITIVE && + (nLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage ) ) + { + pInsertMenu->InsertItem( MN_DICTSTART + i, xDic->getName() ); + } + } + } + + if ( !pInsertMenu->GetItemCount() ) + aPopupMenu.EnableItem( MN_INSERT, sal_False ); + + aPopupMenu.RemoveDisabledEntries( sal_True, sal_True ); + + Rectangle aTempRect = PIMPEE->PaMtoEditCursor( aPaM, GETCRSR_TXTONLY ); + Point aScreenPos = pImpEditView->GetWindowPos( aTempRect.TopLeft() ); + aScreenPos = pImpEditView->GetWindow()->OutputToScreenPixel( aScreenPos ); + aTempRect = pImpEditView->GetWindow()->LogicToPixel( Rectangle(aScreenPos, aTempRect.GetSize() )); + + sal_uInt16 nId = aPopupMenu.Execute( pImpEditView->GetWindow(), aTempRect, POPUPMENU_NOMOUSEUPCLOSE ); + if ( nId == MN_IGNORE ) + { + String aWord = pImpEditView->SpellIgnoreOrAddWord( sal_False ); + if ( pCallBack ) + { + SpellCallbackInfo aInf( SPELLCMD_IGNOREWORD, aWord ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( ( nId == MN_WORDLANGUAGE ) || ( nId == MN_PARALANGUAGE ) ) + { + LanguageType nLangToUse = (nId == MN_WORDLANGUAGE) ? nGuessLangWord : nGuessLangPara; + sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse ); + + SfxItemSet aAttrs = GetEditEngine()->GetEmptyItemSet(); + if (nScriptType == SCRIPTTYPE_LATIN) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) ); + if (nScriptType == SCRIPTTYPE_COMPLEX) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) ); + if (nScriptType == SCRIPTTYPE_ASIAN) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) ); + if ( nId == MN_PARALANGUAGE ) + { + ESelection aSel = GetSelection(); + aSel.nStartPos = 0; + aSel.nEndPos = 0xFFFF; + SetSelection( aSel ); + } + SetAttribs( aAttrs ); + PIMPEE->StartOnlineSpellTimer(); + + if ( pCallBack ) + { + SpellCallbackInfo aInf( ( nId == MN_WORDLANGUAGE ) ? SPELLCMD_WORDLANGUAGE : SPELLCMD_PARALANGUAGE, nLangToUse ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( nId == MN_SPELLING ) + { + if ( !pCallBack ) + { + // Cursor vor das Wort setzen... + EditPaM aCursor = pImpEditView->GetEditSelection().Min(); + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( EditSelection( aCursor, aCursor ) ); + pImpEditView->DrawSelection(); + // Stuerzt ab, wenn keine SfxApp + PIMPEE->Spell( this, sal_False ); + } + else + { + SpellCallbackInfo aInf( SPELLCMD_STARTSPELLDLG, String() ); + pCallBack->Call( &aInf ); + } + } + else if ( nId >= MN_DICTSTART ) + { + Reference< XDictionary > xDic( pDic[nId - MN_DICTSTART], UNO_QUERY ); + if (xDic.is()) + xDic->add( aSelected, sal_False, String() ); + // save modified user-dictionary if it is persistent + Reference< frame::XStorable > xSavDic( xDic, UNO_QUERY ); + if (xSavDic.is()) + xSavDic->store(); + + aPaM.GetNode()->GetWrongList()->GetInvalidStart() = 0; + aPaM.GetNode()->GetWrongList()->GetInvalidEnd() = aPaM.GetNode()->Len(); + PIMPEE->StartOnlineSpellTimer(); + + if ( pCallBack ) + { + SpellCallbackInfo aInf( SPELLCMD_ADDTODICTIONARY, aSelected ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( nId >= MN_AUTOSTART ) + { + DBG_ASSERT(nId - MN_AUTOSTART < aAlt.getLength(), "index out of range"); + String aWord = pAlt[nId - MN_AUTOSTART]; + SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get()->GetAutoCorrect(); + if ( pAutoCorrect ) + pAutoCorrect->PutText( aSelected, aWord, PIMPEE->GetLanguage( aPaM2 ) ); + InsertText( aWord ); + } + else if ( nId >= MN_ALTSTART ) // Replace + { + DBG_ASSERT(nId - MN_ALTSTART < aAlt.getLength(), "index out of range"); + String aWord = pAlt[nId - MN_ALTSTART]; + InsertText( aWord ); + } + else + { + SetSelection( aOldSel ); + } + } +#endif +} + +void EditView::SpellIgnoreWord() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->SpellIgnoreOrAddWord( sal_False ); +} + +sal_Bool EditView::SelectCurrentWord() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aCurSel( pImpEditView->GetEditSelection() ); + pImpEditView->DrawSelection(); + aCurSel = PIMPEE->SelectWord( aCurSel.Max() ); + pImpEditView->SetEditSelection( aCurSel ); + pImpEditView->DrawSelection(); + ShowCursor( sal_True, sal_False ); + return aCurSel.HasRange() ? sal_True : sal_False; +} + +void EditView::InsertField( const SvxFieldItem& rFld ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ImpEditEngine* pImpEE = PIMPEE; + pImpEditView->DrawSelection(); + pImpEE->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM( pImpEE->InsertField( pImpEditView->GetEditSelection(), rFld ) ); + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) ); + pImpEE->UpdateFields(); + pImpEE->FormatAndUpdate( this ); +} + +const SvxFieldItem* EditView::GetFieldUnderMousePointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + sal_uInt16 nPara, nPos; + return GetFieldUnderMousePointer( nPara, nPos ); +} + +const SvxFieldItem* EditView::GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->GetField( rPos, pPara, pPos ); +} + +const SvxFieldItem* EditView::GetFieldUnderMousePointer( sal_uInt16& nPara, sal_uInt16& nPos ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aPos = pImpEditView->GetWindow()->GetPointerPosPixel(); + aPos = pImpEditView->GetWindow()->PixelToLogic( aPos ); + return GetField( aPos, &nPara, &nPos ); +} + +const SvxFieldItem* EditView::GetFieldAtSelection() const +{ + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( pImpEditView->pEditEngine->pImpEditEngine->GetEditDoc() ); + // Nur wenn Cursor vor Feld, keine Selektion, oder nur Feld selektiert + if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && + ( ( aSel.Max().GetIndex() == aSel.Min().GetIndex() ) || + ( aSel.Max().GetIndex() == aSel.Min().GetIndex()+1 ) ) ) + { + EditPaM aPaM = aSel.Min(); + const CharAttribArray& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs(); + sal_uInt16 nXPos = aPaM.GetIndex(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->GetStart() == nXPos ) + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + return (const SvxFieldItem*)pAttr->GetItem(); + } + } + } + return 0; +} + +XubString EditView::GetWordUnderMousePointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Rectangle aRect; + return GetWordUnderMousePointer( aRect ); +} + +XubString EditView::GetWordUnderMousePointer( Rectangle& rWordRect ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Point aPos = pImpEditView->GetWindow()->GetPointerPosPixel(); + aPos = pImpEditView->GetWindow()->PixelToLogic( aPos ); + + XubString aWord; + + if( GetOutputArea().IsInside( aPos ) ) + { + ImpEditEngine* pImpEE = pImpEditView->pEditEngine->pImpEditEngine; + Point aDocPos( pImpEditView->GetDocPos( aPos ) ); + EditPaM aPaM = pImpEE->GetPaM( aDocPos, sal_False ); + EditSelection aWordSel = pImpEE->SelectWord( aPaM ); + + Rectangle aTopLeftRec( pImpEE->PaMtoEditCursor( aWordSel.Min() ) ); + Rectangle aBottomRightRec( pImpEE->PaMtoEditCursor( aWordSel.Max() ) ); + +#if OSL_DEBUG_LEVEL > 1 + DBG_ASSERT( aTopLeftRec.Top() == aBottomRightRec.Top(), "Top() in einer Zeile unterschiedlich?" ); +#endif + + Point aPnt1( pImpEditView->GetWindowPos( aTopLeftRec.TopLeft() ) ); + Point aPnt2( pImpEditView->GetWindowPos( aBottomRightRec.BottomRight()) ); + rWordRect = Rectangle( aPnt1, aPnt2 ); + aWord = pImpEE->GetSelected( aWordSel ); + } + + return aWord; +} + +void EditView::SetInvalidateMore( sal_uInt16 nPixel ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetInvalidateMore( nPixel ); +} + +sal_uInt16 EditView::GetInvalidateMore() const +{ + DBG_CHKTHIS( EditView, 0 ); + return (sal_uInt16)pImpEditView->GetInvalidateMore(); +} + +static void ChangeFontSizeImpl( EditView* pEditView, bool bGrow, const ESelection& rSel, const FontList* pFontList ) +{ + pEditView->SetSelection( rSel ); + + SfxItemSet aSet( pEditView->GetAttribs() ); + if( EditView::ChangeFontSize( bGrow, aSet, pFontList ) ) + { + SfxItemSet aNewSet( pEditView->GetEmptyItemSet() ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT ), EE_CHAR_FONTHEIGHT ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CJK ), EE_CHAR_FONTHEIGHT_CJK ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CTL ), EE_CHAR_FONTHEIGHT_CTL ); + pEditView->SetAttribs( aNewSet ); + } +} + +void EditView::ChangeFontSize( bool bGrow, const FontList* pFontList ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + EditEngine& rEditEngine = *pImpEditView->pEditEngine; + + ESelection aSel( GetSelection() ); + ESelection aOldSelection( aSel ); + aSel.Adjust(); + + if( !aSel.HasRange() ) + { + aSel = rEditEngine.GetWord( aSel, com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } + + if( aSel.HasRange() ) + { + for( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + SvUShorts aPortions; + rEditEngine.GetPortions( nPara, aPortions ); + + if( aPortions.Count() == 0 ) + aPortions.Insert( rEditEngine.GetTextLen(nPara), 0 ); + + const USHORT nBeginPos = (nPara == aSel.nStartPara) ? aSel.nStartPos : 0; + const USHORT nEndPos = (nPara == aSel.nEndPara) ? aSel.nEndPos : 0xffff; + + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nPortionEnd = aPortions.GetObject( nPos ); + USHORT nPortionStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + if( (nPortionEnd < nBeginPos) || (nPortionStart > nEndPos) ) + continue; + + if( nPortionStart < nBeginPos ) + nPortionStart = nBeginPos; + if( nPortionEnd > nEndPos ) + nPortionEnd = nEndPos; + + if( nPortionStart == nPortionEnd ) + continue; + + ESelection aPortionSel( nPara, nPortionStart, nPara, nPortionEnd ); + ChangeFontSizeImpl( this, bGrow, aPortionSel, pFontList ); + } + } + } + else + { + ChangeFontSizeImpl( this, bGrow, aSel, pFontList ); + } + + SetSelection( aOldSelection ); +} + +bool EditView::ChangeFontSize( bool bGrow, SfxItemSet& rSet, const FontList* pFontList ) +{ + static const sal_uInt16 gFontSizeWichMap[] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL, 0 }; + + const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(&rSet.Get( EE_CHAR_FONTINFO )); + if( !pFontItem || !pFontList ) + return false; + + bool bRet = false; + + const sal_uInt16* pWhich = gFontSizeWichMap; + while( *pWhich ) + { + SvxFontHeightItem aFontHeightItem( static_cast<const SvxFontHeightItem&>(rSet.Get( *pWhich )) ); + long nHeight = aFontHeightItem.GetHeight(); + const SfxMapUnit eUnit = rSet.GetPool()->GetMetric( *pWhich ); + nHeight = OutputDevice::LogicToLogic( nHeight * 10, (MapUnit)eUnit, MAP_POINT ); + + FontInfo aFontInfo = pFontList->Get( pFontItem->GetFamilyName(), pFontItem->GetStyleName() ); + const long* pAry = pFontList->GetSizeAry( aFontInfo ); + + if( bGrow ) + { + while( *pAry ) + { + if( *pAry > nHeight ) + { + nHeight = *pAry; + break; + } + pAry++; + } + + if( *pAry == 0 ) + { + nHeight += (nHeight + 5) / 10; + if( nHeight > 9999 ) + nHeight = 9999; + } + + } + else if( *pAry ) + { + bool bFound = false; + if( *pAry < nHeight ) + { + pAry++; + while( *pAry ) + { + if( *pAry >= nHeight ) + { + nHeight = pAry[-1]; + bFound = true; + break; + } + pAry++; + } + } + + if( !bFound ) + { + nHeight -= (nHeight + 5) / 10; + if( nHeight < 2 ) + nHeight = 2; + } + } + + if( (nHeight >= 2) && (nHeight <= 9999 ) ) + { + nHeight = OutputDevice::LogicToLogic( nHeight, MAP_POINT, (MapUnit)eUnit ) / 10; + + if( nHeight != (long)aFontHeightItem.GetHeight() ) + { + aFontHeightItem.SetHeight( nHeight ); + rSet.Put( aFontHeightItem, *pWhich ); + bRet = true; + } + } + pWhich++; + } + return bRet; +} + +String EditView::GetSurroundingText() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( PIMPEE->GetEditDoc() ); + + if( HasSelection() ) + { + XubString aStr = PIMPEE->GetSelected( aSel ); + + // Stop reconversion if the selected text includes a line break. + if ( aStr.Search( 0x0A ) == STRING_NOTFOUND ) + return aStr; + else + return String(); + } + else + { + aSel.Min().SetIndex( 0 ); + aSel.Max().SetIndex( aSel.Max().GetNode()->Len() ); + return PIMPEE->GetSelected( aSel ); + } +} + +Selection EditView::GetSurroundingTextSelection() const +{ + DBG_CHKTHIS( EditView, 0 ); + + ESelection aSelection( GetSelection() ); + aSelection.Adjust(); + + if( HasSelection() ) + { + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( PIMPEE->GetEditDoc() ); + XubString aStr = PIMPEE->GetSelected( aSel ); + + // Stop reconversion if the selected text includes a line break. + if ( aStr.Search( 0x0A ) == STRING_NOTFOUND ) + return Selection( 0, aSelection.nEndPos - aSelection.nStartPos ); + else + return Selection( 0, 0 ); + } + else + { + return Selection( aSelection.nStartPos, aSelection.nEndPos ); + } +} diff --git a/editeng/source/editeng/edtspell.cxx b/editeng/source/editeng/edtspell.cxx new file mode 100644 index 000000000000..fed1394e5fd0 --- /dev/null +++ b/editeng/source/editeng/edtspell.cxx @@ -0,0 +1,746 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <edtspell.hxx> +#include <editeng/flditem.hxx> +#include <editeng/fontitem.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +using ::rtl::OUString; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::linguistic2; + + +EditSpellWrapper::EditSpellWrapper( Window* _pWin, + Reference< XSpellChecker1 > &xChecker, + sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) : + SvxSpellWrapper( _pWin, xChecker, bIsStart, bIsAllRight ) +{ + DBG_ASSERT( pView, "Es muss eine View uebergeben werden!" ); + // IgnoreList behalten, ReplaceList loeschen... + if (SvxGetChangeAllList().is()) + SvxGetChangeAllList()->clear(); + pEditView = pView; +} + +void __EXPORT EditSpellWrapper::SpellStart( SvxSpellArea eArea ) +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + + if ( eArea == SVX_SPELL_BODY_START ) + { + // Wird gerufen, wenn + // a) Spell-Forwad ist am Ende angekomment und soll von vorne beginnen + // IsEndDone() liefert auch sal_True, wenn Rueckwaerts-Spelling am Ende gestartet wird! + if ( IsEndDone() ) + { + pSpellInfo->bSpellToEnd = sal_False; + pSpellInfo->aSpellTo = pSpellInfo->aSpellStart; + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + else + { + pSpellInfo->bSpellToEnd = sal_True; + pSpellInfo->aSpellTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY_END ) + { + // Wird gerufen, wenn + // a) Spell-Forwad wird gestartet + // IsStartDone() liefert auch sal_True, wenn Vorwaerts-Spelling am Anfang gestartet wird! + if ( !IsStartDone() ) + { + pSpellInfo->bSpellToEnd = sal_True; + pSpellInfo->aSpellTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + } + else + { + pSpellInfo->bSpellToEnd = sal_False; + pSpellInfo->aSpellTo = pSpellInfo->aSpellStart; + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetEndPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY ) + { + ; // Wird ueber SpellNextDocument von App gehandelt + + // pSpellInfo->bSpellToEnd = sal_True; + // pSpellInfo->aSpellTo = pImpEE->CreateEPaM( pImpEE->GetEditDoc().GetEndPaM() ); + } + else + { + DBG_ERROR( "SpellStart: Unknown Area!" ); + } +} + +sal_Bool EditSpellWrapper::SpellContinue() +{ + SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) ); + return GetLast().is(); +} + +void __EXPORT EditSpellWrapper::SpellEnd() +{ + // Base class will show language errors... + SvxSpellWrapper::SpellEnd(); +} + +sal_Bool __EXPORT EditSpellWrapper::HasOtherCnt() +{ + return sal_False; +} + +sal_Bool __EXPORT EditSpellWrapper::SpellMore() +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + sal_Bool bMore = sal_False; + if ( pSpellInfo->bMultipleDoc ) + { + bMore = pImpEE->GetEditEnginePtr()->SpellNextDocument(); + if ( bMore ) + { + // Der Text wurde in diese Engine getreten, bei Rueckwaerts + // muss die Selektion hinten sein. + Reference< XPropertySet > xProp( SvxGetLinguPropertySet() ); + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + return bMore; +} + +void __EXPORT EditSpellWrapper::ScrollArea() +{ + // Keine weitere Aktion noetig... + // Es sei denn, der Bereich soll in die Mitte gescrollt werden, + // und nicht irgendwo stehen. +} + +void __EXPORT EditSpellWrapper::ReplaceAll( const String &rNewText, + sal_Int16 ) +{ + // Wird gerufen, wenn Wort in ReplaceList des SpellCheckers + pEditView->InsertText( rNewText ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::ChangeWord( const String& rNewWord, + const sal_uInt16 ) +{ + // Wird gerufen, wenn Wort Button Change + // bzw. intern von mir bei ChangeAll + + // Wenn Punkt hinterm Wort, wird dieser nicht mitgegeben. + // Falls '"' => PreStripped. + String aNewWord( rNewWord ); + pEditView->InsertText( aNewWord ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::ChangeThesWord( const String& rNewWord ) +{ + pEditView->InsertText( rNewWord ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::AutoCorrect( const String&, const String& ) +{ +} + +void EditSpellWrapper::CheckSpellTo() +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() ); + EPaM aEPaM = pImpEE->CreateEPaM( aPaM ); + if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara ) + { + // prueffen, ob SpellToEnd noch gueltiger Index, falls in dem Absatz + // ersetzt wurde. + if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() ) + pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len(); + } +} +SV_IMPL_VARARR( WrongRanges, WrongRange ); + +WrongList::WrongList() +{ + nInvalidStart = 0; + nInvalidEnd = 0xFFFF; +} + +WrongList::~WrongList() +{ +} + +void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep ) +{ + if ( !IsInvalid() ) + { + nInvalidStart = nPos; + nInvalidEnd = nPos+nNew; + } + else + { + if ( nInvalidStart > nPos ) + nInvalidStart = nPos; + if ( nInvalidEnd >= nPos ) + nInvalidEnd = nInvalidEnd + nNew; + else + nInvalidEnd = nPos+nNew; + } + + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + sal_Bool bRefIsValid = sal_True; + if ( rWrong.nEnd >= nPos ) + { + // Alle Wrongs hinter der Einfuegeposition verschieben... + if ( rWrong.nStart > nPos ) + { + rWrong.nStart = rWrong.nStart + nNew; + rWrong.nEnd = rWrong.nEnd + nNew; + } + // 1: Startet davor, geht bis nPos... + else if ( rWrong.nEnd == nPos ) + { + // Sollte bei einem Blank unterbunden werden! + if ( !bPosIsSep ) + rWrong.nEnd = rWrong.nEnd + nNew; + } + // 2: Startet davor, geht hinter Pos... + else if ( ( rWrong.nStart < nPos ) && ( rWrong.nEnd > nPos ) ) + { + rWrong.nEnd = rWrong.nEnd + nNew; + // Bei einem Trenner das Wrong entfernen und neu pruefen + if ( bPosIsSep ) + { + // Wrong aufteilen... + WrongRange aNewWrong( rWrong.nStart, nPos ); + rWrong.nStart = nPos+1; + Insert( aNewWrong, n ); + bRefIsValid = sal_False; // Referenz nach Insert nicht mehr gueltig, der andere wurde davor an dessen Position eingefuegt + n++; // Diesen nicht nochmal... + } + } + // 3: Attribut startet auf Pos... + else if ( rWrong.nStart == nPos ) + { + rWrong.nEnd = rWrong.nEnd + nNew; + if ( bPosIsSep ) + rWrong.nStart++; + } + } + DBG_ASSERT( !bRefIsValid || ( rWrong.nStart < rWrong.nEnd ), + "TextInserted, WrongRange: Start >= End?!" ); + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted ) +{ + sal_uInt16 nEndChanges = nPos+nDeleted; + if ( !IsInvalid() ) + { + sal_uInt16 nNewInvalidStart = nPos ? nPos - 1 : 0; + nInvalidStart = nNewInvalidStart; + nInvalidEnd = nNewInvalidStart + 1; + } + else + { + if ( nInvalidStart > nPos ) + nInvalidStart = nPos; + if ( nInvalidEnd > nPos ) + { + if ( nInvalidEnd > nEndChanges ) + nInvalidEnd = nInvalidEnd - nDeleted; + else + nInvalidEnd = nPos+1; + } + } + + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + sal_Bool bDelWrong = sal_False; + if ( rWrong.nEnd >= nPos ) + { + // Alles Wrongs hinter der Einfuegeposition verschieben... + if ( rWrong.nStart >= nEndChanges ) + { + rWrong.nStart = rWrong.nStart - nDeleted; + rWrong.nEnd = rWrong.nEnd - nDeleted; + } + // 1. Innenliegende Wrongs loeschen... + else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd <= nEndChanges ) ) + { + bDelWrong = sal_True; + } + // 2. Wrong beginnt davor, endet drinnen oder dahinter... + else if ( ( rWrong.nStart <= nPos ) && ( rWrong.nEnd > nPos ) ) + { + if ( rWrong.nEnd <= nEndChanges ) // endet drinnen + rWrong.nEnd = nPos; + else + rWrong.nEnd = rWrong.nEnd - nDeleted; // endet dahinter + } + // 3. Wrong beginnt drinnen, endet dahinter... + else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd > nEndChanges ) ) + { + rWrong.nStart = nEndChanges; + rWrong.nStart = rWrong.nStart - nDeleted; + rWrong.nEnd = rWrong.nEnd - nDeleted; + } + } + DBG_ASSERT( rWrong.nStart < rWrong.nEnd, + "TextInserted, WrongRange: Start >= End?!" ); + if ( bDelWrong ) + { + Remove( n, 1 ); + n--; + } + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const +{ + /* + rnStart enthaelt die Startposition, wird ggf. auf Wrong-Start korrigiert + rnEnd braucht nicht inizialisiert sein. + */ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( rWrong.nEnd > rnStart ) + { + rnStart = rWrong.nStart; + rnEnd = rWrong.nEnd; + return sal_True; + } + } + return sal_False; +} + +sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd == nEnd ) ) + return sal_True; + else if ( rWrong.nStart >= nStart ) + break; + } + return sal_False; +} + +sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nEnd >= nStart ) && ( rWrong.nStart < nEnd ) ) + return sal_True; + else if ( rWrong.nStart >= nEnd ) + break; + } + return sal_False; +} + +void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd, + const ContentNode* pNode ) +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nEnd > nStart ) && ( rWrong.nStart < nEnd ) ) + { + if ( rWrong.nEnd > nEnd ) // // Laeuft raus + { + rWrong.nStart = nEnd; + // Blanks? + while ( ( rWrong.nStart < pNode->Len() ) && + ( ( pNode->GetChar( rWrong.nStart ) == ' ' ) || + ( pNode->IsFeature( rWrong.nStart ) ) ) ) + { + rWrong.nStart++; + } + } + else + { + Remove( n, 1 ); + n--; + } + } + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd, + sal_Bool bClearRange ) +{ + sal_uInt16 nPos = Count(); + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( rWrong.nStart >= nStart ) + { + nPos = n; + if ( bClearRange ) + { + // Es kann eigentlich nur Passieren, dass der Wrong genau + // hier beginnt und weiter rauslauft, aber nicht, dass hier + // mehrere im Bereich liegen... + // Genau im Bereich darf keiner liegen, sonst darf diese Methode + // garnicht erst gerufen werden! + DBG_ASSERT( ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) ) + || ( rWrong.nStart > nEnd ), "InsertWrong: RangeMismatch!" ); + if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) ) + rWrong.nStart = nEnd+1; + } + break; + } + } + Insert( WrongRange( nStart, nEnd ), nPos ); + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::MarkWrongsInvalid() +{ + if ( Count() ) + MarkInvalid( GetObject( 0 ).nStart, GetObject( Count()-1 ).nEnd ); +} + +WrongList* WrongList::Clone() const +{ + WrongList* pNew = new WrongList; + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + pNew->Insert( rWrong, pNew->Count() ); + } + + return pNew; +} + +// #i102062# +bool WrongList::operator==(const WrongList& rCompare) const +{ + // cleck direct members + if(GetInvalidStart() != rCompare.GetInvalidStart() + || GetInvalidEnd() != rCompare.GetInvalidEnd() + || Count() != rCompare.Count()) + { + return false; + } + + for(USHORT a(0); a < Count(); a++) + { + const WrongRange& rCandA(GetObject(a)); + const WrongRange& rCandB(rCompare.GetObject(a)); + + if(rCandA.nStart != rCandB.nStart + || rCandA.nEnd != rCandB.nEnd) + { + return false; + } + } + + return true; +} + +#ifdef DBG_UTIL +sal_Bool WrongList::DbgIsBuggy() const +{ + // Pruefen, ob sich Bereiche ueberlappen + sal_Bool bError = sal_False; + for ( sal_uInt16 _nA = 0; !bError && ( _nA < Count() ); _nA++ ) + { + WrongRange& rWrong = GetObject( _nA ); + for ( sal_uInt16 nB = _nA+1; !bError && ( nB < Count() ); nB++ ) + { + WrongRange& rNextWrong = GetObject( nB ); + // 1) Start davor, End hinterm anderen Start + if ( ( rWrong.nStart <= rNextWrong.nStart ) + && ( rWrong.nEnd >= rNextWrong.nStart ) ) + bError = sal_True; + // 2) Start hinter anderen Start, aber noch vorm anderen End + else if ( ( rWrong.nStart >= rNextWrong.nStart) + && ( rWrong.nStart <= rNextWrong.nEnd ) ) + bError = sal_True; + } + } + return bError; +} +#endif + + +EdtAutoCorrDoc::EdtAutoCorrDoc( ImpEditEngine* pE, ContentNode* pN, + sal_uInt16 nCrsr, xub_Unicode cIns ) +{ + pImpEE = pE; + pCurNode = pN; + nCursor = nCrsr; + + bUndoAction = sal_False; + bAllowUndoAction = cIns ? sal_True : sal_False; +} + +EdtAutoCorrDoc::~EdtAutoCorrDoc() +{ + if ( bUndoAction ) + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); +} + +sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd ) +{ + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEnd-nStt ); + bAllowUndoAction = sal_False; + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt ) +{ + EditSelection aSel = EditPaM( pCurNode, nPos ); + pImpEE->ImpInsertText( aSel, rTxt ); + DBG_ASSERT( nCursor >= nPos, "Cursor mitten im Geschehen ?!" ); + nCursor = nCursor + rTxt.Len(); + + if ( bAllowUndoAction && ( rTxt.Len() == 1 ) ) + ImplStartUndoAction(); + bAllowUndoAction = sal_False; + + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt ) +{ + // Eigentlich ein Replace einfuehren => Entspr. UNDO + sal_uInt16 nEnd = nPos+rTxt.Len(); + if ( nEnd > pCurNode->Len() ) + nEnd = pCurNode->Len(); + + // #i5925# First insert new text behind to be deleted text, for keeping attributes. + pImpEE->ImpInsertText( EditSelection( EditPaM( pCurNode, nEnd ) ), rTxt ); + pImpEE->ImpDeleteSelection( EditSelection( EditPaM( pCurNode, nPos ), EditPaM( pCurNode, nEnd ) ) ); + + if ( nPos == nCursor ) + nCursor = nCursor + rTxt.Len(); + + if ( bAllowUndoAction && ( rTxt.Len() == 1 ) ) + ImplStartUndoAction(); + + bAllowUndoAction = sal_False; + + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd, + sal_uInt16 nSlotId, SfxPoolItem& rItem ) +{ + SfxItemPool* pPool = &pImpEE->GetEditDoc().GetItemPool(); + while ( pPool->GetSecondaryPool() && + !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) + { + pPool = pPool->GetSecondaryPool(); + + } + sal_uInt16 nWhich = pPool->GetWhich( nSlotId ); + if ( nWhich ) + { + rItem.SetWhich( nWhich ); + + SfxItemSet aSet( pImpEE->GetEmptyItemSet() ); + aSet.Put( rItem ); + + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + aSel.Max().SetIndex( nEnd ); // ??? + pImpEE->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE ); + bAllowUndoAction = sal_False; + } + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd, + const String& rURL ) +{ + // Aus dem Text ein Feldbefehl machen... + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + String aText = pImpEE->GetSelected( aSel ); + aSel = pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEnd-nStt ); + SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ), + EE_FEATURE_FIELD ); + pImpEE->InsertField( aSel, aField ); + nCursor++; + pImpEE->UpdateFields(); + bAllowUndoAction = sal_False; + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd ) +{ + USHORT nScriptType = pImpEE->GetScriptType( EditPaM( pCurNode, nStt ) ); + USHORT nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); + + CharAttribArray& rAttribs = pCurNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttrs = rAttribs.Count(); + for ( sal_uInt16 n = 0; n < nAttrs; n++ ) + { + EditCharAttrib* pAttr = rAttribs.GetObject( n ); + if ( pAttr->GetStart() >= nEnd ) + return sal_False; + + if ( ( pAttr->Which() == nScriptFontInfoItemId ) && + ( ((SvxFontItem*)pAttr->GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + { + // Pruefen, ob das Attribt im Bereich liegt... + if ( pAttr->GetEnd() >= nStt ) + return sal_True; + } + } + return sal_False; +} + +const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool ) +{ + // Vorherigen Absatz zurueck geben, damit ermittel werden kann, + // ob es sich beim aktuellen Wort um einen Satzanfang handelt. + + bAllowUndoAction = sal_False; // Jetzt nicht mehr... + + ContentList& rNodes = pImpEE->GetEditDoc(); + sal_uInt16 nPos = rNodes.GetPos( pCurNode ); + + // Sonderbehandlung: Bullet => Absatzanfang => einfach NULL returnen... + const SfxBoolItem& rBulletState = (const SfxBoolItem&) + pImpEE->GetParaAttrib( nPos, EE_PARA_BULLETSTATE ); + sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False; + if ( !bBullet && ( pImpEE->aStatus.GetControlWord() & EE_CNTRL_OUTLINER ) ) + { + // Der Outliner hat im Gliederungsmodus auf Ebene 0 immer ein Bullet. + const SfxInt16Item& rLevel = (const SfxInt16Item&) + pImpEE->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL ); + if ( rLevel.GetValue() == 0 ) + bBullet = sal_True; + } + if ( bBullet ) + return NULL; + + for ( sal_uInt16 n = nPos; n; ) + { + n--; + ContentNode* pNode = rNodes[n]; + if ( pNode->Len() ) + return pNode; + } + return NULL; + +} + +sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos, + sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect, + const String** ppPara ) +{ + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + + bAllowUndoAction = sal_False; // Jetzt nicht mehr... + + String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) ); + sal_Bool bRet = sal_False; + + if( !aShort.Len() ) + return bRet; + + LanguageType eLang = pImpEE->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) ); + const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( *pCurNode, rSttPos, nEndPos, *this, eLang ); + if( pFnd && pFnd->IsTextOnly() ) + { + // dann mal ersetzen + EditSelection aSel( EditPaM( pCurNode, rSttPos ), + EditPaM( pCurNode, nEndPos ) ); + aSel = pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEndPos, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEndPos-rSttPos ); + pImpEE->ImpInsertText( aSel, pFnd->GetLong() ); + nCursor = nCursor + pFnd->GetLong().Len(); + if( ppPara ) + *ppPara = pCurNode; + bRet = sal_True; + } + + return bRet; +} + +LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool ) const +{ + return pImpEE->GetLanguage( EditPaM( pCurNode, nPos+1 ) ); +} + +void EdtAutoCorrDoc::ImplStartUndoAction() +{ + sal_uInt16 nPara = pImpEE->GetEditDoc().GetPos( pCurNode ); + ESelection aSel( nPara, nCursor, nPara, nCursor ); + pImpEE->UndoActionStart( EDITUNDO_INSERT, aSel ); + bUndoAction = sal_True; + bAllowUndoAction = sal_False; +} + diff --git a/editeng/source/editeng/edtspell.hxx b/editeng/source/editeng/edtspell.hxx new file mode 100644 index 000000000000..cfe0aaf57e87 --- /dev/null +++ b/editeng/source/editeng/edtspell.hxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDTSPELL_HXX +#define _EDTSPELL_HXX + +#include <svtools/svxbox.hxx> +#include <editeng/svxenum.hxx> +#include <editeng/splwrap.hxx> +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Reference.h> +#include <editeng/editengdllapi.h> + +namespace com { namespace sun { namespace star { namespace linguistic2 { + class XSpellChecker1; +}}}} + + +class EditView; +class ImpEditEngine; +class ContentNode; + +class EditSpellWrapper : public SvxSpellWrapper +{ +private: + EditView* pEditView; + void CheckSpellTo(); + +protected: + virtual void SpellStart( SvxSpellArea eArea ); + virtual BOOL SpellContinue(); // Bereich pruefen + virtual void ReplaceAll( const String &rNewText, INT16 nLanguage ); + virtual void SpellEnd(); + virtual BOOL SpellMore(); + virtual BOOL HasOtherCnt(); + virtual void ScrollArea(); + virtual void ChangeWord( const String& rNewWord, const USHORT nLang ); + virtual void ChangeThesWord( const String& rNewWord ); + virtual void AutoCorrect( const String& rOldWord, const String& rNewWord ); + +public: + EditSpellWrapper( Window* pWin, + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > &xChecker, + BOOL bIsStart, + BOOL bIsAllRight, EditView* pView ); + +}; + + +struct WrongRange +{ + USHORT nStart; + USHORT nEnd; + + WrongRange( USHORT nS, USHORT nE ) { nStart = nS; nEnd = nE; } +}; + +SV_DECL_VARARR( WrongRanges, WrongRange, 4, 4 ) +#define NOT_INVALID 0xFFFF + +class WrongList : private WrongRanges +{ +private: + USHORT nInvalidStart; + USHORT nInvalidEnd; + + BOOL DbgIsBuggy() const; + +public: + WrongList(); + ~WrongList(); + + BOOL IsInvalid() const { return nInvalidStart != NOT_INVALID; } + void SetValid() { nInvalidStart = NOT_INVALID; nInvalidEnd = 0; } + void MarkInvalid( USHORT nS, USHORT nE ) + { + if ( ( nInvalidStart == NOT_INVALID ) || ( nInvalidStart > nS ) ) + nInvalidStart = nS; + if ( nInvalidEnd < nE ) + nInvalidEnd = nE; + } + + USHORT Count() const { return WrongRanges::Count(); } + + // Wenn man weiss was man tut: + WrongRange& GetObject( USHORT n ) const { return WrongRanges::GetObject( n ); } + void InsertWrong( const WrongRange& rWrong, USHORT nPos ); + + USHORT GetInvalidStart() const { return nInvalidStart; } + USHORT& GetInvalidStart() { return nInvalidStart; } + + USHORT GetInvalidEnd() const { return nInvalidEnd; } + USHORT& GetInvalidEnd() { return nInvalidEnd; } + + void TextInserted( USHORT nPos, USHORT nChars, BOOL bPosIsSep ); + void TextDeleted( USHORT nPos, USHORT nChars ); + + void ResetRanges() { Remove( 0, Count() ); } + BOOL HasWrongs() const { return Count() != 0; } + void InsertWrong( USHORT nStart, USHORT nEnd, BOOL bClearRange ); + BOOL NextWrong( USHORT& rnStart, USHORT& rnEnd ) const; + BOOL HasWrong( USHORT nStart, USHORT nEnd ) const; + BOOL HasAnyWrong( USHORT nStart, USHORT nEnd ) const; + void ClearWrongs( USHORT nStart, USHORT nEnd, const ContentNode* pNode ); + void MarkWrongsInvalid(); + + WrongList* Clone() const; + + // #i102062# + bool operator==(const WrongList& rCompare) const; +}; + +inline void WrongList::InsertWrong( const WrongRange& rWrong, USHORT nPos ) +{ + WrongRanges::Insert( rWrong, nPos ); +#ifdef DBG_UTIL + DBG_ASSERT( !DbgIsBuggy(), "Insert: WrongList kaputt!" ); +#endif +} + + + +class EdtAutoCorrDoc : public SvxAutoCorrDoc +{ + ImpEditEngine* pImpEE; + ContentNode* pCurNode; + USHORT nCursor; + + BOOL bAllowUndoAction; + BOOL bUndoAction; + +protected: + void ImplStartUndoAction(); + +public: + EdtAutoCorrDoc( ImpEditEngine* pImpEE, ContentNode* pCurNode, USHORT nCrsr, xub_Unicode cIns ); + ~EdtAutoCorrDoc(); + + virtual BOOL Delete( USHORT nStt, USHORT nEnd ); + virtual BOOL Insert( USHORT nPos, const String& rTxt ); + virtual BOOL Replace( USHORT nPos, const String& rTxt ); + + virtual BOOL SetAttr( USHORT nStt, USHORT nEnd, USHORT nSlotId, SfxPoolItem& ); + virtual BOOL SetINetAttr( USHORT nStt, USHORT nEnd, const String& rURL ); + + virtual BOOL HasSymbolChars( USHORT nStt, USHORT nEnd ); + + virtual const String* GetPrevPara( BOOL bAtNormalPos ); + + virtual BOOL ChgAutoCorrWord( USHORT& rSttPos, USHORT nEndPos, + SvxAutoCorrect& rACorrect, const String** ppPara ); + + virtual LanguageType GetLanguage( USHORT nPos, BOOL bPrevPara = FALSE ) const; + + USHORT GetCursor() const { return nCursor; } + +}; + +#endif // EDTSPELL + diff --git a/editeng/source/editeng/eehtml.cxx b/editeng/source/editeng/eehtml.cxx new file mode 100644 index 000000000000..ddb82a06661d --- /dev/null +++ b/editeng/source/editeng/eehtml.cxx @@ -0,0 +1,850 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <eehtml.hxx> +#include <impedit.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/flditem.hxx> +#include <tools/urlobj.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> + + +#define ACTION_INSERTTEXT 1 +#define ACTION_INSERTPARABRK 2 + +#define STYLE_PRE 101 + +EditHTMLParser::EditHTMLParser( SvStream& rIn, const String& rBaseURL, SvKeyValueIterator* pHTTPHeaderAttrs ) + : HTMLParser( rIn, true ) + , aBaseURL( rBaseURL ) +{ + pImpEditEngine = 0; + pCurAnchor = 0; + bInPara = FALSE; + bWasInPara = FALSE; + nInTable = 0; + nInCell = 0; + nDefListLevel = 0; + nBulletLevel = 0; + nNumberingLevel = 0; + bFieldsInserted = FALSE; + + if ( pHTTPHeaderAttrs ) + SetEncodingByHTTPHeader( pHTTPHeaderAttrs ); +} + +EditHTMLParser::~EditHTMLParser() +{ + delete pCurAnchor; +} + +SvParserState EditHTMLParser::CallParser( ImpEditEngine* pImpEE, const EditPaM& rPaM ) +{ + DBG_ASSERT( pImpEE, "CallParser: ImpEditEngine ?!" ); + pImpEditEngine = pImpEE; + SvParserState _eState = SVPAR_NOTSTARTED; + if ( pImpEditEngine ) + { + // Umbrechmimik vom RTF-Import einbauen? + aCurSel = EditSelection( rPaM, rPaM ); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_START, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ImpSetStyleSheet( 0 ); + _eState = HTMLParser::CallParser(); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_END, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + if ( bFieldsInserted ) + pImpEditEngine->UpdateFields(); + } + return _eState; +} + +void EditHTMLParser::NextToken( int nToken ) +{ + #ifdef DBG_UTIL + HTML_TOKEN_IDS xID = (HTML_TOKEN_IDS)nToken; + (void)xID; + #endif + + switch( nToken ) + { + case HTML_META: + { + const HTMLOptions *_pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + BOOL bEquiv = FALSE; + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption *pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_HTTPEQUIV: + { + bEquiv = TRUE; + } + break; + case HTML_O_CONTENT: + { + if ( bEquiv ) + { + rtl_TextEncoding eEnc = GetEncodingByMIME( pOption->GetString() ); + if ( eEnc != RTL_TEXTENCODING_DONTKNOW ) + SetSrcEncoding( eEnc ); + } + } + break; + } + } + + } + break; + case HTML_PLAINTEXT_ON: + case HTML_PLAINTEXT2_ON: + bInPara = TRUE; + break; + case HTML_PLAINTEXT_OFF: + case HTML_PLAINTEXT2_OFF: + bInPara = FALSE; + break; + + case HTML_LINEBREAK: + case HTML_NEWPARA: + { + if ( ( bInPara || nInTable ) && + ( ( nToken == HTML_LINEBREAK ) || HasTextInCurrentPara() ) ) + { + ImpInsertParaBreak(); + } + } + break; + case HTML_HORZRULE: + { + if ( HasTextInCurrentPara() ) + ImpInsertParaBreak(); + ImpInsertParaBreak(); + } + case HTML_NONBREAKSPACE: + { + if ( bInPara ) + { + ImpInsertText( String( RTL_CONSTASCII_USTRINGPARAM( " " ) ) ); + } + } + break; + case HTML_TEXTTOKEN: + { + if ( !bInPara ) + StartPara( FALSE ); + +// if ( bInPara || pCurAnchor ) + { + String aText = aToken; + if ( aText.Len() && ( aText.GetChar( 0 ) == ' ' ) + && ThrowAwayBlank() && !IsReadPRE() ) + aText.Erase( 0, 1 ); + + if ( pCurAnchor ) + { + pCurAnchor->aText += aText; + } + else + { + // Nur bis HTML mit 319 geschrieben ?! + if ( IsReadPRE() ) + { + USHORT nTabPos = aText.Search( '\t', 0 ); + while ( nTabPos != STRING_NOTFOUND ) + { + aText.Erase( nTabPos, 1 ); + aText.Insert( String( RTL_CONSTASCII_USTRINGPARAM( " " ) ), nTabPos ); + nTabPos = aText.Search( '\t', nTabPos+8 ); + } + } + ImpInsertText( aText ); + } + } + } + break; + + case HTML_CENTER_ON: + case HTML_CENTER_OFF: // if ( bInPara ) + { + USHORT nNode = pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + aItems.ClearItem( EE_PARA_JUST ); + if ( nToken == HTML_CENTER_ON ) + aItems.Put( SvxAdjustItem( SVX_ADJUST_CENTER, EE_PARA_JUST ) ); + pImpEditEngine->SetParaAttribs( nNode, aItems ); + } + break; + + case HTML_ANCHOR_ON: AnchorStart(); + break; + case HTML_ANCHOR_OFF: AnchorEnd(); + break; + + case HTML_PARABREAK_ON: + if( bInPara && HasTextInCurrentPara() ) + EndPara( TRUE ); + StartPara( TRUE ); + break; + + case HTML_PARABREAK_OFF: + if( bInPara ) + EndPara( TRUE ); + break; + + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + { + HeadingStart( nToken ); + } + break; + + case HTML_HEAD1_OFF: + case HTML_HEAD2_OFF: + case HTML_HEAD3_OFF: + case HTML_HEAD4_OFF: + case HTML_HEAD5_OFF: + case HTML_HEAD6_OFF: + { + HeadingEnd( nToken ); + } + break; + + case HTML_PREFORMTXT_ON: + case HTML_XMP_ON: + case HTML_LISTING_ON: + { + StartPara( TRUE ); + ImpSetStyleSheet( STYLE_PRE ); + } + break; + + case HTML_DEFLIST_ON: + { + nDefListLevel++; + } + break; + + case HTML_DEFLIST_OFF: + { + if( nDefListLevel ) + nDefListLevel--; + } + break; + + case HTML_TABLE_ON: nInTable++; + break; + case HTML_TABLE_OFF: DBG_ASSERT( nInTable, "Nicht in Table, aber TABLE_OFF?" ); + nInTable--; + break; + + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + nInCell++; + // fallthru + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE_OFF: + case HTML_BLOCKQUOTE30_ON: + case HTML_BLOCKQUOTE30_OFF: + case HTML_LISTHEADER_ON: + case HTML_LI_ON: + case HTML_DD_ON: + case HTML_DT_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + { + BOOL bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + StartPara( FALSE ); + } + break; + + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + { + if ( nInCell ) + nInCell--; + } + // fallthru + case HTML_LISTHEADER_OFF: + case HTML_LI_OFF: + case HTML_DD_OFF: + case HTML_DT_OFF: + case HTML_ORDERLIST_OFF: + case HTML_UNORDERLIST_OFF: EndPara( FALSE ); + break; + + case HTML_TABLEROW_ON: + case HTML_TABLEROW_OFF: // Nur nach einem CELL ein RETURN, fuer Calc + + case HTML_COL_ON: + case HTML_COLGROUP_ON: + case HTML_COLGROUP_OFF: break; + + case HTML_FONT_ON: // ... + break; + case HTML_FONT_OFF: // ... + break; + + + // #58335# kein SkipGroup on/off auf inline markup etc. + + // globals + case HTML_HTML_ON: + case HTML_HTML_OFF: + case HTML_BODY_ON: + case HTML_BODY_OFF: + case HTML_HEAD_ON: + case HTML_HEAD_OFF: + case HTML_FORM_ON: + case HTML_FORM_OFF: + case HTML_THEAD_ON: + case HTML_THEAD_OFF: + case HTML_TBODY_ON: + case HTML_TBODY_OFF: + case HTML_TITLE_ON: + case HTML_TITLE_OFF: + // inline elements, structural markup + // HTML 3.0 + case HTML_BANNER_ON: + case HTML_BANNER_OFF: + case HTML_DIVISION_ON: + case HTML_DIVISION_OFF: +// case HTML_LISTHEADER_ON: //! special handling +// case HTML_LISTHEADER_OFF: + case HTML_NOTE_ON: + case HTML_NOTE_OFF: + // inline elements, logical markup + // HTML 2.0 + case HTML_ADDRESS_ON: + case HTML_ADDRESS_OFF: +// case HTML_BLOCKQUOTE_ON: //! extra Behandlung +// case HTML_BLOCKQUOTE_OFF: + case HTML_CITIATION_ON: + case HTML_CITIATION_OFF: + case HTML_CODE_ON: + case HTML_CODE_OFF: + case HTML_DEFINSTANCE_ON: + case HTML_DEFINSTANCE_OFF: + case HTML_EMPHASIS_ON: + case HTML_EMPHASIS_OFF: + case HTML_KEYBOARD_ON: + case HTML_KEYBOARD_OFF: + case HTML_SAMPLE_ON: + case HTML_SAMPLE_OFF: + case HTML_STRIKE_ON: + case HTML_STRIKE_OFF: + case HTML_STRONG_ON: + case HTML_STRONG_OFF: + case HTML_VARIABLE_ON: + case HTML_VARIABLE_OFF: + // HTML 3.0 + case HTML_ABBREVIATION_ON: + case HTML_ABBREVIATION_OFF: + case HTML_ACRONYM_ON: + case HTML_ACRONYM_OFF: + case HTML_AUTHOR_ON: + case HTML_AUTHOR_OFF: +// case HTML_BLOCKQUOTE30_ON: //! extra Behandlung +// case HTML_BLOCKQUOTE30_OFF: + case HTML_DELETEDTEXT_ON: + case HTML_DELETEDTEXT_OFF: + case HTML_INSERTEDTEXT_ON: + case HTML_INSERTEDTEXT_OFF: + case HTML_LANGUAGE_ON: + case HTML_LANGUAGE_OFF: + case HTML_PERSON_ON: + case HTML_PERSON_OFF: + case HTML_SHORTQUOTE_ON: + case HTML_SHORTQUOTE_OFF: + case HTML_SUBSCRIPT_ON: + case HTML_SUBSCRIPT_OFF: + case HTML_SUPERSCRIPT_ON: + case HTML_SUPERSCRIPT_OFF: + // inline elements, visual markup + // HTML 2.0 + case HTML_BOLD_ON: + case HTML_BOLD_OFF: + case HTML_ITALIC_ON: + case HTML_ITALIC_OFF: + case HTML_TELETYPE_ON: + case HTML_TELETYPE_OFF: + case HTML_UNDERLINE_ON: + case HTML_UNDERLINE_OFF: + // HTML 3.0 + case HTML_BIGPRINT_ON: + case HTML_BIGPRINT_OFF: + case HTML_STRIKETHROUGH_ON: + case HTML_STRIKETHROUGH_OFF: + case HTML_SMALLPRINT_ON: + case HTML_SMALLPRINT_OFF: + // figures + case HTML_FIGURE_ON: + case HTML_FIGURE_OFF: + case HTML_CAPTION_ON: + case HTML_CAPTION_OFF: + case HTML_CREDIT_ON: + case HTML_CREDIT_OFF: + // misc + case HTML_DIRLIST_ON: + case HTML_DIRLIST_OFF: + case HTML_FOOTNOTE_ON: //! landen so im Text + case HTML_FOOTNOTE_OFF: + case HTML_MENULIST_ON: + case HTML_MENULIST_OFF: +// case HTML_PLAINTEXT_ON: //! extra Behandlung +// case HTML_PLAINTEXT_OFF: +// case HTML_PREFORMTXT_ON: //! extra Behandlung +// case HTML_PREFORMTXT_OFF: + case HTML_SPAN_ON: + case HTML_SPAN_OFF: + // obsolete +// case HTML_XMP_ON: //! extra Behandlung +// case HTML_XMP_OFF: +// case HTML_LISTING_ON: //! extra Behandlung +// case HTML_LISTING_OFF: + // Netscape + case HTML_BLINK_ON: + case HTML_BLINK_OFF: + case HTML_NOBR_ON: + case HTML_NOBR_OFF: + case HTML_NOEMBED_ON: + case HTML_NOEMBED_OFF: + case HTML_NOFRAMES_ON: + case HTML_NOFRAMES_OFF: + // Internet Explorer + case HTML_MARQUEE_ON: + case HTML_MARQUEE_OFF: +// case HTML_PLAINTEXT2_ON: //! extra Behandlung +// case HTML_PLAINTEXT2_OFF: + break; + + default: + { + if ( nToken & HTML_TOKEN_ONOFF ) + { + if ( ( nToken == HTML_UNKNOWNCONTROL_ON ) || ( nToken == HTML_UNKNOWNCONTROL_OFF ) ) + { + ; + } + else if ( !(nToken & 1) ) + { + DBG_ASSERT( !( nToken & 1 ), "Kein Start-Token ?!" ); + SkipGroup( nToken + 1 ); + } + } + } + } // SWITCH + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_NEXTTOKEN, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = (short)nTokenValue; + if ( nToken == HTML_TEXTTOKEN ) + aImportInfo.aText = aToken; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + +} + +void EditHTMLParser::ImpInsertParaBreak() +{ + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTPARA, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + nLastAction = ACTION_INSERTPARABRK; +} + +void EditHTMLParser::ImpSetAttribs( const SfxItemSet& rItems, EditSelection* pSel ) +{ + // pSel, wenn Zeichenattribute, sonst Absatzattribute fuer den + // aktuellen Absatz. + DBG_ASSERT( pSel || ( aCurSel.Min().GetNode() == aCurSel.Max().GetNode() ), "ImpInsertAttribs: Selektion?" ); + + EditPaM aStartPaM( pSel ? pSel->Min() : aCurSel.Min() ); + EditPaM aEndPaM( pSel ? pSel->Max() : aCurSel.Max() ); + + if ( !pSel ) + { + aStartPaM.SetIndex( 0 ); + aEndPaM.SetIndex( aEndPaM.GetNode()->Len() ); + } + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + EditSelection aSel( aStartPaM, aEndPaM ); + ImportInfo aImportInfo( HTMLIMP_SETATTR, this, pImpEditEngine->CreateESel( aSel ) ); + aImportInfo.pAttrs = (void*)&rItems; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ContentNode* pSN = aStartPaM.GetNode(); + USHORT nStartNode = pImpEditEngine->GetEditDoc().GetPos( pSN ); + + // Wenn ein Attribut von 0 bis aktuelle Absatzlaenge geht, + // soll es ein Absatz-Attribut sein! + + // Achtung: Selektion kann ueber mehrere Absaetze gehen. + // Alle vollstaendigen Absaetze sind Absatzattribute... + + // HTML eigentlich nicht: +#ifdef DBG_UTIL + ContentNode* pEN = aEndPaM.GetNode(); + USHORT nEndNode = pImpEditEngine->GetEditDoc().GetPos( pEN ); + DBG_ASSERT( nStartNode == nEndNode, "ImpSetAttribs: Mehrere Absaetze?" ); +#endif + +/* + for ( USHORT z = nStartNode+1; z < nEndNode; z++ ) + { + DBG_ASSERT( pImpEditEngine->GetEditDoc().SaveGetObject( z ), "Node existiert noch nicht(RTF)" ); + pImpEditEngine->SetParaAttribs( z, rSet.GetAttrSet() ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + if ( aStartPaM.GetIndex() == 0 ) + pImpEditEngine->SetParaAttribs( nStartNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, EditPaM( aStartPaM.GetNode(), aStartPaM.GetNode()->Len() ) ), rSet.GetAttrSet() ); + + // Den Anfang des EndNodes.... + if ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) + pImpEditEngine->SetParaAttribs( nEndNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( EditPaM( aEndPaM.GetNode(), 0 ), aEndPaM ), rSet.GetAttrSet() ); + } + else +*/ + { + if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) + { + // Muesse gemergt werden: + SfxItemSet aItems( pImpEditEngine->GetParaAttribs( nStartNode ) ); + aItems.Put( rItems ); + pImpEditEngine->SetParaAttribs( nStartNode, aItems ); + } + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, aEndPaM ), rItems ); + } +} + +void EditHTMLParser::ImpSetStyleSheet( USHORT nHLevel ) +{ + /* + nHLevel: 0: Ausschalten + 1-6: Heading + STYLE_PRE: Preformatted + */ + +// if ( pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) +// { +// SvxRTFStyleType* pS = GetStyleTbl().Get( rSet.StyleNo() ); +// DBG_ASSERT( pS, "Vorlage in RTF nicht definiert!" ); +// if ( pS ) +// pImpEditEngine->SetStyleSheet( EditSelection( aStartPaM, aEndPaM ), pS->sName, SFX_STYLE_FAMILY_ALL ); +// } +// else + { + // Harte Attribute erzeugen... + // Reicht fuer Calc, bei StyleSheets muesste noch geklaert werden, + // dass diese auch in der App liegen sollten, damit sie beim + // fuettern in eine andere Engine auch noch da sind... + + USHORT nNode = pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); +// SfxItemSet aItems( pImpEditEngine->GetEmptyItemSet() ); + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + + aItems.ClearItem( EE_PARA_ULSPACE ); + aItems.ClearItem( EE_CHAR_FONTHEIGHT ); + aItems.ClearItem( EE_CHAR_FONTINFO ); + aItems.ClearItem( EE_CHAR_WEIGHT ); + + // Fett in den ersten 3 Headings + if ( ( nHLevel >= 1 ) && ( nHLevel <= 3 ) ) + { + SvxWeightItem aWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ); + aItems.Put( aWeightItem ); + } + + // Fonthoehe und Abstaende, wenn LogicToLogic moeglich: + MapUnit eUnit = pImpEditEngine->GetRefMapMode().GetMapUnit(); + if ( ( eUnit != MAP_PIXEL ) && ( eUnit != MAP_SYSFONT ) && + ( eUnit != MAP_APPFONT ) && ( eUnit != MAP_RELATIVE ) ) + { + long nPoints = 10; + if ( nHLevel == 1 ) + nPoints = 22; + else if ( nHLevel == 2 ) + nPoints = 16; + else if ( nHLevel == 3 ) + nPoints = 12; + else if ( nHLevel == 4 ) + nPoints = 11; + + nPoints = OutputDevice::LogicToLogic( nPoints, MAP_POINT, eUnit ); + SvxFontHeightItem aHeightItem( nPoints, 100, EE_CHAR_FONTHEIGHT ); + aItems.Put( aHeightItem ); + + // Absatzabstaende, wenn Heading: + if ( !nHLevel || ((nHLevel >= 1) && (nHLevel <= 6)) ) + { + SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE ); + aULSpaceItem.SetUpper( (USHORT)OutputDevice::LogicToLogic( 42, MAP_10TH_MM, eUnit ) ); + aULSpaceItem.SetLower( (USHORT)OutputDevice::LogicToLogic( 35, MAP_10TH_MM, eUnit ) ); + aItems.Put( aULSpaceItem ); + } + } + + // Bei Pre einen proportionalen Font waehlen + if ( nHLevel == STYLE_PRE ) + { + Font aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, LANGUAGE_SYSTEM, 0 ); + SvxFontItem aFontItem( aFont.GetFamily(), aFont.GetName(), XubString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO ); + aItems.Put( aFontItem ); + } + + pImpEditEngine->SetParaAttribs( nNode, aItems ); + } +} + +void EditHTMLParser::ImpInsertText( const String& rText ) +{ + String aText( rText ); + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTTEXT, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.aText = aText; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + aCurSel = pImpEditEngine->ImpInsertText( aCurSel, aText ); + nLastAction = ACTION_INSERTTEXT; +} + +void EditHTMLParser::SkipGroup( int nEndToken ) +{ + // #69109# groups in cells are closed upon leaving the cell, because those + // ******* web authors don't know their job + // for example: <td><form></td> lacks a closing </form> + BYTE nCellLevel = nInCell; + int nToken; + while( nCellLevel <= nInCell && ( (nToken = GetNextToken() ) != nEndToken ) && nToken ) + { + switch ( nToken ) + { + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + nInCell++; + break; + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + if ( nInCell ) + nInCell--; + break; + } + } +} + +void EditHTMLParser::StartPara( BOOL bReal ) +{ + if ( bReal ) + { + const HTMLOptions *_pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + SvxAdjust eAdjust = SVX_ADJUST_LEFT; + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption *pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_ALIGN: + { + if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_RIGHT; + else if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_middle ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_CENTER; + else if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_center ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_CENTER; + else + eAdjust = SVX_ADJUST_LEFT; + } + break; + } + } + SfxItemSet aItemSet( pImpEditEngine->GetEmptyItemSet() ); + aItemSet.Put( SvxAdjustItem( eAdjust, EE_PARA_JUST ) ); + ImpSetAttribs( aItemSet ); + } + bInPara = TRUE; +} + +void EditHTMLParser::EndPara( BOOL ) +{ + if ( bInPara ) + { + BOOL bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + // Nur, wenn ohne Absatzabstaende gearbeitet wird... +// if ( !nInTable && bReal && (nNumberingLevel<=1) && (nBulletLevel<=1) ) +// ImpInsertParaBreak(); + } + bInPara = FALSE; +} + +BOOL EditHTMLParser::ThrowAwayBlank() +{ + // Ein Blank muss weggeschmissen werden, wenn der neue Text mit einem + // Blank beginnt und der aktuelle Absatz leer ist oder mit einem + // Blank endet... + ContentNode* pNode = aCurSel.Max().GetNode(); + if ( pNode->Len() && ( pNode->GetChar( pNode->Len()-1 ) != ' ' ) ) + return FALSE; + return TRUE; +} + +BOOL EditHTMLParser::HasTextInCurrentPara() +{ + return aCurSel.Max().GetNode()->Len() ? TRUE : FALSE; +} + +void EditHTMLParser::AnchorStart() +{ + // Anker im Anker ignoriern + if ( !pCurAnchor ) + { + const HTMLOptions* _pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + + String aRef; + + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption* pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_HREF: + aRef = pOption->GetString(); + break; + } + } + + if ( aRef.Len() ) + { + String aURL = aRef; + if ( aURL.Len() && ( aURL.GetChar( 0 ) != '#' ) ) + { + INetURLObject aTargetURL; + INetURLObject aRootURL( aBaseURL ); + aRootURL.GetNewAbsURL( aRef, &aTargetURL ); + aURL = aTargetURL.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + pCurAnchor = new AnchorInfo; + pCurAnchor->aHRef = aURL; + } + } +} + +void EditHTMLParser::AnchorEnd() +{ + if ( pCurAnchor ) + { + // Als URL-Feld einfuegen... + SvxFieldItem aFld( SvxURLField( pCurAnchor->aHRef, pCurAnchor->aText, SVXURLFORMAT_REPR ), EE_FEATURE_FIELD ); + aCurSel = pImpEditEngine->InsertField( aCurSel, aFld ); + bFieldsInserted = TRUE; + delete pCurAnchor; + pCurAnchor = 0; + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTFIELD, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + } +} + +void EditHTMLParser::HeadingStart( int nToken ) +{ + bWasInPara = bInPara; + StartPara( FALSE ); + + if ( bWasInPara && HasTextInCurrentPara() ) + ImpInsertParaBreak(); + + USHORT nId = sal::static_int_cast< USHORT >( + 1 + ( ( nToken - HTML_HEAD1_ON ) / 2 ) ); + DBG_ASSERT( (nId >= 1) && (nId <= 9), "HeadingStart: ID kann nicht stimmen!" ); + ImpSetStyleSheet( nId ); +} + +void EditHTMLParser::HeadingEnd( int ) +{ + EndPara( FALSE ); + ImpSetStyleSheet( 0 ); + + if ( bWasInPara ) + { + bInPara = TRUE; + bWasInPara = FALSE; + } +} diff --git a/editeng/source/editeng/eehtml.hxx b/editeng/source/editeng/eehtml.hxx new file mode 100644 index 000000000000..a9b20bcd652f --- /dev/null +++ b/editeng/source/editeng/eehtml.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EEHTML_HXX +#define _EEHTML_HXX + +#include <svl/svarray.hxx> + +#include <editdoc.hxx> +#include <svtools/parhtml.hxx> + +class ImpEditEngine; + +#define MAX_NUMBERLEVEL 10 + +struct AnchorInfo +{ + String aHRef; + String aText; +}; + +class EditHTMLParser : public HTMLParser +{ + using HTMLParser::CallParser; +private: + EditSelection aCurSel; + String aBaseURL; + ImpEditEngine* pImpEditEngine; + AnchorInfo* pCurAnchor; + + BOOL bInPara; + BOOL bWasInPara; // bInPara vor HeadingStart merken, weil sonst hinterher weg + BOOL bFieldsInserted; + BYTE nInTable; + BYTE nInCell; + + BYTE nDefListLevel; + BYTE nBulletLevel; + BYTE nNumberingLevel; + + BYTE nLastAction; + + void StartPara( BOOL bReal ); + void EndPara( BOOL bReal ); + void AnchorStart(); + void AnchorEnd(); + void HeadingStart( int nToken ); + void HeadingEnd( int nToken ); + void SkipGroup( int nEndToken ); + BOOL ThrowAwayBlank(); + BOOL HasTextInCurrentPara(); + void ProcessUnknownControl( BOOL bOn ); + + void ImpInsertParaBreak(); + void ImpInsertText( const String& rText ); + void ImpSetAttribs( const SfxItemSet& rItems, EditSelection* pSel = 0 ); + void ImpSetStyleSheet( USHORT nHeadingLevel ); + +protected: + virtual void NextToken( int nToken ); + +public: + EditHTMLParser( SvStream& rIn, const String& rBaseURL, SvKeyValueIterator* pHTTPHeaderAttrs ); + ~EditHTMLParser(); + + virtual SvParserState CallParser( ImpEditEngine* pImpEE, const EditPaM& rPaM ); + + const EditSelection& GetCurSelection() const { return aCurSel; } +}; + +SV_DECL_REF( EditHTMLParser ) +SV_IMPL_REF( EditHTMLParser ); + +#endif // _EEHTML_HXX diff --git a/editeng/source/editeng/eeng_pch.cxx b/editeng/source/editeng/eeng_pch.cxx new file mode 100644 index 000000000000..249f4cb0ab12 --- /dev/null +++ b/editeng/source/editeng/eeng_pch.cxx @@ -0,0 +1,30 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <eeng_pch.hxx> diff --git a/editeng/source/editeng/eeng_pch.hxx b/editeng/source/editeng/eeng_pch.hxx new file mode 100644 index 000000000000..14c8b9f5dc4b --- /dev/null +++ b/editeng/source/editeng/eeng_pch.hxx @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#define _STD_VAR_ARRAYS + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + + diff --git a/editeng/source/editeng/eeobj.cxx b/editeng/source/editeng/eeobj.cxx new file mode 100644 index 000000000000..a275f8b5d372 --- /dev/null +++ b/editeng/source/editeng/eeobj.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <eeng_pch.hxx> + +#include <eeobj.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <editeng/editeng.hxx> +#include <svl/itempool.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +using namespace ::com::sun::star; + + +EditDataObject::EditDataObject() +{ +} + +EditDataObject::~EditDataObject() +{ +} + +// uno::XInterface +uno::Any EditDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException) +{ + uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) ); + return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); +} + +// datatransfer::XTransferable +uno::Any EditDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) +{ + uno::Any aAny; + + ULONG nT = SotExchange::GetFormat( rFlavor ); + if ( nT == SOT_FORMAT_STRING ) + { + aAny <<= (::rtl::OUString)GetString(); + } + else if ( ( nT == SOT_FORMATSTR_ID_EDITENGINE ) || ( nT == SOT_FORMAT_RTF ) ) + { + // MT 01/2002: No RTF on demand any more: + // 1) Was not working, because I had to flush() the clipboard immediately anyway + // 2) Don't have the old pool defaults and the StyleSheetPool here. + + SvMemoryStream* pStream = ( nT == SOT_FORMATSTR_ID_EDITENGINE ) ? &GetStream() : &GetRTFStream(); + pStream->Seek( STREAM_SEEK_TO_END ); + ULONG nLen = pStream->Tell(); + pStream->Seek(0); + + uno::Sequence< sal_Int8 > aSeq( nLen ); + memcpy( aSeq.getArray(), pStream->GetData(), nLen ); + aAny <<= aSeq; + } + else + { + datatransfer::UnsupportedFlavorException aException; + throw( aException ); + } + + return aAny; +} + +uno::Sequence< datatransfer::DataFlavor > EditDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException) +{ + uno::Sequence< datatransfer::DataFlavor > aDataFlavors(3); + SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_EDITENGINE, aDataFlavors.getArray()[0] ); + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[1] ); + SotExchange::GetFormatDataFlavor( SOT_FORMAT_RTF, aDataFlavors.getArray()[2] ); + + return aDataFlavors; +} + +sal_Bool EditDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException) +{ + sal_Bool bSupported = sal_False; + + ULONG nT = SotExchange::GetFormat( rFlavor ); + if ( ( nT == SOT_FORMAT_STRING ) || ( nT == SOT_FORMAT_RTF ) /* || ( nT == SOT_FORMAT_XML ) */ || ( nT == SOT_FORMATSTR_ID_EDITENGINE ) ) + bSupported = sal_True; + + return bSupported; +} diff --git a/editeng/source/editeng/eeobj.hxx b/editeng/source/editeng/eeobj.hxx new file mode 100644 index 000000000000..6a4956b2481a --- /dev/null +++ b/editeng/source/editeng/eeobj.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DATAOBJ_HXX +#define _DATAOBJ_HXX + +#include <cppuhelper/weak.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> + +#include <tools/stream.hxx> + +class EditDataObject : public ::com::sun::star::datatransfer::XTransferable, + public ::cppu::OWeakObject + +{ +private: + SvMemoryStream maBinData; + SvMemoryStream maRTFData; + String maText; + + String maOfficeBookmark; + +// String maNetscapeBookmark; +// SvMemoryStream maRTFData; + +public: + EditDataObject(); + ~EditDataObject(); + + SvMemoryStream& GetStream() { return maBinData; } + SvMemoryStream& GetRTFStream() { return maRTFData; } + String& GetString() { return maText; } + String& GetURL() { return maOfficeBookmark; } + + + // ::com::sun::star::uno::XInterface + ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL acquire() throw() { OWeakObject::acquire(); } + void SAL_CALL release() throw() { OWeakObject::release(); } + + // ::com::sun::star::datatransfer::XTransferable + ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException); + sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException); +}; + +#endif // _DATAOBJ_HXX + diff --git a/editeng/source/editeng/eerdll.cxx b/editeng/source/editeng/eerdll.cxx new file mode 100644 index 000000000000..7d6df3f0fab4 --- /dev/null +++ b/editeng/source/editeng/eerdll.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> + +#include <svl/solar.hrc> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <svl/itempool.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <comphelper/processfactory.hxx> + +static EditDLL* pDLL=0; + +using namespace ::com::sun::star; + +EditDLL* EditDLL::Get() +{ + if ( !pDLL ) + pDLL = new EditDLL; + return pDLL; +} + +GlobalEditData::GlobalEditData() +{ + ppDefItems = NULL; + pStdRefDevice = NULL; +} + +GlobalEditData::~GlobalEditData() +{ + // DefItems zerstoeren... + // Oder einfach stehen lassen, da sowieso App-Ende?! + if ( ppDefItems ) + SfxItemPool::ReleaseDefaults( ppDefItems, EDITITEMCOUNT, TRUE ); + delete pStdRefDevice; +} + +SfxPoolItem** GlobalEditData::GetDefItems() +{ + if ( !ppDefItems ) + { + ppDefItems = new SfxPoolItem*[EDITITEMCOUNT]; + + // Absatzattribute: + SvxNumRule aTmpNumRule( 0, 0, FALSE ); + + ppDefItems[0] = new SvxFrameDirectionItem( FRMDIR_HORI_LEFT_TOP, EE_PARA_WRITINGDIR ); + ppDefItems[1] = new SvXMLAttrContainerItem( EE_PARA_XMLATTRIBS ); + ppDefItems[2] = new SfxBoolItem( EE_PARA_HANGINGPUNCTUATION, FALSE ); + ppDefItems[3] = new SfxBoolItem( EE_PARA_FORBIDDENRULES, TRUE ); + ppDefItems[4] = new SvxScriptSpaceItem( TRUE, EE_PARA_ASIANCJKSPACING ); + ppDefItems[5] = new SvxNumBulletItem( aTmpNumRule, EE_PARA_NUMBULLET ); + ppDefItems[6] = new SfxBoolItem( EE_PARA_HYPHENATE, FALSE ); + ppDefItems[7] = new SfxBoolItem( EE_PARA_BULLETSTATE, TRUE ); + ppDefItems[8] = new SvxLRSpaceItem( EE_PARA_OUTLLRSPACE ); + ppDefItems[9] = new SfxInt16Item( EE_PARA_OUTLLEVEL, -1 ); + ppDefItems[10] = new SvxBulletItem( EE_PARA_BULLET ); + ppDefItems[11] = new SvxLRSpaceItem( EE_PARA_LRSPACE ); + ppDefItems[12] = new SvxULSpaceItem( EE_PARA_ULSPACE ); + ppDefItems[13] = new SvxLineSpacingItem( 0, EE_PARA_SBL ); + ppDefItems[14] = new SvxAdjustItem( SVX_ADJUST_LEFT, EE_PARA_JUST ); + ppDefItems[15] = new SvxTabStopItem( 0, 0, SVX_TAB_ADJUST_LEFT, EE_PARA_TABS ); + + // Zeichenattribute: + ppDefItems[16] = new SvxColorItem( Color( COL_AUTO ), EE_CHAR_COLOR ); + ppDefItems[17] = new SvxFontItem( EE_CHAR_FONTINFO ); + ppDefItems[18] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT ); + ppDefItems[19] = new SvxCharScaleWidthItem( 100, EE_CHAR_FONTWIDTH ); + ppDefItems[20] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ); + ppDefItems[21] = new SvxUnderlineItem( UNDERLINE_NONE, EE_CHAR_UNDERLINE ); + ppDefItems[22] = new SvxCrossedOutItem( STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ); + ppDefItems[23] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ); + ppDefItems[24] = new SvxContourItem( FALSE, EE_CHAR_OUTLINE ); + ppDefItems[25] = new SvxShadowedItem( FALSE, EE_CHAR_SHADOW ); + ppDefItems[26] = new SvxEscapementItem( 0, 100, EE_CHAR_ESCAPEMENT ); + ppDefItems[27] = new SvxAutoKernItem( FALSE, EE_CHAR_PAIRKERNING ); + ppDefItems[28] = new SvxKerningItem( 0, EE_CHAR_KERNING ); + ppDefItems[29] = new SvxWordLineModeItem( FALSE, EE_CHAR_WLM ); + ppDefItems[30] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE ); + ppDefItems[31] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE_CJK ); + ppDefItems[32] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE_CTL ); + ppDefItems[33] = new SvxFontItem( EE_CHAR_FONTINFO_CJK ); + ppDefItems[34] = new SvxFontItem( EE_CHAR_FONTINFO_CTL ); + ppDefItems[35] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT_CJK ); + ppDefItems[36] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT_CTL ); + ppDefItems[37] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ); + ppDefItems[38] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ); + ppDefItems[39] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ); + ppDefItems[40] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ); + ppDefItems[41] = new SvxEmphasisMarkItem( EMPHASISMARK_NONE, EE_CHAR_EMPHASISMARK ); + ppDefItems[42] = new SvxCharReliefItem( RELIEF_NONE, EE_CHAR_RELIEF ); + ppDefItems[43] = new SfxVoidItem( EE_CHAR_RUBI_DUMMY ); +#ifndef SVX_LIGHT + ppDefItems[44] = new SvXMLAttrContainerItem( EE_CHAR_XMLATTRIBS ); +#else + // no need to have alien attributes persistent + ppDefItems[44] = new SfxVoidItem( EE_CHAR_XMLATTRIBS ); +#endif // #ifndef SVX_LIGHT + ppDefItems[45] = new SvxOverlineItem( UNDERLINE_NONE, EE_CHAR_OVERLINE ); + + // Features + ppDefItems[46] = new SfxVoidItem( EE_FEATURE_TAB ); + ppDefItems[47] = new SfxVoidItem( EE_FEATURE_LINEBR ); + ppDefItems[48] = new SvxCharSetColorItem( Color( COL_RED ), RTL_TEXTENCODING_DONTKNOW, EE_FEATURE_NOTCONV ); + ppDefItems[49] = new SvxFieldItem( SvxFieldData(), EE_FEATURE_FIELD ); + + DBG_ASSERT( EDITITEMCOUNT == 50, "ITEMCOUNT geaendert, DefItems nicht angepasst!" ); + + // Init DefFonts: + GetDefaultFonts( *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO - EE_ITEMS_START], + *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO_CJK - EE_ITEMS_START], + *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO_CTL - EE_ITEMS_START] ); + } + + return ppDefItems; +} + +vos::ORef<SvxForbiddenCharactersTable> GlobalEditData::GetForbiddenCharsTable() +{ + if ( !xForbiddenCharsTable.isValid() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + xForbiddenCharsTable = new SvxForbiddenCharactersTable( xMSF ); + } + return xForbiddenCharsTable; +} + +uno::Reference< linguistic2::XLanguageGuessing > GlobalEditData::GetLanguageGuesser() +{ + if (!xLanguageGuesser.is()) + { + uno::Reference< lang::XMultiServiceFactory > xMgr ( comphelper::getProcessServiceFactory() ); + if (xMgr.is()) + { + xLanguageGuesser = uno::Reference< linguistic2::XLanguageGuessing >( + xMgr->createInstance( + rtl::OUString::createFromAscii( "com.sun.star.linguistic2.LanguageGuessing" ) ), + uno::UNO_QUERY ); + } + } + return xLanguageGuesser; +} + +OutputDevice* GlobalEditData::GetStdRefDevice() +{ + if ( !pStdRefDevice ) + { + pStdRefDevice = new VirtualDevice; + pStdRefDevice->SetMapMode( MAP_TWIP ); + } + return pStdRefDevice; +} + +EditResId::EditResId( USHORT nId ): + ResId( nId, *EE_DLL()->GetResMgr() ) +{ +} + +EditDLL::EditDLL() +{ + pGlobalData = new GlobalEditData; + ByteString aResMgrName( "editeng" ); + pResMgr = ResMgr::CreateResMgr( + aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() ); +} + +EditDLL::~EditDLL() +{ + delete pResMgr; + delete pGlobalData; +} diff --git a/editeng/source/editeng/eerdll2.hxx b/editeng/source/editeng/eerdll2.hxx new file mode 100644 index 000000000000..49bfa058038e --- /dev/null +++ b/editeng/source/editeng/eerdll2.hxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EERDLL2_HXX +#define _EERDLL2_HXX + +#include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <editeng/forbiddencharacterstable.hxx> +#include <vos/ref.hxx> + +class SfxPoolItem; + +class GlobalEditData +{ +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XLanguageGuessing > xLanguageGuesser; + SfxPoolItem** ppDefItems; + OutputDevice* pStdRefDevice; + + vos::ORef<SvxForbiddenCharactersTable> xForbiddenCharsTable; + +public: + GlobalEditData(); + ~GlobalEditData(); + + SfxPoolItem** GetDefItems(); + OutputDevice* GetStdRefDevice(); + + vos::ORef<SvxForbiddenCharactersTable> GetForbiddenCharsTable(); + void SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) { xForbiddenCharsTable = xForbiddenChars; } + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XLanguageGuessing > GetLanguageGuesser(); +}; + + +#endif //_EERDLL2_HXX + diff --git a/editeng/source/editeng/eertfpar.cxx b/editeng/source/editeng/eertfpar.cxx new file mode 100644 index 000000000000..9f919afb39d6 --- /dev/null +++ b/editeng/source/editeng/eertfpar.cxx @@ -0,0 +1,632 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <eertfpar.hxx> +#include <impedit.hxx> +#include <svl/intitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/flditem.hxx> + +#include <svtools/rtftoken.h> + +// alle Werte auf default; wird nach einlesen der Bitmap aufgerufen ! +void SvxRTFPictureType::ResetValues() +{ // setze alle Werte RTF-Defaults + eStyle = RTF_BITMAP; + nMode = HEX_MODE; + nType = nGoalWidth = nGoalHeight = 0; + nWidth = nHeight = nWidthBytes = 0; + uPicLen = 0; + nBitsPerPixel = nPlanes = 1; + nScalX = nScalY = 100; // Skalierung in Prozent + nCropT = nCropB = nCropL = nCropR = 0; +} + +ImportInfo::ImportInfo( ImportState eSt, SvParser* pPrsrs, const ESelection& rSel ) + : aSelection( rSel ) +{ + pParser = pPrsrs, + eState = eSt; + + nToken = 0; + nTokenValue = 0; + pAttrs = NULL; +} + +ImportInfo::~ImportInfo() +{ +} + +EditRTFParser::EditRTFParser( SvStream& rIn, EditSelection aSel, SfxItemPool& rAttrPool, ImpEditEngine* pImpEE ) + : SvxRTFParser( rAttrPool, rIn, 0 ), aRTFMapMode( MAP_TWIP ) +{ + + pImpEditEngine = pImpEE; + aCurSel = aSel; + eDestCharSet = RTL_TEXTENCODING_DONTKNOW; + nDefFont = 0; + nDefTab = 0; + nLastAction = 0; + nDefFontHeight = 0; + + SetInsPos( EditPosition( pImpEditEngine, &aCurSel ) ); + + // Umwandeln der Twips-Werte... + SetCalcValue( TRUE ); + SetChkStyleAttr( pImpEE->GetStatus().DoImportRTFStyleSheets() ); + SetNewDoc( FALSE ); // damit die Pool-Defaults nicht + // ueberschrieben werden... + aEditMapMode = MapMode( pImpEE->GetRefDevice()->GetMapMode().GetMapUnit() ); +} + +EditRTFParser::~EditRTFParser() +{ +} + +SvParserState __EXPORT EditRTFParser::CallParser() +{ + DBG_ASSERT( !aCurSel.HasRange(), "Selection bei CallParser!" ); + // Den Teil, in den importiert wird, vom Rest abtrennen. + // Diese Mimik sollte fuer alle Imports verwendet werden. + // aStart1PaM: Letzte Position vor dem importierten Inhalt + // aEnd1PaM: Erste Position nach dem importierten Inhalt + // aStart2PaM: Erste Position des importierten Inhaltes + // aEnd2PaM: Letzte Position des importierten Inhaltes + EditPaM aStart1PaM( aCurSel.Min().GetNode(), aCurSel.Min().GetIndex() ); + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + EditPaM aStart2PaM = aCurSel.Min(); + // Sinnvoll oder nicht?: + aStart2PaM.GetNode()->GetContentAttribs().GetItems().ClearItem(); + AddRTFDefaultValues( aStart2PaM, aStart2PaM ); + EditPaM aEnd1PaM( pImpEditEngine->ImpInsertParaBreak( aCurSel.Max() ) ); + // aCurCel zeigt jetzt auf den Zwischenraum + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_START, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + SvParserState _eState = SvxRTFParser::CallParser(); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_END, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + if ( nLastAction == ACTION_INSERTPARABRK ) + { + ContentNode* pCurNode = aCurSel.Max().GetNode(); + USHORT nPara = pImpEditEngine->GetEditDoc().GetPos( pCurNode ); + ContentNode* pPrevNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara-1 ); + DBG_ASSERT( pPrevNode, "Ungueltiges RTF-Dokument ?!" ); + EditSelection aSel; + aSel.Min() = EditPaM( pPrevNode, pPrevNode->Len() ); + aSel.Max() = EditPaM( pCurNode, 0 ); + aCurSel.Max() = pImpEditEngine->ImpDeleteSelection( aSel ); + } + EditPaM aEnd2PaM( aCurSel.Max() ); + //AddRTFDefaultValues( aStart2PaM, aEnd2PaM ); + BOOL bOnlyOnePara = ( aEnd2PaM.GetNode() == aStart2PaM.GetNode() ); + // Den Brocken wieder einfuegen... + // Problem: Absatzattribute duerfen ggf. nicht uebernommen werden + // => Zeichenattribute machen. + + BOOL bSpecialBackward = aStart1PaM.GetNode()->Len() ? FALSE : TRUE; + if ( bOnlyOnePara || aStart1PaM.GetNode()->Len() ) + pImpEditEngine->ParaAttribsToCharAttribs( aStart2PaM.GetNode() ); + aCurSel.Min() = pImpEditEngine->ImpConnectParagraphs( + aStart1PaM.GetNode(), aStart2PaM.GetNode(), bSpecialBackward ); + bSpecialBackward = aEnd1PaM.GetNode()->Len() ? TRUE : FALSE; + // wenn bOnlyOnePara, dann ist der Node beim Connect verschwunden. + if ( !bOnlyOnePara && aEnd1PaM.GetNode()->Len() ) + pImpEditEngine->ParaAttribsToCharAttribs( aEnd2PaM.GetNode() ); + aCurSel.Max() = pImpEditEngine->ImpConnectParagraphs( + ( bOnlyOnePara ? aStart1PaM.GetNode() : aEnd2PaM.GetNode() ), + aEnd1PaM.GetNode(), bSpecialBackward ); + + return _eState; +} + +void EditRTFParser::AddRTFDefaultValues( const EditPaM& rStart, const EditPaM& rEnd ) +{ + // Problem: DefFont und DefFontHeight + Size aSz( 12, 0 ); + MapMode aPntMode( MAP_POINT ); + MapMode _aEditMapMode( pImpEditEngine->GetRefDevice()->GetMapMode().GetMapUnit() ); + aSz = pImpEditEngine->GetRefDevice()->LogicToLogic( aSz, &aPntMode, &_aEditMapMode ); + SvxFontHeightItem aFontHeightItem( aSz.Width(), 100, EE_CHAR_FONTHEIGHT ); + Font aDefFont( GetDefFont() ); + SvxFontItem aFontItem( aDefFont.GetFamily(), aDefFont.GetName(), + aDefFont.GetStyleName(), aDefFont.GetPitch(), aDefFont.GetCharSet(), EE_CHAR_FONTINFO ); + + USHORT nStartPara = pImpEditEngine->GetEditDoc().GetPos( rStart.GetNode() ); + USHORT nEndPara = pImpEditEngine->GetEditDoc().GetPos( rEnd.GetNode() ); + for ( USHORT nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "AddRTFDefaultValues - Kein Absatz ?!" ); + if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTINFO ) ) + pNode->GetContentAttribs().GetItems().Put( aFontItem ); + if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTHEIGHT ) ) + pNode->GetContentAttribs().GetItems().Put( aFontHeightItem ); + } +} + +void __EXPORT EditRTFParser::NextToken( int nToken ) +{ + switch( nToken ) + { + case RTF_DEFF: + { + nDefFont = USHORT(nTokenValue); + } + break; + case RTF_DEFTAB: + { + nDefTab = USHORT(nTokenValue); + } + break; + case RTF_CELL: + { + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + } + break; + case RTF_LINE: + { + aCurSel = pImpEditEngine->InsertLineBreak( aCurSel ); + } + break; + case RTF_FIELD: + { + ReadField(); + } + break; + case RTF_PGDSCTBL: // #i29453# ignore \*\pgdsctbl destination + case RTF_LISTTEXT: + { + SkipGroup(); + } + break; + default: + { + SvxRTFParser::NextToken( nToken ); + if ( nToken == RTF_STYLESHEET ) + CreateStyleSheets(); + } + break; + } + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_NEXTTOKEN, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = short(nTokenValue); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } +} + +void __EXPORT EditRTFParser::UnknownAttrToken( int nToken, SfxItemSet* ) +{ + // fuer Tokens, die im ReadAttr nicht ausgewertet werden + // Eigentlich nur fuer Calc (RTFTokenHdl), damit RTF_INTBL + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_UNKNOWNATTR, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = short(nTokenValue); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } +} + +void __EXPORT EditRTFParser::InsertText() +{ + String aText( aToken ); + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_INSERTTEXT, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.aText = aText; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertText( aCurSel, aText ); + nLastAction = ACTION_INSERTTEXT; +} + +void __EXPORT EditRTFParser::InsertPara() +{ + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_INSERTPARA, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + nLastAction = ACTION_INSERTPARABRK; +} + +void __EXPORT EditRTFParser::MovePos( int bForward ) +{ + if( bForward ) + aCurSel = pImpEditEngine->CursorRight( aCurSel.Max(), ::com::sun::star::i18n::CharacterIteratorMode::SKIPCHARACTER ); + else + aCurSel = pImpEditEngine->CursorLeft( aCurSel.Max(), ::com::sun::star::i18n::CharacterIteratorMode::SKIPCHARACTER ); +} + +void __EXPORT EditRTFParser::SetEndPrevPara( SvxNodeIdx*& rpNodePos, + USHORT& rCntPos ) +{ + // Gewollt ist: von der aktuellen Einfuegeposition den vorherigen + // Absatz bestimmen und von dem das Ende setzen. + // Dadurch wird "\pard" immer auf den richtigen Absatz + // angewendet. + + ContentNode* pN = aCurSel.Max().GetNode(); + USHORT nCurPara = pImpEditEngine->GetEditDoc().GetPos( pN ); + DBG_ASSERT( nCurPara != 0, "Absatz gleich 0: SetEnfPrevPara" ); + if ( nCurPara ) + nCurPara--; + ContentNode* pPrevNode = pImpEditEngine->GetEditDoc().SaveGetObject( nCurPara ); + DBG_ASSERT( pPrevNode, "pPrevNode = 0!" ); + rpNodePos = new EditNodeIdx( pImpEditEngine, pPrevNode ); + rCntPos = pPrevNode->Len(); +} + +int __EXPORT EditRTFParser::IsEndPara( SvxNodeIdx* pNd, USHORT nCnt ) const +{ + return ( nCnt == ( ((EditNodeIdx*)pNd)->GetNode()->Len()) ); +} + +void __EXPORT EditRTFParser::SetAttrInDoc( SvxRTFItemStackType &rSet ) +{ + ContentNode* pSttNode = ((EditNodeIdx&)rSet.GetSttNode()).GetNode(); + ContentNode* pEndNode = ((EditNodeIdx&)rSet.GetEndNode()).GetNode(); + + EditPaM aStartPaM( pSttNode, rSet.GetSttCnt() ); + EditPaM aEndPaM( pEndNode, rSet.GetEndCnt() ); + + // ggf. noch das Escapemant-Item umbiegen: + const SfxPoolItem* pItem; + + // #i66167# adapt font heights to destination MapUnit if necessary + const MapUnit eDestUnit = ( MapUnit )( pImpEditEngine->GetEditDoc().GetItemPool().GetMetric(0) ); + const MapUnit eSrcUnit = aRTFMapMode.GetMapUnit(); + if (eDestUnit != eSrcUnit) + { + USHORT aFntHeightIems[3] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL }; + for (int i = 0; i < 2; ++i) + { + if (SFX_ITEM_SET == rSet.GetAttrSet().GetItemState( aFntHeightIems[i], FALSE, &pItem )) + { + UINT32 nHeight = ((SvxFontHeightItem*)pItem)->GetHeight(); + long nNewHeight; + nNewHeight = pImpEditEngine->GetRefDevice()->LogicToLogic( (long)nHeight, eSrcUnit, eDestUnit ); + + SvxFontHeightItem aFntHeightItem( nNewHeight, ((SvxFontHeightItem*)pItem)->GetProp(), aFntHeightIems[i] ); + rSet.GetAttrSet().Put( aFntHeightItem ); + } + } + } + + if( SFX_ITEM_SET == rSet.GetAttrSet().GetItemState( EE_CHAR_ESCAPEMENT, FALSE, &pItem )) + { + // die richtige + long nEsc = ((SvxEscapementItem*)pItem)->GetEsc(); + + if( ( DFLT_ESC_AUTO_SUPER != nEsc ) && ( DFLT_ESC_AUTO_SUB != nEsc ) ) + { + nEsc *= 10; //HalPoints => Twips wurde in RTFITEM.CXX unterschlagen! + SvxFont aFont; + pImpEditEngine->SeekCursor( aStartPaM.GetNode(), aStartPaM.GetIndex()+1, aFont ); + nEsc = nEsc * 100 / aFont.GetSize().Height(); + + SvxEscapementItem aEscItem( (short) nEsc, ((SvxEscapementItem*)pItem)->GetProp(), EE_CHAR_ESCAPEMENT ); + rSet.GetAttrSet().Put( aEscItem ); + } + } + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + EditSelection aSel( aStartPaM, aEndPaM ); + ImportInfo aImportInfo( RTFIMP_SETATTR, this, pImpEditEngine->CreateESel( aSel ) ); + aImportInfo.pAttrs = &rSet; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ContentNode* pSN = aStartPaM.GetNode(); + ContentNode* pEN = aEndPaM.GetNode(); + USHORT nStartNode = pImpEditEngine->GetEditDoc().GetPos( pSN ); + USHORT nEndNode = pImpEditEngine->GetEditDoc().GetPos( pEN ); + sal_Int16 nOutlLevel = 0xff; + + if ( rSet.StyleNo() && pImpEditEngine->GetStyleSheetPool() && pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) + { + SvxRTFStyleType* pS = GetStyleTbl().Get( rSet.StyleNo() ); + DBG_ASSERT( pS, "Vorlage in RTF nicht definiert!" ); + if ( pS ) + { + pImpEditEngine->SetStyleSheet( EditSelection( aStartPaM, aEndPaM ), (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( pS->sName, SFX_STYLE_FAMILY_ALL ) ); + nOutlLevel = pS->nOutlineNo; + } + } + + // Wenn ein Attribut von 0 bis aktuelle Absatzlaenge geht, + // soll es ein Absatz-Attribut sein! + + // Achtung: Selektion kann ueber mehrere Absaetze gehen. + // Alle vollstaendigen Absaetze sind Absatzattribute... + for ( USHORT z = nStartNode+1; z < nEndNode; z++ ) + { + DBG_ASSERT( pImpEditEngine->GetEditDoc().SaveGetObject( z ), "Node existiert noch nicht(RTF)" ); + pImpEditEngine->SetParaAttribs( z, rSet.GetAttrSet() ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + if ( aStartPaM.GetIndex() == 0 ) + pImpEditEngine->SetParaAttribs( nStartNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, EditPaM( aStartPaM.GetNode(), aStartPaM.GetNode()->Len() ) ), rSet.GetAttrSet() ); + + // Den Anfang des EndNodes.... + if ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) + pImpEditEngine->SetParaAttribs( nEndNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( EditPaM( aEndPaM.GetNode(), 0 ), aEndPaM ), rSet.GetAttrSet() ); + } + else + { + if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) + { + // #96298# When settings char attribs as para attribs, we must merge with existing attribs, not overwrite the ItemSet! + SfxItemSet aAttrs = pImpEditEngine->GetParaAttribs( nStartNode ); + aAttrs.Put( rSet.GetAttrSet() ); + pImpEditEngine->SetParaAttribs( nStartNode, aAttrs ); + } + else + { + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, aEndPaM ), rSet.GetAttrSet() ); + } + } + + // OutlLevel... + if ( nOutlLevel != 0xff ) + { + for ( USHORT n = nStartNode; n <= nEndNode; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( n ); + pNode->GetContentAttribs().GetItems().Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nOutlLevel ) ); + } + } +} + +SvxRTFStyleType* EditRTFParser::FindStyleSheet( const XubString& rName ) +{ + SvxRTFStyleType* pS = GetStyleTbl().First(); + while ( pS && ( pS->sName != rName ) ) + pS = GetStyleTbl().Next(); + + return pS; +} + +SfxStyleSheet* EditRTFParser::CreateStyleSheet( SvxRTFStyleType* pRTFStyle ) +{ + // Prueffen, ob so eine Vorlage existiert.... + // dann wird sie auch nicht geaendert! + SfxStyleSheet* pStyle = (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( pRTFStyle->sName, SFX_STYLE_FAMILY_ALL ); + if ( pStyle ) + return pStyle; + + String aName( pRTFStyle->sName ); + String aParent; + if ( pRTFStyle->nBasedOn ) + { + SvxRTFStyleType* pS = GetStyleTbl().Get( pRTFStyle->nBasedOn ); + if ( pS && ( pS !=pRTFStyle ) ) + aParent = pS->sName; + } + + pStyle = (SfxStyleSheet*) &pImpEditEngine->GetStyleSheetPool()->Make( aName, SFX_STYLE_FAMILY_PARA ); + + // 1) Items konvertieren und uebernehmen... + ConvertAndPutItems( pStyle->GetItemSet(), pRTFStyle->aAttrSet ); + + // 2) Solange Parent nicht im Pool, auch diesen kreieren... + if ( aParent.Len() && ( aParent != aName ) ) + { + SfxStyleSheet* pS = (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( aParent, SFX_STYLE_FAMILY_ALL ); + if ( !pS ) + { + // Wenn nirgendwo gefunden, aus RTF erzeugen... + SvxRTFStyleType* _pRTFStyle = FindStyleSheet( aParent ); + if ( _pRTFStyle ) + pS = CreateStyleSheet( _pRTFStyle ); + } + // 2b) ItemSet mit Parent verknuepfen... + if ( pS ) + pStyle->GetItemSet().SetParent( &pS->GetItemSet() ); + } + return pStyle; +} + +void EditRTFParser::CreateStyleSheets() +{ + // der SvxRTFParser hat jetzt die Vorlagen erzeugt... + if ( pImpEditEngine->GetStyleSheetPool() && pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) + { + SvxRTFStyleType* pRTFStyle = GetStyleTbl().First(); + while ( pRTFStyle ) + { + CreateStyleSheet( pRTFStyle ); + + pRTFStyle = GetStyleTbl().Next(); + } + } +} + +void __EXPORT EditRTFParser::CalcValue() +{ + const MapUnit eDestUnit = static_cast< MapUnit >( aEditMapMode.GetMapUnit() ); + const MapUnit eSrcUnit = aRTFMapMode.GetMapUnit(); + if (eDestUnit != eSrcUnit) + nTokenValue = OutputDevice::LogicToLogic( (long)nTokenValue, eSrcUnit, eDestUnit ); +} + +void EditRTFParser::ReadField() +{ + // Aus SwRTFParser::ReadField() + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt + BOOL bFldInst = FALSE; + BOOL bFldRslt = FALSE; + String aFldInst; + String aFldRslt; + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( GetNextToken() ) + { + case '}': + { + _nOpenBrakets--; + if ( _nOpenBrakets == 1 ) + { + bFldInst = FALSE; + bFldRslt = FALSE; + } + } + break; + + case '{': _nOpenBrakets++; + break; + + case RTF_FIELD: SkipGroup(); + break; + + case RTF_FLDINST: bFldInst = TRUE; + break; + + case RTF_FLDRSLT: bFldRslt = TRUE; + break; + + case RTF_TEXTTOKEN: + { + if ( bFldInst ) + aFldInst += aToken; + else if ( bFldRslt ) + aFldRslt += aToken; + } + break; + } + } + if ( aFldInst.Len() ) + { + String aHyperLinkMarker( RTL_CONSTASCII_USTRINGPARAM( "HYPERLINK " ) ); + if ( aFldInst.CompareIgnoreCaseToAscii( aHyperLinkMarker, aHyperLinkMarker.Len() ) == COMPARE_EQUAL ) + { + aFldInst.Erase( 0, aHyperLinkMarker.Len() ); + aFldInst.EraseLeadingChars(); + aFldInst.EraseTrailingChars(); + aFldInst.Erase( 0, 1 ); // " + aFldInst.Erase( aFldInst.Len()-1, 1 ); // " + + if ( !aFldRslt.Len() ) + aFldRslt = aFldInst; + + SvxFieldItem aField( SvxURLField( aFldInst, aFldRslt, SVXURLFORMAT_REPR ), EE_FEATURE_FIELD ); + aCurSel = pImpEditEngine->InsertField( aCurSel, aField ); + pImpEditEngine->UpdateFields(); + nLastAction = ACTION_INSERTTEXT; + } + } + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +} + +void EditRTFParser::SkipGroup() +{ + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( GetNextToken() ) + { + case '}': + { + _nOpenBrakets--; + } + break; + + case '{': + { + _nOpenBrakets++; + } + break; + } + } + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +} + +ULONG __EXPORT EditNodeIdx::GetIdx() const +{ + return pImpEditEngine->GetEditDoc().GetPos( pNode ); +} + +SvxNodeIdx* __EXPORT EditNodeIdx::Clone() const +{ + return new EditNodeIdx( pImpEditEngine, pNode ); +} + +SvxPosition* __EXPORT EditPosition::Clone() const +{ + return new EditPosition( pImpEditEngine, pCurSel ); +} + +SvxNodeIdx* __EXPORT EditPosition::MakeNodeIdx() const +{ + return new EditNodeIdx( pImpEditEngine, pCurSel->Max().GetNode() ); +} + +ULONG __EXPORT EditPosition::GetNodeIdx() const +{ + ContentNode* pN = pCurSel->Max().GetNode(); + return pImpEditEngine->GetEditDoc().GetPos( pN ); +} + +USHORT __EXPORT EditPosition::GetCntIdx() const +{ + return pCurSel->Max().GetIndex(); +} diff --git a/editeng/source/editeng/eertfpar.hxx b/editeng/source/editeng/eertfpar.hxx new file mode 100644 index 000000000000..42c75b811f33 --- /dev/null +++ b/editeng/source/editeng/eertfpar.hxx @@ -0,0 +1,128 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _EERTFPAR_HXX +#define _EERTFPAR_HXX + +#include <editeng/svxrtf.hxx> + +#include <editdoc.hxx> +#include <impedit.hxx> + +#ifndef SVX_LIGHT + +class EditNodeIdx : public SvxNodeIdx +{ +private: + ContentNode* pNode; + ImpEditEngine* pImpEditEngine; + +public: + EditNodeIdx( ImpEditEngine* pIEE, ContentNode* pNd = 0) + { pImpEditEngine = pIEE; pNode = pNd; } + virtual ULONG GetIdx() const; + virtual SvxNodeIdx* Clone() const; + ContentNode* GetNode() { return pNode; } +}; + +class EditPosition : public SvxPosition +{ +private: + EditSelection* pCurSel; + ImpEditEngine* pImpEditEngine; + +public: + EditPosition( ImpEditEngine* pIEE, EditSelection* pSel ) + { pImpEditEngine = pIEE; pCurSel = pSel; } + + virtual ULONG GetNodeIdx() const; + virtual USHORT GetCntIdx() const; + + // erzeuge von sich selbst eine Kopie + virtual SvxPosition* Clone() const; + + // erzeuge vom NodeIndex eine Kopie + virtual SvxNodeIdx* MakeNodeIdx() const; +}; + +#define ACTION_INSERTTEXT 1 +#define ACTION_INSERTPARABRK 2 + +class EditRTFParser : public SvxRTFParser +{ +private: + EditSelection aCurSel; + ImpEditEngine* pImpEditEngine; + CharSet eDestCharSet; + MapMode aRTFMapMode; + MapMode aEditMapMode; + + USHORT nDefFont; + USHORT nDefTab; + USHORT nDefFontHeight; + BYTE nLastAction; + +protected: + virtual void InsertPara(); + virtual void InsertText(); + virtual void MovePos( int bForward = TRUE ); + virtual void SetEndPrevPara( SvxNodeIdx*& rpNodePos, + USHORT& rCntPos ); + + virtual void UnknownAttrToken( int nToken, SfxItemSet* pSet ); + virtual void NextToken( int nToken ); + virtual void SetAttrInDoc( SvxRTFItemStackType &rSet ); + virtual int IsEndPara( SvxNodeIdx* pNd, USHORT nCnt ) const; + virtual void CalcValue(); + void CreateStyleSheets(); + SfxStyleSheet* CreateStyleSheet( SvxRTFStyleType* pRTFStyle ); + SvxRTFStyleType* FindStyleSheet( const String& rName ); + void AddRTFDefaultValues( const EditPaM& rStart, const EditPaM& rEnd ); + void ReadField(); + void SkipGroup(); + +public: + EditRTFParser( SvStream& rIn, EditSelection aCurSel, SfxItemPool& rAttrPool, ImpEditEngine* pImpEditEngine ); + ~EditRTFParser(); + + virtual SvParserState CallParser(); + + + void SetDestCharSet( CharSet eCharSet ) { eDestCharSet = eCharSet; } + CharSet GetDestCharSet() const { return eDestCharSet; } + + USHORT GetDefTab() const { return nDefTab; } + Font GetDefFont() { return GetFont( nDefFont ); } + + EditPaM GetCurPaM() const { return aCurSel.Max(); } +}; + +SV_DECL_REF( EditRTFParser ) +SV_IMPL_REF( EditRTFParser ); + + +#endif // !SVX_LIGH +#endif //_EERTFPAR_HXX diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx new file mode 100644 index 000000000000..b327d2a685bd --- /dev/null +++ b/editeng/source/editeng/impedit.cxx @@ -0,0 +1,2002 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <tools/poly.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/linguistic2/XDictionaryEntry.hpp> +#include <com/sun/star/linguistic2/DictionaryType.hpp> +#include <com/sun/star/linguistic2/DictionaryEvent.hpp> +#include <com/sun/star/linguistic2/XDictionaryEventListener.hpp> +#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp> +#include <com/sun/star/linguistic2/XDictionary.hpp> +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> +#include <vos/mutex.hxx> +#include <editeng/flditem.hxx> +#include <svl/intitem.hxx> +#include <svtools/transfer.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + +#define SCRLRANGE 20 // 1/20 der Breite/Hoehe scrollen, wenn im QueryDrop + +inline void lcl_AllignToPixel( Point& rPoint, OutputDevice* pOutDev, short nDiffX, short nDiffY ) +{ + rPoint = pOutDev->LogicToPixel( rPoint ); + + if ( nDiffX ) + rPoint.X() += nDiffX; + if ( nDiffY ) + rPoint.Y() += nDiffY; + + rPoint = pOutDev->PixelToLogic( rPoint ); +} + +// ---------------------------------------------------------------------- +// class ImpEditView +// ---------------------------------------------------------------------- +ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, Window* pWindow ) : + aOutArea( Point(), pEng->GetPaperSize() ) +{ + pEditView = pView; + pEditEngine = pEng; + pOutWin = pWindow; + pPointer = NULL; + pBackgroundColor = NULL; + nScrollDiffX = 0; + nExtraCursorFlags = 0; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + pCursor = NULL; + pDragAndDropInfo = NULL; + bReadOnly = sal_False; + bClickedInSelection = sal_False; + eSelectionMode = EE_SELMODE_TXTONLY; + eAnchorMode = ANCHOR_TOP_LEFT; + nInvMore = 1; + nTravelXPos = TRAVEL_X_DONTKNOW; + nControl = EV_CNTRL_AUTOSCROLL | EV_CNTRL_ENABLEPASTE; + bActiveDragAndDropListener = FALSE; + + aEditSelection.Min() = pEng->pImpEditEngine->GetEditDoc().GetStartPaM(); + aEditSelection.Max() = pEng->pImpEditEngine->GetEditDoc().GetEndPaM(); +} + +ImpEditView::~ImpEditView() +{ + RemoveDragAndDropListeners(); + + if ( pOutWin && ( pOutWin->GetCursor() == pCursor ) ) + pOutWin->SetCursor( NULL ); + + delete pCursor; + delete pBackgroundColor; + delete pPointer; + delete pDragAndDropInfo; +} + +void ImpEditView::SetBackgroundColor( const Color& rColor ) +{ + delete pBackgroundColor; + pBackgroundColor = new Color( rColor ); +} + +void ImpEditView::SetEditSelection( const EditSelection& rEditSelection ) +{ + // #100856# set state before notification + aEditSelection = rEditSelection; + + if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTVIEWSELECTIONCHANGED ); + aNotify.pEditEngine = pEditEngine; + aNotify.pEditView = GetEditViewPtr(); + pEditEngine->pImpEditEngine->CallNotify( aNotify ); + } +} + + +void ImpEditView::DrawSelection( EditSelection aTmpSel, Region* pRegion ) +{ + if ( GetSelectionMode() == EE_SELMODE_HIDDEN ) + return; + + // Vor dem Zeichnen der Selektion muss sichergestellt werden, + // das der Fensterinhalt komplett gueltig ist! + // Muss hier stehen, damit auf jeden Fall weg wenn lerr, nicht spaeter + // zwei Paint-Events! + // 19.10: Muss sogar vor Abfrage von bUpdate, falls nach Invalidate + // noch Paints in der Queue, aber jemand schaltet den UpdateMode um! + + // pRegion: Wenn nicht NULL, dann nur Region berechnen. + PolyPolygon* pPolyPoly = NULL; + if ( pRegion ) + pPolyPoly = new PolyPolygon; + + sal_Bool bClipRegion = pOutWin->IsClipRegion(); + Region aOldRegion = pOutWin->GetClipRegion(); + + if ( !pRegion ) + { + if ( pEditEngine->pImpEditEngine->GetUpdateMode() == sal_False ) + return; + if ( pEditEngine->pImpEditEngine->IsInUndo() ) + return; + + if ( !aTmpSel.HasRange() ) + return; + + // aTmpOutArea: Falls OutputArea > Papierbreite und + // Text > Papierbreite ( uebergrosse Felder ) + Rectangle aTmpOutArea( aOutArea ); + if ( aTmpOutArea.GetWidth() > pEditEngine->pImpEditEngine->GetPaperSize().Width() ) + aTmpOutArea.Right() = aTmpOutArea.Left() + pEditEngine->pImpEditEngine->GetPaperSize().Width(); + pOutWin->IntersectClipRegion( aTmpOutArea ); + + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Hide(); + } + + DBG_ASSERT( !pEditEngine->pImpEditEngine->aIdleFormatter.IsActive(), "DrawSelection: Not formatted!" ); + aTmpSel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + ContentNode* pStartNode = aTmpSel.Min().GetNode(); + ContentNode* pEndNode = aTmpSel.Max().GetNode(); + sal_uInt16 nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( pStartNode ); + sal_uInt16 nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( pEndNode ); + // ueber die Absaetze iterieren.... + for ( sal_uInt16 nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ParaPortion* pTmpPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + DBG_ASSERT( pTmpPortion, "Portion in Selektion nicht gefunden!" ); + DBG_ASSERT( !pTmpPortion->IsInvalid(), "Portion in Selektion nicht formatiert!" ); + + if ( !pTmpPortion->IsVisible() || pTmpPortion->IsInvalid() ) + continue; + + long nParaStart = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pTmpPortion ); + if ( ( nParaStart + pTmpPortion->GetHeight() ) < GetVisDocTop() ) + continue; + if ( nParaStart > GetVisDocBottom() ) + break; + + sal_uInt16 nStartLine = 0; + sal_uInt16 nEndLine = pTmpPortion->GetLines().Count() -1; + if ( nPara == nStartPara ) + nStartLine = pTmpPortion->GetLines().FindLine( aTmpSel.Min().GetIndex(), sal_False ); + if ( nPara == nEndPara ) + nEndLine = pTmpPortion->GetLines().FindLine( aTmpSel.Max().GetIndex(), sal_True ); + + // ueber die Zeilen iterieren.... + for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ ) + { + EditLine* pLine = pTmpPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: DrawSelection()" ); + + BOOL bPartOfLine = FALSE; + sal_uInt16 nStartIndex = pLine->GetStart(); + sal_uInt16 nEndIndex = pLine->GetEnd(); + if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) && ( nStartIndex != aTmpSel.Min().GetIndex() ) ) + { + nStartIndex = aTmpSel.Min().GetIndex(); + bPartOfLine = TRUE; + } + if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) && ( nEndIndex != aTmpSel.Max().GetIndex() ) ) + { + nEndIndex = aTmpSel.Max().GetIndex(); + bPartOfLine = TRUE; + } + + // Kann passieren, wenn am Anfang einer umgebrochenen Zeile. + if ( nEndIndex < nStartIndex ) + nEndIndex = nStartIndex; + + Rectangle aTmpRec( pEditEngine->pImpEditEngine->GetEditCursor( pTmpPortion, nStartIndex ) ); + Point aTopLeft( aTmpRec.TopLeft() ); + Point aBottomRight( aTmpRec.BottomRight() ); + + aTopLeft.Y() += nParaStart; + aBottomRight.Y() += nParaStart; + + // Nur Painten, wenn im sichtbaren Bereich... + if ( aTopLeft.Y() > GetVisDocBottom() ) + break; + + if ( aBottomRight.Y() < GetVisDocTop() ) + continue; + + // Now that we have Bidi, the first/last index doesn't have to be the 'most outside' postion + if ( !bPartOfLine ) + { + Range aLineXPosStartEnd = pEditEngine->pImpEditEngine->GetLineXPosStartEnd( pTmpPortion, pLine ); + aTopLeft.X() = aLineXPosStartEnd.Min(); + aBottomRight.X() = aLineXPosStartEnd.Max(); + ImplDrawHighlightRect( pOutWin, aTopLeft, aBottomRight, pPolyPoly ); + } + else + { + USHORT nTmpStartIndex = nStartIndex; + USHORT nWritingDirStart, nTmpEndIndex; + + while ( nTmpStartIndex < nEndIndex ) + { + pEditEngine->pImpEditEngine->GetRightToLeft( nPara, nTmpStartIndex+1, &nWritingDirStart, &nTmpEndIndex ); + if ( nTmpEndIndex > nEndIndex ) + nTmpEndIndex = nEndIndex; + + DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelection, Start >= End?" ); + + long nX1 = pEditEngine->pImpEditEngine->GetXPos( pTmpPortion, pLine, nTmpStartIndex, TRUE ); + long nX2 = pEditEngine->pImpEditEngine->GetXPos( pTmpPortion, pLine, nTmpEndIndex ); + + Point aPt1( Min( nX1, nX2 ), aTopLeft.Y() ); + Point aPt2( Max( nX1, nX2 ), aBottomRight.Y() ); + + ImplDrawHighlightRect( pOutWin, aPt1, aPt2, pPolyPoly ); + + nTmpStartIndex = nTmpEndIndex; + } + } + + } + } + + if ( pRegion ) + { + *pRegion = Region( *pPolyPoly ); + delete pPolyPoly; + } + else + { + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Show(); + + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + } +} + +void ImpEditView::ImplDrawHighlightRect( Window* _pOutWin, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, PolyPolygon* pPolyPoly ) +{ + if ( rDocPosTopLeft.X() != rDocPosBottomRight.X() ) + { + sal_Bool bPixelMode = _pOutWin->GetMapMode() == MAP_PIXEL; + + Point aPnt1( GetWindowPos( rDocPosTopLeft ) ); + Point aPnt2( GetWindowPos( rDocPosBottomRight ) ); + + if ( !IsVertical() ) + { + lcl_AllignToPixel( aPnt1, _pOutWin, +1, 0 ); + lcl_AllignToPixel( aPnt2, _pOutWin, 0, ( bPixelMode ? 0 : -1 ) ); + } + else + { + lcl_AllignToPixel( aPnt1, _pOutWin, 0, +1 ); + lcl_AllignToPixel( aPnt2, _pOutWin, ( bPixelMode ? 0 : +1 ), 0 ); + } + + Rectangle aRect( aPnt1, aPnt2 ); + if ( pPolyPoly ) + { + Polygon aTmpPoly( 4 ); + aTmpPoly[0] = aRect.TopLeft(); + aTmpPoly[1] = aRect.TopRight(); + aTmpPoly[2] = aRect.BottomRight(); + aTmpPoly[3] = aRect.BottomLeft(); + pPolyPoly->Insert( aTmpPoly ); + } + else + { + _pOutWin->Invert( aRect ); + } + } +} + + +BOOL ImpEditView::IsVertical() const +{ + return pEditEngine->pImpEditEngine->IsVertical(); +} + +Rectangle ImpEditView::GetVisDocArea() const +{ + return Rectangle( GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom() ); +} + +Point ImpEditView::GetDocPos( const Point& rWindowPos ) const +{ + // Fensterposition => Dokumentposition + Point aPoint; + + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aPoint.X() = rWindowPos.X() - aOutArea.Left() + GetVisDocLeft(); + aPoint.Y() = rWindowPos.Y() - aOutArea.Top() + GetVisDocTop(); + } + else + { + aPoint.X() = rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft(); + aPoint.Y() = aOutArea.Right() - rWindowPos.X() + GetVisDocTop(); + } + + return aPoint; +} + +Point ImpEditView::GetWindowPos( const Point& rDocPos ) const +{ + // Dokumentposition => Fensterposition + Point aPoint; + + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aPoint.X() = rDocPos.X() + aOutArea.Left() - GetVisDocLeft(); + aPoint.Y() = rDocPos.Y() + aOutArea.Top() - GetVisDocTop(); + } + else + { + aPoint.X() = aOutArea.Right() - rDocPos.Y() + GetVisDocTop(); + aPoint.Y() = rDocPos.X() + aOutArea.Top() - GetVisDocLeft(); + } + + return aPoint; +} + +Rectangle ImpEditView::GetWindowPos( const Rectangle& rDocRect ) const +{ + // Dokumentposition => Fensterposition + Point aPos( GetWindowPos( rDocRect.TopLeft() ) ); + Size aSz = rDocRect.GetSize(); + Rectangle aRect; + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aRect = Rectangle( aPos, aSz ); + } + else + { + Point aNewPos( aPos.X()-aSz.Height(), aPos.Y() ); + aRect = Rectangle( aNewPos, Size( aSz.Height(), aSz.Width() ) ); + } + return aRect; +} + + +Region* ImpEditView::CalcSelectedRegion() +{ + Region* pRegion = new Region; + DrawSelection( GetEditSelection(), pRegion ); + return pRegion; +} + +void ImpEditView::SetSelectionMode( EESelectionMode eNewMode ) +{ + if ( eSelectionMode != eNewMode ) + { + DrawSelection(); // 'Wegmalen' ... + eSelectionMode = eNewMode; + DrawSelection(); // und neu zeichnen. + } +} + +void ImpEditView::SetOutputArea( const Rectangle& rRec ) +{ + // sollte besser auf Pixel allignt sein! + Rectangle aNewRec( pOutWin->LogicToPixel( rRec ) ); + aNewRec = pOutWin->PixelToLogic( aNewRec ); + aOutArea = aNewRec; + if ( aOutArea.Right() < aOutArea.Left() ) + aOutArea.Right() = aOutArea.Left(); + if ( aOutArea.Bottom() < aOutArea.Top() ) + aOutArea.Bottom() = aOutArea.Top(); + + if ( DoBigScroll() ) + SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 3 / 10 ); + else + SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 2 / 10 ); +} + +void ImpEditView::ResetOutputArea( const Rectangle& rRec ) +{ + Rectangle aCurArea( aOutArea ); + SetOutputArea( rRec ); + // Umliegende Bereiche invalidieren, wenn UpdateMode der Engine auf sal_True + if ( !aCurArea.IsEmpty() && pEditEngine->pImpEditEngine->GetUpdateMode() ) + { + long nMore = 0; + if ( DoInvalidateMore() ) + nMore = GetWindow()->PixelToLogic( Size( nInvMore, 0 ) ).Width(); + if ( aCurArea.Left() < aOutArea.Left() ) + { + Rectangle aRect( aCurArea.TopLeft(), + Size( aOutArea.Left()-aCurArea.Left(), aCurArea.GetHeight() ) ); + if ( nMore ) + { + aRect.Left() -= nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Right() > aOutArea.Right() ) + { + long nW = aCurArea.Right() - aOutArea.Right(); + Point aPos( aCurArea.TopRight() ); + aPos.X() -= nW; + Rectangle aRect( aPos, Size( nW, aCurArea.GetHeight() ) ); + if ( nMore ) + { + aRect.Right() += nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Top() < aOutArea.Top() ) + { + Rectangle aRect( aCurArea.TopLeft(), Size( aCurArea.GetWidth(), aOutArea.Top() - aCurArea.Top() ) ); + if ( nMore ) + { + aRect.Top() -= nMore; + aRect.Left() -= nMore; + aRect.Right() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Bottom() > aOutArea.Bottom() ) + { + long nH = aCurArea.Bottom() - aOutArea.Bottom(); + Point aPos( aCurArea.BottomLeft() ); + aPos.Y() -= nH; + Rectangle aRect( aPos, Size( aCurArea.GetWidth(), nH ) ); + if ( nMore ) + { + aRect.Bottom() += nMore; + aRect.Left() -= nMore; + aRect.Right() += nMore; + } + + GetWindow()->Invalidate( aRect ); + } + } +} + +void ImpEditView::RecalcOutputArea() +{ + Rectangle aOldArea( aOutArea ); + Point aNewTopLeft( aOutArea.TopLeft() ); + Size aNewSz( aOutArea.GetSize() ); + + // X: + if ( DoAutoWidth() ) + { + if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageWidth() ) + aNewSz.Width() = pEditEngine->pImpEditEngine->GetPaperSize().Width(); + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_VCENTER_LEFT: + case ANCHOR_BOTTOM_LEFT: + { + aNewTopLeft.X() = aAnchorPoint.X(); + } + break; + case ANCHOR_TOP_HCENTER: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_BOTTOM_HCENTER: + { + aNewTopLeft.X() = aAnchorPoint.X() - aNewSz.Width() / 2; + } + break; + case ANCHOR_TOP_RIGHT: + case ANCHOR_VCENTER_RIGHT: + case ANCHOR_BOTTOM_RIGHT: + { + aNewTopLeft.X() = aAnchorPoint.X() - aNewSz.Width() - 1; + } + break; + } + } + + // Y: + if ( DoAutoHeight() ) + { + if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageHeight() ) + aNewSz.Height() = pEditEngine->pImpEditEngine->GetPaperSize().Height(); + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_TOP_HCENTER: + case ANCHOR_TOP_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y(); + } + break; + case ANCHOR_VCENTER_LEFT: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_VCENTER_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y() - aNewSz.Height() / 2; + } + break; + case ANCHOR_BOTTOM_LEFT: + case ANCHOR_BOTTOM_HCENTER: + case ANCHOR_BOTTOM_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y() - aNewSz.Height() - 1; + } + break; + } + } + ResetOutputArea( Rectangle( aNewTopLeft, aNewSz ) ); +} + +void ImpEditView::SetAnchorMode( EVAnchorMode eMode ) +{ + eAnchorMode = eMode; + CalcAnchorPoint(); +} + +void ImpEditView::CalcAnchorPoint() +{ + // GetHeight() und GetWidth() -1, da Rectangle-Berechnung nicht erwuenscht. + + // X: + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_VCENTER_LEFT: + case ANCHOR_BOTTOM_LEFT: + { + aAnchorPoint.X() = aOutArea.Left(); + } + break; + case ANCHOR_TOP_HCENTER: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_BOTTOM_HCENTER: + { + aAnchorPoint.X() = aOutArea.Left() + (aOutArea.GetWidth()-1) / 2; + } + break; + case ANCHOR_TOP_RIGHT: + case ANCHOR_VCENTER_RIGHT: + case ANCHOR_BOTTOM_RIGHT: + { + aAnchorPoint.X() = aOutArea.Right(); + } + break; + } + + // Y: + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_TOP_HCENTER: + case ANCHOR_TOP_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Top(); + } + break; + case ANCHOR_VCENTER_LEFT: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_VCENTER_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Top() + (aOutArea.GetHeight()-1) / 2; + } + break; + case ANCHOR_BOTTOM_LEFT: + case ANCHOR_BOTTOM_HCENTER: + case ANCHOR_BOTTOM_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Bottom() - 1; + } + break; + } +} + +void ImpEditView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, USHORT nShowCursorFlags ) +{ + // Kein ShowCursor bei einer leeren View... + if ( ( aOutArea.Left() >= aOutArea.Right() ) && ( aOutArea.Top() >= aOutArea.Bottom() ) ) + return; + + pEditEngine->pImpEditEngine->CheckIdleFormatter(); + if ( !pEditEngine->pImpEditEngine->IsFormatted() ) + pEditEngine->pImpEditEngine->FormatDoc(); + + // Aus irgendwelchen Gruenden lande ich waehrend der Formatierung hier, + // wenn sich der Outiner im Paint initialisiert, weil kein SetPool(); + if ( pEditEngine->pImpEditEngine->IsFormatting() ) + return; + if ( pEditEngine->pImpEditEngine->GetUpdateMode() == sal_False ) + return; + if ( pEditEngine->pImpEditEngine->IsInUndo() ) + return; + + if ( pOutWin->GetCursor() != GetCursor() ) + pOutWin->SetCursor( GetCursor() ); + + EditPaM aPaM( aEditSelection.Max() ); + + USHORT nTextPortionStart = 0; + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + if (nPara == USHRT_MAX) // #i94322 + return; + ParaPortion* pParaPortion = pEditEngine->pImpEditEngine->GetParaPortions().GetObject( nPara ); + + nShowCursorFlags |= nExtraCursorFlags; + + nShowCursorFlags |= GETCRSR_TXTONLY; + + // Use CursorBidiLevel 0/1 in meaning of + // 0: prefer portion end, normal mode + // 1: prefer portion start + + if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW ) && GetCursorBidiLevel() ) + { + nShowCursorFlags |= GETCRSR_PREFERPORTIONSTART; + } + + Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags ); + if ( !IsInsertMode() && !aEditSelection.HasRange() ) + { + if ( aPaM.GetNode()->Len() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) + { + // If we are behind a portion, and the next portion has other direction, we must change position... + aEditCursor.Left() = aEditCursor.Right() = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GETCRSR_TXTONLY|GETCRSR_PREFERPORTIONSTART ).Left(); + + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, TRUE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) + { + aEditCursor.Right() += pTextPortion->GetSize().Width(); + } + else + { + EditPaM aNext = pEditEngine->pImpEditEngine->CursorRight( aPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL ); + Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GETCRSR_TXTONLY ); + if ( aTmpRect.Top() != aEditCursor.Top() ) + aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GETCRSR_TXTONLY|GETCRSR_ENDOFLINE ); + aEditCursor.Right() = aTmpRect.Left(); + } + } + } + long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth(); + if ( aEditCursor.GetHeight() > nMaxHeight ) + { + aEditCursor.Bottom() = aEditCursor.Top() + nMaxHeight - 1; + } + if ( bGotoCursor ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) ) + { + // pruefen, ob scrollen notwendig... + // wenn scrollen, dann Update() und Scroll() ! + long nDocDiffX = 0; + long nDocDiffY = 0; + + Rectangle aTmpVisArea( GetVisDocArea() ); + // aTmpOutArea: Falls OutputArea > Papierbreite und + // Text > Papierbreite ( uebergrosse Felder ) + long nMaxTextWidth = !IsVertical() ? pEditEngine->pImpEditEngine->GetPaperSize().Width() : pEditEngine->pImpEditEngine->GetPaperSize().Height(); + if ( aTmpVisArea.GetWidth() > nMaxTextWidth ) + aTmpVisArea.Right() = aTmpVisArea.Left() + nMaxTextWidth; + + if ( aEditCursor.Bottom() > aTmpVisArea.Bottom() ) + { // hochscrollen, hier positiv + nDocDiffY = aEditCursor.Bottom() - aTmpVisArea.Bottom(); + } + else if ( aEditCursor.Top() < aTmpVisArea.Top() ) + { // runterscrollen, negativ + nDocDiffY = aEditCursor.Top() - aTmpVisArea.Top(); + } + + if ( aEditCursor.Right() > aTmpVisArea.Right() ) + { + // linksscrollen, positiv + nDocDiffX = aEditCursor.Right() - aTmpVisArea.Right(); + // Darfs ein bischen mehr sein? + if ( aEditCursor.Right() < ( nMaxTextWidth - GetScrollDiffX() ) ) + nDocDiffX += GetScrollDiffX(); + else + { + long n = nMaxTextWidth - aEditCursor.Right(); + // Bei einem MapMode != RefMapMode kann der EditCursor auch mal ueber + // die Papierbreite Wandern! + nDocDiffX += ( n > 0 ? n : -n ); + } + } + else if ( aEditCursor.Left() < aTmpVisArea.Left() ) + { // rechtsscrollen + // negativ: + nDocDiffX = aEditCursor.Left() - aTmpVisArea.Left(); + // Darfs ein bischen mehr sein? + if ( aEditCursor.Left() > ( - (long)GetScrollDiffX() ) ) + nDocDiffX -= GetScrollDiffX(); + else + nDocDiffX -= aEditCursor.Left(); + } + if ( aPaM.GetIndex() == 0 ) // braucht Olli fuer den Outliner + { + // Aber sicherstellen, dass dadurch der Cursor nicht den + // sichtbaren bereich verlaesst! + if ( aEditCursor.Left() < aTmpVisArea.GetWidth() ) + { + nDocDiffX = -aTmpVisArea.Left(); + } + } + + if ( nDocDiffX | nDocDiffY ) + { + long nDiffX = !IsVertical() ? nDocDiffX : -nDocDiffY; + long nDiffY = !IsVertical() ? nDocDiffY : nDocDiffX; + + // Negativ: Zum Anfang bzw. linken Rand + if ( ( Abs( nDiffY ) > pEditEngine->pImpEditEngine->nOnePixelInRef ) && DoBigScroll() ) + { + long nH = aOutArea.GetHeight() / 4; + if ( ( nH > aEditCursor.GetHeight() ) && ( Abs( nDiffY ) < nH ) ) + { + if ( nDiffY < 0 ) + nDiffY -= nH; + else + nDiffY += nH; + } + } + + if ( ( Abs( nDiffX ) > pEditEngine->pImpEditEngine->nOnePixelInRef ) && DoBigScroll() ) + { + long nW = aOutArea.GetWidth() / 4; + if ( Abs( nDiffX ) < nW ) + { + if ( nDiffY < 0 ) + nDiffY -= nW; + else + nDiffY += nW; + } + } + + if ( nDiffX ) + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_HSCROLL; + if ( nDiffY ) + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_VSCROLL; + Scroll( -nDiffX, -nDiffY ); + pEditEngine->pImpEditEngine->DelayedCallStatusHdl(); + } + } + + // Cursor evtl. etwas stutzen... + if ( ( aEditCursor.Bottom() > GetVisDocTop() ) && + ( aEditCursor.Top() < GetVisDocBottom() ) ) + { + if ( aEditCursor.Bottom() > GetVisDocBottom() ) + aEditCursor.Bottom() = GetVisDocBottom(); + if ( aEditCursor.Top() < GetVisDocTop() ) + aEditCursor.Top() = GetVisDocTop(); + } + + long nOnePixel = pOutWin->PixelToLogic( Size( 1, 0 ) ).Width(); + + if ( /* pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() || */ + ( ( aEditCursor.Top() + nOnePixel >= GetVisDocTop() ) && + ( aEditCursor.Bottom() - nOnePixel <= GetVisDocBottom() ) && + ( aEditCursor.Left() + nOnePixel >= GetVisDocLeft() ) && + ( aEditCursor.Right() - nOnePixel <= GetVisDocRight() ) ) ) + { + Rectangle aCursorRect = GetWindowPos( aEditCursor ); + GetCursor()->SetPos( aCursorRect.TopLeft() ); + Size aCursorSz( aCursorRect.GetSize() ); + // Rectangle is inclusive + aCursorSz.Width()--; + aCursorSz.Height()--; + if ( !aCursorSz.Width() || !aCursorSz.Height() ) + { + long nCursorSz = pOutWin->GetSettings().GetStyleSettings().GetCursorSize(); + nCursorSz = pOutWin->PixelToLogic( Size( nCursorSz, 0 ) ).Width(); + if ( !aCursorSz.Width() ) + aCursorSz.Width() = nCursorSz; + if ( !aCursorSz.Height() ) + aCursorSz.Height() = nCursorSz; + } + // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag + if ( IsVertical() ) + { + Size aOldSz( aCursorSz ); + aCursorSz.Width() = aOldSz.Height(); + aCursorSz.Height() = aOldSz.Width(); + GetCursor()->SetPos( aCursorRect.TopRight() ); + GetCursor()->SetOrientation( 2700 ); + } + else + // --> FME 2004-10-18 #i32593# + // Reset correct orientation in horizontal layout + GetCursor()->SetOrientation( 0 ); + // <-- + + GetCursor()->SetSize( aCursorSz ); + + unsigned char nCursorDir = CURSOR_DIRECTION_NONE; + if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) ) + { + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, nShowCursorFlags & GETCRSR_PREFERPORTIONSTART ? TRUE : FALSE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); + if ( nRTLLevel%2 ) + nCursorDir = CURSOR_DIRECTION_RTL; + else + nCursorDir = CURSOR_DIRECTION_LTR; + + } + GetCursor()->SetDirection( nCursorDir ); + + if ( bForceVisCursor ) + GetCursor()->Show(); + + // #102936# Call SetInputContext every time, otherwise we may have the wrong font + // if ( !pEditEngine->pImpEditEngine->mpIMEInfos ) + { + SvxFont aFont; + pEditEngine->pImpEditEngine->SeekCursor( aPaM.GetNode(), aPaM.GetIndex()+1, aFont ); + ULONG nContextFlags = INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT; + GetWindow()->SetInputContext( InputContext( aFont, nContextFlags ) ); + } + } + else + { + pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() = pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() | EE_STAT_CURSOROUT; + GetCursor()->Hide(); + GetCursor()->SetPos( Point( -1, -1 ) ); + GetCursor()->SetSize( Size( 0, 0 ) ); + } +} + +Pair ImpEditView::Scroll( long ndX, long ndY, BYTE nRangeCheck ) +{ + DBG_ASSERT( pEditEngine->pImpEditEngine->IsFormatted(), "Scroll: Nicht formatiert!" ); + if ( !ndX && !ndY ) + return Range( 0, 0 ); + +#ifdef DBG_UTIL + Rectangle aR( aOutArea ); + aR = pOutWin->LogicToPixel( aR ); + aR = pOutWin->PixelToLogic( aR ); + DBG_ASSERTWARNING( aR == aOutArea, "OutArea vor Scroll nicht aligned" ); +#endif + + Rectangle aNewVisArea( GetVisDocArea() ); + Size aPaperSz( pEditEngine->pImpEditEngine->GetPaperSize() ); + + // Vertical: + if ( !IsVertical() ) + { + aNewVisArea.Top() -= ndY; + aNewVisArea.Bottom() -= ndY; + } + else + { + aNewVisArea.Top() += ndX; + aNewVisArea.Bottom() += ndX; + } + if ( ( nRangeCheck == RGCHK_PAPERSZ1 ) && ( aNewVisArea.Bottom() > (long)pEditEngine->pImpEditEngine->GetTextHeight() ) ) + { + // GetTextHeight noch optimieren! + long nDiff = pEditEngine->pImpEditEngine->GetTextHeight() - aNewVisArea.Bottom(); // negativ + aNewVisArea.Move( 0, nDiff ); // koennte im neg. Bereich landen... + } + if ( ( aNewVisArea.Top() < 0 ) && ( nRangeCheck != RGCHK_NONE ) ) + aNewVisArea.Move( 0, -aNewVisArea.Top() ); + + // Horizontal: + if ( !IsVertical() ) + { + aNewVisArea.Left() -= ndX; + aNewVisArea.Right() -= ndX; + } + else + { + aNewVisArea.Left() -= ndY; + aNewVisArea.Right() -= ndY; + } + if ( ( nRangeCheck == RGCHK_PAPERSZ1 ) && ( aNewVisArea.Right() > (long)pEditEngine->pImpEditEngine->CalcTextWidth( FALSE ) ) ) + { + long nDiff = pEditEngine->pImpEditEngine->CalcTextWidth( FALSE ) - aNewVisArea.Right(); // negativ + aNewVisArea.Move( nDiff, 0 ); // koennte im neg. Bereich landen... + } + if ( ( aNewVisArea.Left() < 0 ) && ( nRangeCheck != RGCHK_NONE ) ) + aNewVisArea.Move( -aNewVisArea.Left(), 0 ); + + // Die Differenz muss auf Pixel alignt sein (wegen Scroll!) + long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : -( GetVisDocTop() - aNewVisArea.Top() ); + long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : ( GetVisDocLeft() - aNewVisArea.Left() ); + + Size aDiffs( nDiffX, nDiffY ); + aDiffs = pOutWin->LogicToPixel( aDiffs ); + aDiffs = pOutWin->PixelToLogic( aDiffs ); + + long nRealDiffX = aDiffs.Width(); + long nRealDiffY = aDiffs.Height(); + + + if ( nRealDiffX || nRealDiffY ) + { + Cursor* pCrsr = GetCursor(); + sal_Bool bVisCursor = pCrsr->IsVisible(); + pCrsr->Hide(); + pOutWin->Update(); + if ( !IsVertical() ) + aVisDocStartPos.Move( -nRealDiffX, -nRealDiffY ); + else + aVisDocStartPos.Move( -nRealDiffY, nRealDiffX ); + // Das Move um den allignten Wert ergibt nicht unbedingt ein + // alligntes Rechteck... + // MT 11/00: Align VisArea??? + aVisDocStartPos = pOutWin->LogicToPixel( aVisDocStartPos ); + aVisDocStartPos = pOutWin->PixelToLogic( aVisDocStartPos ); + Rectangle aRec( aOutArea ); + pOutWin->Scroll( nRealDiffX, nRealDiffY, aRec, sal_True ); + pOutWin->Update(); + pCrsr->SetPos( pCrsr->GetPos() + Point( nRealDiffX, nRealDiffY ) ); + if ( bVisCursor ) + { + Rectangle aCursorRec( pCrsr->GetPos(), pCrsr->GetSize() ); + if ( aOutArea.IsInside( aCursorRec ) ) + pCrsr->Show(); + } + + if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTVIEWSCROLLED ); + aNotify.pEditEngine = pEditEngine; + aNotify.pEditView = GetEditViewPtr(); + pEditEngine->pImpEditEngine->CallNotify( aNotify ); + } + } + + return Pair( nRealDiffX, nRealDiffY ); +} + +sal_Bool ImpEditView::PostKeyEvent( const KeyEvent& rKeyEvent ) +{ + BOOL bDone = FALSE; + + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_CUT: + { + if ( !bReadOnly ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + CutCopy( aClipBoard, sal_True ); + bDone = sal_True; + } + } + break; + case KEYFUNC_COPY: + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + CutCopy( aClipBoard, sal_False ); + bDone = TRUE; + } + break; + case KEYFUNC_PASTE: + { + if ( !bReadOnly && IsPasteEnabled() ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + Paste( aClipBoard, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_PASTE ); + bDone = sal_True; + } + } + break; + default: + break; + } + } + + if( !bDone ) + bDone = pEditEngine->PostKeyEvent( rKeyEvent, GetEditViewPtr() ); + + return bDone; +} + +sal_Bool ImpEditView::MouseButtonUp( const MouseEvent& rMouseEvent ) +{ + if ( pEditEngine->pImpEditEngine->aStatus.NotifyCursorMovements() ) + { + if ( pEditEngine->pImpEditEngine->aStatus.GetPrevParagraph() != pEditEngine->pImpEditEngine->GetEditDoc().GetPos( GetEditSelection().Max().GetNode() ) ) + { + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_CRSRLEFTPARA; + pEditEngine->pImpEditEngine->CallStatusHdl(); + } + } + nTravelXPos = TRAVEL_X_DONTKNOW; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + nExtraCursorFlags = 0; + bClickedInSelection = sal_False; + + if ( rMouseEvent.IsMiddle() && !bReadOnly && + ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetPrimarySelection()); + Paste( aClipBoard ); + } + else if ( rMouseEvent.IsLeft() && GetEditSelection().HasRange() ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetPrimarySelection()); + CutCopy( aClipBoard, FALSE ); + } + + return pEditEngine->pImpEditEngine->MouseButtonUp( rMouseEvent, GetEditViewPtr() ); +} + +sal_Bool ImpEditView::MouseButtonDown( const MouseEvent& rMouseEvent ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + if ( pEditEngine->pImpEditEngine->aStatus.NotifyCursorMovements() ) + pEditEngine->pImpEditEngine->aStatus.GetPrevParagraph() = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( GetEditSelection().Max().GetNode() ); + nTravelXPos = TRAVEL_X_DONTKNOW; + nExtraCursorFlags = 0; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + bClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); + return pEditEngine->pImpEditEngine->MouseButtonDown( rMouseEvent, GetEditViewPtr() ); +} + +sal_Bool ImpEditView::MouseMove( const MouseEvent& rMouseEvent ) +{ + return pEditEngine->pImpEditEngine->MouseMove( rMouseEvent, GetEditViewPtr() ); +} + +void ImpEditView::Command( const CommandEvent& rCEvt ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + pEditEngine->pImpEditEngine->Command( rCEvt, GetEditViewPtr() ); +} + + +void ImpEditView::SetInsertMode( sal_Bool bInsert ) +{ + if ( bInsert != IsInsertMode() ) + { + SetFlags( nControl, EV_CNTRL_OVERWRITE, !bInsert ); + ShowCursor( DoAutoScroll(), sal_False ); + } +} + +sal_Bool ImpEditView::IsWrongSpelledWord( const EditPaM& rPaM, sal_Bool bMarkIfWrong ) +{ + sal_Bool bIsWrong = sal_False; +#ifndef SVX_LIGHT + if ( rPaM.GetNode()->GetWrongList() ) + { + EditSelection aSel = pEditEngine->pImpEditEngine->SelectWord( rPaM, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + bIsWrong = rPaM.GetNode()->GetWrongList()->HasWrong( aSel.Min().GetIndex(), aSel.Max().GetIndex() ); + if ( bIsWrong && bMarkIfWrong ) + { + DrawSelection(); // alte Selektion 'weg-zeichnen' + SetEditSelection( aSel ); + DrawSelection(); + } + } +#endif // !SVX_LIGHT + return bIsWrong; +} + +String ImpEditView::SpellIgnoreOrAddWord( sal_Bool bAdd ) +{ + String aWord; +#ifndef SVX_LIGHT + if ( pEditEngine->pImpEditEngine->GetSpeller().is() ) + { + EditPaM aPaM = GetEditSelection().Max(); + if ( !HasSelection() ) + { + EditSelection aSel = pEditEngine->pImpEditEngine->SelectWord( aPaM ); + aWord = pEditEngine->pImpEditEngine->GetSelected( aSel ); + } + else + { + aWord = pEditEngine->pImpEditEngine->GetSelected( GetEditSelection() ); + // Und deselektieren + DrawSelection(); // alte Selektion 'weg-zeichnen' + SetEditSelection( EditSelection( aPaM, aPaM ) ); + DrawSelection(); + } + + if ( aWord.Len() ) + { + if ( bAdd ) + { + DBG_ERROR( "Sorry, AddWord not implemented" ); + } + else // Ignore + { + Reference< XDictionary > xDic( SvxGetIgnoreAllList(), UNO_QUERY ); + if (xDic.is()) + xDic->add( aWord, sal_False, String() ); + } + const EditDoc& rDoc = pEditEngine->pImpEditEngine->GetEditDoc(); + sal_uInt16 nNodes = rDoc.Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = rDoc.GetObject( n ); + pNode->GetWrongList()->MarkWrongsInvalid(); + } + pEditEngine->pImpEditEngine->DoOnlineSpelling( aPaM.GetNode() ); + pEditEngine->pImpEditEngine->StartOnlineSpellTimer(); + } + } +#endif // !SVX_LIGHT + return aWord; +} + +void ImpEditView::DeleteSelected() +{ + DrawSelection(); + + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DELETE ); + + EditPaM aPaM = pEditEngine->pImpEditEngine->DeleteSelected( GetEditSelection() ); + + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_DELETE ); + + SetEditSelection( EditSelection( aPaM, aPaM ) ); + pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() ); + ShowCursor( DoAutoScroll(), TRUE ); +} + +const SvxFieldItem* ImpEditView::GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const +{ + if( !GetOutputArea().IsInside( rPos ) ) + return 0; + + Point aDocPos( GetDocPos( rPos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, sal_False ); + + if ( aPaM.GetIndex() == aPaM.GetNode()->Len() ) + { + // Sonst immer, wenn Feld ganz am Schluss und Mouse unter Text + return 0; + } + + const CharAttribArray& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs(); + sal_uInt16 nXPos = aPaM.GetIndex(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->GetStart() == nXPos ) + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + if ( pPara ) + *pPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aPaM.GetNode() ); + if ( pPos ) + *pPos = pAttr->GetStart(); + return (const SvxFieldItem*)pAttr->GetItem(); + } + } + return NULL; +} + +BOOL ImpEditView::IsBulletArea( const Point& rPos, sal_uInt16* pPara ) +{ + if ( pPara ) + *pPara = 0xFFFF; + + if( !GetOutputArea().IsInside( rPos ) ) + return FALSE; + + Point aDocPos( GetDocPos( rPos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, sal_False ); + + if ( aPaM.GetIndex() == 0 ) + { + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + Rectangle aBulletArea = pEditEngine->GetBulletArea( nPara ); + long nY = pEditEngine->GetDocPosTopLeft( nPara ).Y(); + ParaPortion* pParaPortion = pEditEngine->pImpEditEngine->GetParaPortions().GetObject( nPara ); + nY += pParaPortion->GetFirstLineOffset(); + if ( ( aDocPos.Y() > ( nY + aBulletArea.Top() ) ) && + ( aDocPos.Y() < ( nY + aBulletArea.Bottom() ) ) && + ( aDocPos.X() > ( aBulletArea.Left() ) ) && + ( aDocPos.X() < ( aBulletArea.Right() ) ) ) + { + if ( pPara ) + *pPara = nPara; + return TRUE; + } + } + + return FALSE; +} + +void ImpEditView::CutCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, BOOL bCut ) +{ + if ( rxClipboard.is() && GetEditSelection().HasRange() ) + { + uno::Reference< datatransfer::XTransferable > xData = pEditEngine->pImpEditEngine->CreateTransferable( GetEditSelection() ); + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + rxClipboard->setContents( xData, NULL ); + + // #87756# FlushClipboard, but it would be better to become a TerminateListener to the Desktop and flush on demand... + uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY ); + if( xFlushableClipboard.is() ) + xFlushableClipboard->flushClipboard(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + + if ( bCut ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_CUT ); + DeleteSelected(); + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_CUT ); + + } + } +} + +void ImpEditView::Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, BOOL bUseSpecial ) +{ + if ( rxClipboard.is() ) + { + uno::Reference< datatransfer::XTransferable > xDataObj; + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + xDataObj = rxClipboard->getContents(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + + if ( xDataObj.is() && EditEngine::HasValidData( xDataObj ) ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE ); + + EditSelection aSel( GetEditSelection() ); + if ( aSel.HasRange() ) + { + DrawSelection(); + aSel = pEditEngine->pImpEditEngine->ImpDeleteSelection( aSel ); + } + + PasteOrDropInfos aPasteOrDropInfos; + aPasteOrDropInfos.nAction = EE_ACTION_PASTE; + aPasteOrDropInfos.nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() ); + pEditEngine->pImpEditEngine->aBeginPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + if ( DoSingleLinePaste() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( xDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = xDataObj->getTransferData( aFlavor ); + ::rtl::OUString aTmpText; + aData >>= aTmpText; + String aText( aTmpText ); + aText.ConvertLineEnd( LINEEND_LF ); + aText.SearchAndReplaceAll( LINE_SEP, ' ' ); + aSel = pEditEngine->pImpEditEngine->ImpInsertText( aSel, aText ); + } + catch( ... ) + { + ; // #i9286# can happen, even if isDataFlavorSupported returns true... + } + } + } + else + { + aSel = pEditEngine->pImpEditEngine->InsertText( xDataObj, String(), aSel.Min(), bUseSpecial && pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + } + + aPasteOrDropInfos.nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() ); + pEditEngine->pImpEditEngine->aEndPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_PASTE ); + SetEditSelection( aSel ); + pEditEngine->pImpEditEngine->UpdateSelections(); + pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() ); + ShowCursor( DoAutoScroll(), TRUE ); + } + } +} + + +BOOL ImpEditView::IsInSelection( const EditPaM& rPaM ) +{ + EditSelection aSel = GetEditSelection(); + if ( !aSel.HasRange() ) + return FALSE; + + aSel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + USHORT nStartNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() ); + USHORT nCurNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( rPaM.GetNode() ); + + if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) + return TRUE; + + if ( nStartNode == nEndNode ) + { + if ( nCurNode == nStartNode ) + if ( ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) ) + return TRUE; + } + else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) ) + return TRUE; + else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) ) + return TRUE; + + return FALSE; +} + +void ImpEditView::CreateAnchor() +{ + pEditEngine->pImpEditEngine->bInSelection = TRUE; + GetEditSelection().Min() = GetEditSelection().Max(); +} + +void ImpEditView::DeselectAll() +{ + pEditEngine->pImpEditEngine->bInSelection = FALSE; + DrawSelection(); + GetEditSelection().Min() = GetEditSelection().Max(); +} + +BOOL ImpEditView::IsSelectionAtPoint( const Point& rPosPixel ) +{ + if ( pDragAndDropInfo && pDragAndDropInfo->pField ) + return TRUE; + + Point aMousePos( rPosPixel ); + + // Logische Einheiten... + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() ) + { + return FALSE; + } + + Point aDocPos( GetDocPos( aMousePos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, FALSE ); + return IsInSelection( aPaM ); +} + +BOOL ImpEditView::SetCursorAtPoint( const Point& rPointPixel ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); + + Point aMousePos( rPointPixel ); + + // Logische Einheiten... + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() ) + { + return FALSE; + } + + Point aDocPos( GetDocPos( aMousePos ) ); + + // Kann optimiert werden: Erst innerhalb eines Absatzes die Zeilen + // fuer den PaM durchwuehlen, dann nochmal mit dem PaM fuer das Rect, + // obwohl die Zeile schon bekannt ist.... + // Das muss doch nicht sein ! + + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos ); + BOOL bGotoCursor = DoAutoScroll(); + + // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion + EditSelection aTmpNewSel( GetEditSelection().Max(), aPaM ); + + // --> OD 2005-12-16 #i27299# + // work on copy of current selection and set new selection, if it has changed. + EditSelection aNewEditSelection( GetEditSelection() ); + + aNewEditSelection.Max() = aPaM; + if ( !pEditEngine->pImpEditEngine->aSelEngine.HasAnchor() ) + { + if ( aNewEditSelection.Min() != aPaM ) + pEditEngine->pImpEditEngine->CursorMoved( aNewEditSelection.Min().GetNode() ); + aNewEditSelection.Min() = aPaM; + } + else + { + DrawSelection( aTmpNewSel ); + } + + // set changed text selection + if ( GetEditSelection() != aNewEditSelection ) + { + SetEditSelection( aNewEditSelection ); + } + // <-- + + BOOL bForceCursor = ( pDragAndDropInfo ? FALSE : TRUE ) && !pEditEngine->pImpEditEngine->IsInSelectionMode(); + ShowCursor( bGotoCursor, bForceCursor ); + return TRUE; +} + + +void ImpEditView::HideDDCursor() +{ + if ( pDragAndDropInfo && pDragAndDropInfo->bVisCursor ) + { + GetWindow()->DrawOutDev( pDragAndDropInfo->aCurSavedCursor.TopLeft(), pDragAndDropInfo->aCurSavedCursor.GetSize(), + Point(0,0), pDragAndDropInfo->aCurSavedCursor.GetSize(),*pDragAndDropInfo->pBackground ); + pDragAndDropInfo->bVisCursor = sal_False; + } +} + +void ImpEditView::ShowDDCursor( const Rectangle& rRect ) +{ + if ( !pDragAndDropInfo->bVisCursor ) + { + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Hide(); + + Color aOldFillColor = GetWindow()->GetFillColor(); + GetWindow()->SetFillColor( Color(4210752) ); // GRAY BRUSH_50, OLDSV, change to DDCursor! + + // Hintergrund sichern... + Rectangle aSaveRec( GetWindow()->LogicToPixel( rRect ) ); + // lieber etwas mehr sichern... + aSaveRec.Right() += 1; + aSaveRec.Bottom() += 1; + + Size aNewSzPx( aSaveRec.GetSize() ); + if ( !pDragAndDropInfo->pBackground ) + { + pDragAndDropInfo->pBackground = new VirtualDevice( *GetWindow() ); + MapMode aMapMode( GetWindow()->GetMapMode() ); + aMapMode.SetOrigin( Point( 0, 0 ) ); + pDragAndDropInfo->pBackground->SetMapMode( aMapMode ); + + } + +#ifdef DBG_UTIL + Size aCurSzPx( pDragAndDropInfo->pBackground->GetOutputSizePixel() ); + if ( ( aCurSzPx.Width() < aNewSzPx.Width() ) ||( aCurSzPx.Height() < aNewSzPx.Height() ) ) + { + sal_Bool bDone = pDragAndDropInfo->pBackground->SetOutputSizePixel( aNewSzPx ); + DBG_ASSERT( bDone, "Virtuelles Device kaputt?" ); + } +#endif + + aSaveRec = GetWindow()->PixelToLogic( aSaveRec ); + + pDragAndDropInfo->pBackground->DrawOutDev( Point(0,0), aSaveRec.GetSize(), + aSaveRec.TopLeft(), aSaveRec.GetSize(), *GetWindow() ); + pDragAndDropInfo->aCurSavedCursor = aSaveRec; + + // Cursor malen... + GetWindow()->DrawRect( rRect ); + + pDragAndDropInfo->bVisCursor = sal_True; + pDragAndDropInfo->aCurCursor = rRect; + + GetWindow()->SetFillColor( aOldFillColor ); + } +} + +void ImpEditView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException) +{ + DBG_ASSERT( !pDragAndDropInfo, "dragGestureRecognized - DragAndDropInfo exist!" ); + + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + Point aMousePosPixel( rDGE.DragOriginX, rDGE.DragOriginY ); + + EditSelection aCopySel( GetEditSelection() ); + aCopySel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + if ( GetEditSelection().HasRange() && bClickedInSelection ) + { + pDragAndDropInfo = new DragAndDropInfo(); + } + else + { + // Field?! + USHORT nPara, nPos; + Point aMousePos = GetWindow()->PixelToLogic( aMousePosPixel ); + const SvxFieldItem* pField = GetField( aMousePos, &nPara, &nPos ); + if ( pField ) + { + pDragAndDropInfo = new DragAndDropInfo(); + pDragAndDropInfo->pField = pField; + ContentNode* pNode = pEditEngine->pImpEditEngine->GetEditDoc().GetObject( nPara ); + aCopySel = EditSelection( EditPaM( pNode, nPos ), EditPaM( pNode, nPos+1 ) ); + GetEditSelection() = aCopySel; + DrawSelection(); + BOOL bGotoCursor = DoAutoScroll(); + BOOL bForceCursor = ( pDragAndDropInfo ? FALSE : TRUE ) && !pEditEngine->pImpEditEngine->IsInSelectionMode(); + ShowCursor( bGotoCursor, bForceCursor ); + } + else if ( IsBulletArea( aMousePos, &nPara ) ) + { + pDragAndDropInfo = new DragAndDropInfo(); + pDragAndDropInfo->bOutlinerMode = TRUE; + EditPaM aStartPaM( pEditEngine->pImpEditEngine->GetEditDoc().GetObject( nPara ), 0 ); + EditPaM aEndPaM( aStartPaM ); + const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); + for ( USHORT n = nPara +1; n < pEditEngine->pImpEditEngine->GetEditDoc().Count(); n++ ) + { + const SfxInt16Item& rL = (const SfxInt16Item&) pEditEngine->GetParaAttrib( n, EE_PARA_OUTLLEVEL ); + if ( rL.GetValue() > rLevel.GetValue() ) + { + aEndPaM.SetNode( pEditEngine->pImpEditEngine->GetEditDoc().GetObject( n ) ); + } + else + { + break; + } + } + aEndPaM.GetIndex() = aEndPaM.GetNode()->Len(); + SetEditSelection( EditSelection( aStartPaM, aEndPaM ) ); + } + } + + if ( pDragAndDropInfo ) + { + + pDragAndDropInfo->bStarterOfDD = sal_True; + + // Sensibler Bereich, wo gescrollt werden soll. + Size aSz( 5, 0 ); + aSz = GetWindow()->PixelToLogic( aSz ); + pDragAndDropInfo->nSensibleRange = (sal_uInt16) aSz.Width(); + pDragAndDropInfo->nCursorWidth = (sal_uInt16) aSz.Width() / 2; + pDragAndDropInfo->aBeginDragSel = pEditEngine->pImpEditEngine->CreateESel( aCopySel ); + + uno::Reference< datatransfer::XTransferable > xData = pEditEngine->pImpEditEngine->CreateTransferable( aCopySel ); + + sal_Int8 nActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE; + + rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, xData, mxDnDListener ); + // Falls Drag&Move in einer Engine, muessen Copy&Del geklammert sein! + GetCursor()->Hide(); + + } +} + +void ImpEditView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + DBG_ASSERT( pDragAndDropInfo, "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!" ); + + // #123688# Shouldn't happen, but seems to happen... + if ( pDragAndDropInfo ) + { + if ( !bReadOnly && rDSDE.DropSuccess && !pDragAndDropInfo->bOutlinerMode && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) ) + { + if ( pDragAndDropInfo->bStarterOfDD && pDragAndDropInfo->bDroppedInMe ) + { + // DropPos: Wohin wurde gedroppt, unabhaengig von laenge. + ESelection aDropPos( pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos, pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos ); + ESelection aToBeDelSel = pDragAndDropInfo->aBeginDragSel; + ESelection aNewSel( pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos, + pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos ); + sal_Bool bBeforeSelection = aDropPos.IsLess( pDragAndDropInfo->aBeginDragSel ); + sal_uInt16 nParaDiff = pDragAndDropInfo->aBeginDragSel.nEndPara - pDragAndDropInfo->aBeginDragSel.nStartPara; + if ( bBeforeSelection ) + { + // aToBeDelSel anpassen. + DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara, "Doch nicht davor?" ); + aToBeDelSel.nStartPara = aToBeDelSel.nStartPara + nParaDiff; + aToBeDelSel.nEndPara = aToBeDelSel.nEndPara + nParaDiff; + // Zeichen korrigieren? + if ( aToBeDelSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara ) + { + sal_uInt16 nMoreChars; + if ( pDragAndDropInfo->aDropSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara ) + nMoreChars = pDragAndDropInfo->aDropSel.nEndPos - pDragAndDropInfo->aDropSel.nStartPos; + else + nMoreChars = pDragAndDropInfo->aDropSel.nEndPos; + aToBeDelSel.nStartPos = + aToBeDelSel.nStartPos + nMoreChars; + if ( aToBeDelSel.nStartPara == aToBeDelSel.nEndPara ) + aToBeDelSel.nEndPos = + aToBeDelSel.nEndPos + nMoreChars; + } + } + else + { + // aToBeDelSel ist ok, aber Selektion der View + // muss angepasst werden, wenn davor geloescht wird! + DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara, "Doch nicht davor?" ); + aNewSel.nStartPara = aNewSel.nStartPara - nParaDiff; + aNewSel.nEndPara = aNewSel.nEndPara - nParaDiff; + // Zeichen korrigieren? + if ( pDragAndDropInfo->aBeginDragSel.nEndPara == pDragAndDropInfo->aDropSel.nStartPara ) + { + sal_uInt16 nLessChars; + if ( pDragAndDropInfo->aBeginDragSel.nStartPara == pDragAndDropInfo->aBeginDragSel.nEndPara ) + nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos - pDragAndDropInfo->aBeginDragSel.nStartPos; + else + nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos; + aNewSel.nStartPos = aNewSel.nStartPos - nLessChars; + if ( aNewSel.nStartPara == aNewSel.nEndPara ) + aNewSel.nEndPos = aNewSel.nEndPos - nLessChars; + } + } + + DrawSelection(); + EditSelection aDelSel( pEditEngine->pImpEditEngine->CreateSel( aToBeDelSel ) ); + DBG_ASSERT( !aDelSel.DbgIsBuggy( pEditEngine->pImpEditEngine->aEditDoc ), "ToBeDel ist buggy!" ); + pEditEngine->pImpEditEngine->ImpDeleteSelection( aDelSel ); + if ( !bBeforeSelection ) + { + DBG_ASSERT( !pEditEngine->pImpEditEngine->CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->pImpEditEngine->aEditDoc), "Bad" ); + SetEditSelection( pEditEngine->pImpEditEngine->CreateSel( aNewSel ) ); + } + pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() ); + DrawSelection(); + } + else + { + // andere EditEngine... + if ( pEditEngine->pImpEditEngine->ImplHasText() ) // #88630# SC ist removing the content when switching the task + DeleteSelected(); + } + } + + if ( pDragAndDropInfo->bUndoAction ) + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_DRAGANDDROP ); + + HideDDCursor(); + ShowCursor( DoAutoScroll(), TRUE ); + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + pEditEngine->GetEndDropHdl().Call(GetEditViewPtr()); + } +} + +void ImpEditView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + DBG_ASSERT( pDragAndDropInfo, "Drop - No Drag&Drop info?!" ); + + if ( pDragAndDropInfo->bDragAccepted ) + { + pEditEngine->GetBeginDropHdl().Call(GetEditViewPtr()); + BOOL bChanges = FALSE; + + HideDDCursor(); + + if ( pDragAndDropInfo->bStarterOfDD ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DRAGANDDROP ); + pDragAndDropInfo->bUndoAction = TRUE; + } + + if ( pDragAndDropInfo->bOutlinerMode ) + { + bChanges = TRUE; + GetEditViewPtr()->MoveParagraphs( Range( pDragAndDropInfo->aBeginDragSel.nStartPara, pDragAndDropInfo->aBeginDragSel.nEndPara ), pDragAndDropInfo->nOutlinerDropDest ); + } + else + { + uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; + if ( xDataObj.is() ) + { + bChanges = TRUE; + // Selektion wegmalen... + DrawSelection(); + EditPaM aPaM( pDragAndDropInfo->aDropDest ); + + PasteOrDropInfos aPasteOrDropInfos; + aPasteOrDropInfos.nAction = EE_ACTION_DROP; + aPasteOrDropInfos.nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aPaM.GetNode() ); + pEditEngine->pImpEditEngine->aBeginPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + EditSelection aNewSel = pEditEngine->pImpEditEngine->InsertText( xDataObj, String(), aPaM, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + + aPasteOrDropInfos.nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() ); + pEditEngine->pImpEditEngine->aEndPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + SetEditSelection( aNewSel ); + pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() ); + if ( pDragAndDropInfo->bStarterOfDD ) + { + // Nur dann setzen, wenn in gleicher Engine! + pDragAndDropInfo->aDropSel.nStartPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + pDragAndDropInfo->aDropSel.nStartPos = aPaM.GetIndex(); + pDragAndDropInfo->aDropSel.nEndPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aNewSel.Max().GetNode() ); + pDragAndDropInfo->aDropSel.nEndPos = aNewSel.Max().GetIndex(); + pDragAndDropInfo->bDroppedInMe = sal_True; + } + } + } + + if ( bChanges ) + { + rDTDE.Context->acceptDrop( rDTDE.DropAction ); + } + + if ( !pDragAndDropInfo->bStarterOfDD ) + { + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + } + + rDTDE.Context->dropComplete( bChanges ); + } +} + +void ImpEditView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + if ( !pDragAndDropInfo ) + pDragAndDropInfo = new DragAndDropInfo( ); + + pDragAndDropInfo->bHasValidData = sal_False; + + // Check for supported format... + // Only check for text, will also be there if bin or rtf + datatransfer::DataFlavor aTextFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aTextFlavor ); + const ::com::sun::star::datatransfer::DataFlavor* pFlavors = rDTDEE.SupportedDataFlavors.getConstArray(); + int nFlavors = rDTDEE.SupportedDataFlavors.getLength(); + for ( int n = 0; n < nFlavors; n++ ) + { + if( TransferableDataHelper::IsEqual( pFlavors[n], aTextFlavor ) ) + { + pDragAndDropInfo->bHasValidData = sal_True; + break; + } + } + + dragOver( rDTDEE ); +} + +void ImpEditView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + HideDDCursor(); + + if ( !pDragAndDropInfo->bStarterOfDD ) + { + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + } +} + +void ImpEditView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + sal_Bool bAccept = sal_False; + + if ( GetOutputArea().IsInside( aMousePos ) && !bReadOnly ) + { +// sal_Int8 nSupportedActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE; + + if ( pDragAndDropInfo->bHasValidData /* && ( nSupportedActions & rDTDE.DropAction ) MT: Default = 0x80 ?! */ ) + { + bAccept = sal_True; + + sal_Bool bAllowScroll = DoAutoScroll(); + if ( bAllowScroll ) + { + long nScrollX = 0; + long nScrollY = 0; + // pruefen, ob im sensitiven Bereich + if ( ( (aMousePos.X()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Left() ) && ( ( aMousePos.X() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Left() ) ) + nScrollX = GetOutputArea().GetWidth() / SCRLRANGE; + else if ( ( (aMousePos.X()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Right() ) && ( ( aMousePos.X() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Right() ) ) + nScrollX = -( GetOutputArea().GetWidth() / SCRLRANGE ); + + if ( ( (aMousePos.Y()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Top() ) && ( ( aMousePos.Y() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Top() ) ) + nScrollY = GetOutputArea().GetHeight() / SCRLRANGE; + else if ( ( (aMousePos.Y()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Bottom() ) && ( ( aMousePos.Y() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Bottom() ) ) + nScrollY = -( GetOutputArea().GetHeight() / SCRLRANGE ); + + if ( nScrollX || nScrollY ) + { + HideDDCursor(); + Scroll( nScrollX, nScrollY, RGCHK_PAPERSZ1 ); + } + } + + Point aDocPos( GetDocPos( aMousePos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos ); + pDragAndDropInfo->aDropDest = aPaM; + if ( pDragAndDropInfo->bOutlinerMode ) + { + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + ParaPortion* pPPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + long nDestParaStartY = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + long nRel = aDocPos.Y() - nDestParaStartY; + if ( nRel < ( pPPortion->GetHeight() / 2 ) ) + { + pDragAndDropInfo->nOutlinerDropDest = nPara; + } + else + { + pDragAndDropInfo->nOutlinerDropDest = nPara+1; + } + + if( ( pDragAndDropInfo->nOutlinerDropDest >= pDragAndDropInfo->aBeginDragSel.nStartPara ) && + ( pDragAndDropInfo->nOutlinerDropDest <= (pDragAndDropInfo->aBeginDragSel.nEndPara+1) ) ) + { + bAccept = FALSE; + } + } + else if ( HasSelection() ) + { + // es darf nicht in eine Selektion gedroppt werden + EPaM aP = pEditEngine->pImpEditEngine->CreateEPaM( aPaM ); + ESelection aDestSel( aP.nPara, aP.nIndex, aP.nPara, aP.nIndex); + ESelection aCurSel = pEditEngine->pImpEditEngine->CreateESel( GetEditSelection() ); + aCurSel.Adjust(); + if ( !aDestSel.IsLess( aCurSel ) && !aDestSel.IsGreater( aCurSel ) ) + { + bAccept = FALSE; + } + } + if ( bAccept ) + { + Rectangle aEditCursor; + if ( pDragAndDropInfo->bOutlinerMode ) + { + long nDDYPos; + if ( pDragAndDropInfo->nOutlinerDropDest < pEditEngine->pImpEditEngine->GetEditDoc().Count() ) + { + ParaPortion* pPPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( pDragAndDropInfo->nOutlinerDropDest ); + nDDYPos = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + } + else + { + nDDYPos = pEditEngine->pImpEditEngine->GetTextHeight(); + } + Point aStartPos( 0, nDDYPos ); + aStartPos = GetWindowPos( aStartPos ); + Point aEndPos( GetOutputArea().GetWidth(), nDDYPos ); + aEndPos = GetWindowPos( aEndPos ); + aEditCursor = GetWindow()->LogicToPixel( Rectangle( aStartPos, aEndPos ) ); + if ( !pEditEngine->IsVertical() ) + { + aEditCursor.Top()--; + aEditCursor.Bottom()++; + } + else + { + aEditCursor.Left()--; + aEditCursor.Right()++; + } + aEditCursor = GetWindow()->PixelToLogic( aEditCursor ); + } + else + { + aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM ); + Point aTopLeft( GetWindowPos( aEditCursor.TopLeft() ) ); + aEditCursor.SetPos( aTopLeft ); + aEditCursor.Right() = aEditCursor.Left() + pDragAndDropInfo->nCursorWidth; + aEditCursor = GetWindow()->LogicToPixel( aEditCursor ); + aEditCursor = GetWindow()->PixelToLogic( aEditCursor ); + } + + sal_Bool bCursorChanged = !pDragAndDropInfo->bVisCursor || ( pDragAndDropInfo->aCurCursor != aEditCursor ); + if ( bCursorChanged ) + { + HideDDCursor(); + ShowDDCursor(aEditCursor ); + } + pDragAndDropInfo->bDragAccepted = TRUE; + rDTDE.Context->acceptDrag( rDTDE.DropAction ); + } + } + } + + if ( !bAccept ) + { + HideDDCursor(); + pDragAndDropInfo->bDragAccepted = FALSE; + rDTDE.Context->rejectDrag(); + } +} + +void ImpEditView::AddDragAndDropListeners() +{ + Window* pWindow = GetWindow(); + if ( !bActiveDragAndDropListener && pWindow && pWindow->GetDragGestureRecognizer().is() ) + { + vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); + mxDnDListener = pDnDWrapper; + + uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY ); + pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); + uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); + pWindow->GetDropTarget()->addDropTargetListener( xDTL ); + pWindow->GetDropTarget()->setActive( sal_True ); + pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); + + bActiveDragAndDropListener = TRUE; + } +} + +void ImpEditView::RemoveDragAndDropListeners() +{ + if ( bActiveDragAndDropListener && GetWindow() && GetWindow()->GetDragGestureRecognizer().is() ) + { + uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY ); + GetWindow()->GetDragGestureRecognizer()->removeDragGestureListener( xDGL ); + uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); + GetWindow()->GetDropTarget()->removeDropTargetListener( xDTL ); + + if ( mxDnDListener.is() ) + { + uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY ); + xEL->disposing( lang::EventObject() ); // #95154# Empty Source means it's the Client + mxDnDListener.clear(); + } + + bActiveDragAndDropListener = FALSE; + } +} diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx new file mode 100644 index 000000000000..3bacfc949e3b --- /dev/null +++ b/editeng/source/editeng/impedit.hxx @@ -0,0 +1,1208 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _IMPEDIT_HXX +#define _IMPEDIT_HXX + +#include <editdoc.hxx> +#include <editsel.hxx> +#include <editundo.hxx> +#include <editobj2.hxx> +#include <editstt2.hxx> +#include <editeng/editdata.hxx> +#include <editeng/svxacorr.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/cursor.hxx> + +#include <vcl/dndhelp.hxx> +#include <svl/ondemand.hxx> +#include <com/sun/star/linguistic2/XSpellAlternatives.hpp> +#include <com/sun/star/linguistic2/SpellFailure.hpp> +#include <com/sun/star/linguistic2/XSpellChecker.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> +#include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp> + +#include <i18npool/lang.h> +#include <vos/ref.hxx> + +DBG_NAMEEX( EditView ) +DBG_NAMEEX( EditEngine ) + +#define PIMPEE pImpEditView->pEditEngine->pImpEditEngine + +#define DEL_LEFT 1 +#define DEL_RIGHT 2 +#define TRAVEL_X_DONTKNOW 0xFFFFFFFF +#define CURSOR_BIDILEVEL_DONTKNOW 0xFFFF +#define MAXCHARSINPARA 0x3FFF-CHARPOSGROW // Max 16K, because WYSIWYG array + +#define ATTRSPECIAL_WHOLEWORD 1 +#define ATTRSPECIAL_EDGE 2 + +#define GETCRSR_TXTONLY 0x0001 +#define GETCRSR_STARTOFLINE 0x0002 +#define GETCRSR_ENDOFLINE 0x0004 +#define GETCRSR_PREFERPORTIONSTART 0x0008 + +#define LINE_SEP 0x0A + +typedef EENotify* EENotifyPtr; +SV_DECL_PTRARR_DEL( NotifyList, EENotifyPtr, 1, 1 ) // IMPL is in outliner.cxx, move to EE later and share declaration, or use BlockNotifications from EE directly + + +class EditView; +class EditEngine; +class SvxFontTable; +class SvxColorList; + +class SvxSearchItem; +class SvxLRSpaceItem; +class TextRanger; +class SvKeyValueIterator; +class SvxForbiddenCharactersTable; +class SvtCTLOptions; +#include <editeng/SpellPortions.hxx> + +#include <editeng/eedata.hxx> + +class SvUShorts; +class SvxNumberFormat; + + +namespace com { +namespace sun { +namespace star { +namespace datatransfer { +namespace clipboard { + class XClipboard; +}}}}} + +namespace svtools { + class ColorConfig; +} + +struct DragAndDropInfo +{ + Rectangle aCurCursor; + Rectangle aCurSavedCursor; + sal_uInt16 nSensibleRange; + sal_uInt16 nCursorWidth; + ESelection aBeginDragSel; + EditPaM aDropDest; + USHORT nOutlinerDropDest; + ESelection aDropSel; + VirtualDevice* pBackground; + const SvxFieldItem* pField; + sal_Bool bVisCursor : 1; + sal_Bool bDroppedInMe : 1; + sal_Bool bStarterOfDD : 1; + sal_Bool bHasValidData : 1; + sal_Bool bUndoAction : 1; + sal_Bool bOutlinerMode : 1; + sal_Bool bDragAccepted : 1; + + DragAndDropInfo() + { + pBackground = NULL; bVisCursor = sal_False; bDroppedInMe = sal_False; bStarterOfDD = sal_False; + bHasValidData = sal_False; bUndoAction = sal_False; bOutlinerMode = sal_False; + nSensibleRange = 0; nCursorWidth = 0; pField = 0; nOutlinerDropDest = 0; bDragAccepted = sal_False; + } +}; + +struct ImplIMEInfos +{ + String aOldTextAfterStartPos; + sal_uInt16* pAttribs; + EditPaM aPos; + sal_uInt16 nLen; + sal_Bool bCursor; + sal_Bool bWasCursorOverwrite; + + ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos ); + ~ImplIMEInfos(); + + void CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ); + void DestroyAttribs(); +}; + +// #i18881# to be able to identify the postions of changed words +// the positions of each portion need to be saved +typedef std::vector<EditSelection> SpellContentSelections; + +struct SpellInfo +{ + EESpellState eState; + EPaM aSpellStart; + EPaM aSpellTo; + sal_Bool bSpellToEnd; + sal_Bool bMultipleDoc; + ::svx::SpellPortions aLastSpellPortions; + SpellContentSelections aLastSpellContentSelections; + SpellInfo() + { bSpellToEnd = sal_True; eState = EE_SPELL_OK; bMultipleDoc = sal_False; } +}; + +// used for text conversion +struct ConvInfo +{ + EPaM aConvStart; + EPaM aConvTo; + EPaM aConvContinue; // position to start search for next text portion (word) with + sal_Bool bConvToEnd; + sal_Bool bMultipleDoc; + + ConvInfo() { bConvToEnd = sal_True; bMultipleDoc = sal_False; } +}; + +struct FormatterFontMetric +{ + sal_uInt16 nMaxAscent; + sal_uInt16 nMaxDescent; + + FormatterFontMetric() { nMaxAscent = 0; nMaxDescent = 0; /* nMinLeading = 0xFFFF; */ } + sal_uInt16 GetHeight() const { return nMaxAscent+nMaxDescent; } +}; + +class IdleFormattter : public Timer +{ +private: + EditView* pView; + int nRestarts; + +public: + IdleFormattter(); + ~IdleFormattter(); + + void DoIdleFormat( EditView* pV ); + void ForceTimeout(); + void ResetRestarts() { nRestarts = 0; } + EditView* GetView() { return pView; } +}; + +// ---------------------------------------------------------------------- +// class ImpEditView +// ---------------------------------------------------------------------- +class ImpEditView : public vcl::unohelper::DragAndDropClient +{ + friend class EditView; + friend class EditEngine; + friend class ImpEditEngine; + using vcl::unohelper::DragAndDropClient::dragEnter; + using vcl::unohelper::DragAndDropClient::dragExit; + using vcl::unohelper::DragAndDropClient::dragOver; + +private: + EditView* pEditView; + Cursor* pCursor; + Color* pBackgroundColor; + EditEngine* pEditEngine; + Window* pOutWin; + Pointer* pPointer; + DragAndDropInfo* pDragAndDropInfo; + + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener; + + + long nInvMore; + ULONG nControl; + sal_uInt32 nTravelXPos; + sal_uInt16 nExtraCursorFlags; + sal_uInt16 nCursorBidiLevel; + sal_uInt16 nScrollDiffX; + sal_Bool bReadOnly; + sal_Bool bClickedInSelection; + sal_Bool bActiveDragAndDropListener; + + Point aAnchorPoint; + Rectangle aOutArea; + Point aVisDocStartPos; + EESelectionMode eSelectionMode; + EditSelection aEditSelection; + EVAnchorMode eAnchorMode; + +protected: + + // DragAndDropClient + void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException); + void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException); + void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException); + void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException); + void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + + void ShowDDCursor( const Rectangle& rRect ); + void HideDDCursor(); + + void ImplDrawHighlightRect( Window* pOutWin, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, PolyPolygon* pPolyPoly ); + +public: + ImpEditView( EditView* pView, EditEngine* pEng, Window* pWindow ); + ~ImpEditView(); + + EditView* GetEditViewPtr() { return pEditView; } + + sal_uInt16 GetScrollDiffX() const { return nScrollDiffX; } + void SetScrollDiffX( sal_uInt16 n ) { nScrollDiffX = n; } + + sal_uInt16 GetCursorBidiLevel() const { return nCursorBidiLevel; } + void SetCursorBidiLevel( sal_uInt16 n ) { nCursorBidiLevel = n; } + + Point GetDocPos( const Point& rWindowPos ) const; + Point GetWindowPos( const Point& rDocPos ) const; + Rectangle GetWindowPos( const Rectangle& rDocPos ) const; + + void SetOutputArea( const Rectangle& rRec ); + void ResetOutputArea( const Rectangle& rRec ); + const Rectangle& GetOutputArea() const { return aOutArea; } + + BOOL IsVertical() const; + + BOOL PostKeyEvent( const KeyEvent& rKeyEvent ); + + BOOL MouseButtonUp( const MouseEvent& rMouseEvent ); + BOOL MouseButtonDown( const MouseEvent& rMouseEvent ); + BOOL MouseMove( const MouseEvent& rMouseEvent ); + void Command( const CommandEvent& rCEvt ); + + void CutCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, sal_Bool bCut ); + void Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, sal_Bool bUseSpecial = sal_False ); + + void SetVisDocStartPos( const Point& rPos ) { aVisDocStartPos = rPos; } + const Point& GetVisDocStartPos() const { return aVisDocStartPos; } + + long GetVisDocLeft() const { return aVisDocStartPos.X(); } + long GetVisDocTop() const { return aVisDocStartPos.Y(); } + long GetVisDocRight() const { return aVisDocStartPos.X() + ( !IsVertical() ? aOutArea.GetWidth() : aOutArea.GetHeight() ); } + long GetVisDocBottom() const { return aVisDocStartPos.Y() + ( !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth() ); } + Rectangle GetVisDocArea() const; + + EditSelection& GetEditSelection() { return aEditSelection; } + void SetEditSelection( const EditSelection& rEditSelection ); + sal_Bool HasSelection() const { return aEditSelection.HasRange(); } + + void DrawSelection() { DrawSelection( aEditSelection ); } + void DrawSelection( EditSelection, Region* pRegion = NULL ); + Region* CalcSelectedRegion(); + + Window* GetWindow() const { return pOutWin; } + + EESelectionMode GetSelectionMode() const { return eSelectionMode; } + void SetSelectionMode( EESelectionMode eMode ); + + inline void SetPointer( const Pointer& rPointer ); + inline const Pointer& GetPointer(); + + inline void SetCursor( const Cursor& rCursor ); + inline Cursor* GetCursor(); + + void AddDragAndDropListeners(); + void RemoveDragAndDropListeners(); + + BOOL IsBulletArea( const Point& rPos, sal_uInt16* pPara ); + +// Fuer die SelectionEngine... + void CreateAnchor(); + void DeselectAll(); + sal_Bool SetCursorAtPoint( const Point& rPointPixel ); + sal_Bool IsSelectionAtPoint( const Point& rPosPixel ); + sal_Bool IsInSelection( const EditPaM& rPaM ); + + + void SetAnchorMode( EVAnchorMode eMode ); + EVAnchorMode GetAnchorMode() const { return eAnchorMode; } + void CalcAnchorPoint(); + void RecalcOutputArea(); + + void ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, BOOL test ); + void ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, USHORT nShowCursorFlags = 0 ); + Pair Scroll( long ndX, long ndY, BYTE nRangeCheck = RGCHK_NEG ); + + void SetInsertMode( sal_Bool bInsert ); + sal_Bool IsInsertMode() const { return ( ( nControl & EV_CNTRL_OVERWRITE ) == 0 ); } + + void EnablePaste( sal_Bool bEnable ) { SetFlags( nControl, EV_CNTRL_ENABLEPASTE, bEnable ); } + sal_Bool IsPasteEnabled() const { return ( ( nControl & EV_CNTRL_ENABLEPASTE ) != 0 ); } + + sal_Bool DoSingleLinePaste() const { return ( ( nControl & EV_CNTRL_SINGLELINEPASTE ) != 0 ); } + sal_Bool DoAutoScroll() const { return ( ( nControl & EV_CNTRL_AUTOSCROLL ) != 0 ); } + sal_Bool DoBigScroll() const { return ( ( nControl & EV_CNTRL_BIGSCROLL ) != 0 ); } + sal_Bool DoAutoSize() const { return ( ( nControl & EV_CNTRL_AUTOSIZE ) != 0 ); } + sal_Bool DoAutoWidth() const { return ( ( nControl & EV_CNTRL_AUTOSIZEX) != 0 ); } + sal_Bool DoAutoHeight() const { return ( ( nControl & EV_CNTRL_AUTOSIZEY) != 0 ); } + sal_Bool DoInvalidateMore() const { return ( ( nControl & EV_CNTRL_INVONEMORE ) != 0 ); } + + void SetBackgroundColor( const Color& rColor ); + const Color& GetBackgroundColor() const { + return ( pBackgroundColor ? *pBackgroundColor : pOutWin->GetBackground().GetColor() ); } + + sal_Bool IsWrongSpelledWord( const EditPaM& rPaM, sal_Bool bMarkIfWrong ); + String SpellIgnoreOrAddWord( sal_Bool bAdd ); + + const SvxFieldItem* GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const; + void DeleteSelected(); + + // Ggf. mehr als OutputArea invalidieren, fuer den DrawingEngine-Textrahmen... + void SetInvalidateMore( sal_uInt16 nPixel ) { nInvMore = nPixel; } + sal_uInt16 GetInvalidateMore() const { return (sal_uInt16)nInvMore; } +}; + +// ---------------------------------------------------------------------- +// ImpEditEngine +// ---------------------------------------------------------------------- + +typedef EditView* EditViewPtr; +SV_DECL_PTRARR( EditViews, EditViewPtr, 0, 1 ) + +class ImpEditEngine : public SfxListener +{ + // Die Undos muessen direkt manipulieren ( private-Methoden ), + // damit keine neues Undos eingefuegt werden! + friend class EditUndoInsertChars; + friend class EditUndoRemoveChars; + friend class EditUndoDelContent; + friend class EditUndoConnectParas; + friend class EditUndoSplitPara; + friend class EditUndoInsertFeature; + friend class EditUndoMoveParagraphs; + + friend class EditView; + friend class ImpEditView; + friend class EditEngine; // Fuer Zugriff auf Imp-Methoden + friend class EditRTFParser; // Fuer Zugriff auf Imp-Methoden + friend class EditHTMLParser; // Fuer Zugriff auf Imp-Methoden + friend class EdtAutoCorrDoc; // Fuer Zugriff auf Imp-Methoden + friend class EditDbg; // DebugRoutinen + +private: + + // ================================================================ + // Daten... + // ================================================================ + + // Dokument-Spezifische Daten... + ParaPortionList aParaPortionList; // Formatierung + Size aPaperSize; // Layout + Size aMinAutoPaperSize; // Layout ? + Size aMaxAutoPaperSize; // Layout ? + EditDoc aEditDoc; // Dokumenteninhalt + + // Engine-Spezifische Daten.... + EditEngine* pEditEngine; + EditViews aEditViews; + EditView* pActiveView; + TextRanger* pTextRanger; + + SfxStyleSheetPool* pStylePool; + SfxItemPool* pTextObjectPool; + + VirtualDevice* pVirtDev; + OutputDevice* pRefDev; + + svtools::ColorConfig* pColorConfig; + mutable SvtCTLOptions* pCTLOptions; + + SfxItemSet* pEmptyItemSet; + EditUndoManager* pUndoManager; + ESelection* pUndoMarkSelection; + + ImplIMEInfos* mpIMEInfos; + + NotifyList aNotifyCache; + + XubString aWordDelimiters; + XubString aGroupChars; + + EditSelFunctionSet aSelFuncSet; + EditSelectionEngine aSelEngine; + + Color maBackgroundColor; + + sal_uInt32 nBlockNotifications; + sal_uInt16 nStretchX; + sal_uInt16 nStretchY; + + USHORT nAsianCompressionMode; + BOOL bKernAsianPunctuation; + BOOL bAddExtLeading; + + EEHorizontalTextDirection eDefaultHorizontalTextDirection; + + sal_uInt16 nBigTextObjectStart; + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > xSpeller; + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > xHyphenator; + SpellInfo* pSpellInfo; + mutable ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > xBI; + mutable ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > xISC; + + ConvInfo * pConvInfo; + + XubString aAutoCompleteText; + + InternalEditStatus aStatus; + + LanguageType eDefLanguage; + + OnDemandLocaleDataWrapper xLocaleDataWrapper; + OnDemandTransliterationWrapper xTransliterationWrapper; + + sal_Bool bIsFormatting; + sal_Bool bFormatted; + sal_Bool bInSelection; + sal_Bool bIsInUndo; + sal_Bool bUpdate; + sal_Bool bUndoEnabled; + sal_Bool bOwnerOfRefDev; + sal_Bool bDowning; + sal_Bool bUseAutoColor; + sal_Bool bForceAutoColor; + sal_Bool bCallParaInsertedOrDeleted; + sal_Bool bImpConvertFirstCall; // specifies if ImpConvert is called the very first time after Convert was called + sal_Bool bFirstWordCapitalization; // specifies if auto-correction should capitalize the first word or not + + // Fuer Formatierung / Update.... + DeletedNodesList aDeletedNodes; + Rectangle aInvalidRec; + sal_uInt32 nCurTextHeight; + sal_uInt16 nOnePixelInRef; + + IdleFormattter aIdleFormatter; + + Timer aOnlineSpellTimer; + + // Wenn an einer Stelle erkannt wird, dass der StatusHdl gerufen werden + // muss, dies aber nicht sofort geschehen darf (kritischer Abschnitt): + Timer aStatusTimer; + Link aStatusHdlLink; + Link aNotifyHdl; + Link aImportHdl; + Link aBeginMovingParagraphsHdl; + Link aEndMovingParagraphsHdl; + Link aBeginPasteOrDropHdl; + Link aEndPasteOrDropHdl; + Link aModifyHdl; + Link maBeginDropHdl; + Link maEndDropHdl; + + vos::ORef<SvxForbiddenCharactersTable> xForbiddenCharsTable; + + + // ================================================================ + // Methoden... + // ================================================================ + + void CursorMoved( ContentNode* pPrevNode ); + void ParaAttribsChanged( ContentNode* pNode ); + void TextModified(); + void CalcHeight( ParaPortion* pPortion ); + + // ggf. lieber inline, aber so einiges... + void InsertUndo( EditUndo* pUndo, sal_Bool bTryMerge = sal_False ); + void ResetUndoManager(); + sal_Bool HasUndoManager() const { return pUndoManager ? sal_True : sal_False; } + + EditUndoSetAttribs* CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet ); + + EditPaM GetPaM( Point aDocPos, sal_Bool bSmart = sal_True ); + EditPaM GetPaM( ParaPortion* pPortion, Point aPos, sal_Bool bSmart = sal_True ); + long GetXPos( ParaPortion* pParaPortion, EditLine* pLine, USHORT nIndex, BOOL bPreferPortionStart = FALSE ); + long GetPortionXOffset( ParaPortion* pParaPortion, EditLine* pLine, USHORT nTextPortion ); + USHORT GetChar( ParaPortion* pParaPortion, EditLine* pLine, long nX, BOOL bSmart = TRUE ); + Range GetInvalidYOffsets( ParaPortion* pPortion ); + Range GetLineXPosStartEnd( ParaPortion* pParaPortion, EditLine* pLine ); + + void SetParaAttrib( BYTE nFunc, EditSelection aSel, sal_uInt16 nValue ); + sal_uInt16 GetParaAttrib( BYTE nFunc, EditSelection aSel ); + void SetCharAttrib( EditSelection aSel, const SfxPoolItem& rItem ); + void ParaAttribsToCharAttribs( ContentNode* pNode ); + void GetCharAttribs( sal_uInt16 nPara, EECharAttribArray& rLst ) const; + + EditTextObject* CreateBinTextObject( EditSelection aSelection, SfxItemPool*, sal_Bool bAllowBigObjects = sal_False, sal_uInt16 nBigObjStart = 0 ) const; + void StoreBinTextObject( SvStream& rOStream, BinTextObject& rTextObject ); + EditSelection InsertBinTextObject( BinTextObject&, EditPaM aPaM ); + EditSelection InsertText( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& rxDataObj, const String& rBaseURL, const EditPaM& rPaM, BOOL bUseSpecial ); + + EditPaM Clear(); + EditPaM RemoveText(); + EditPaM RemoveText( EditSelection aEditSelection ); + sal_Bool CreateLines( USHORT nPara, sal_uInt32 nStartPosY ); + void CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 nStartPosY ); + sal_Bool FinishCreateLines( ParaPortion* pParaPortion ); + void CalcCharPositions( ParaPortion* pParaPortion ); + void CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStartPos /*, sal_Bool bCreateBlockPortions */ ); + void RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars ); + sal_uInt16 SplitTextPortion( ParaPortion* pParaPortion, sal_uInt16 nPos, EditLine* pCurLine = 0 ); + void SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut = NULL, sal_uInt16 nIgnoreWhich = 0 ); + void RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont ); + void CheckAutoPageSize(); + + void ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate ); + void ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace ); + EditPaM ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, sal_Bool bBackward = sal_False ); + EditPaM ImpDeleteSelection( EditSelection aEditSelection); + EditPaM ImpInsertParaBreak( const EditPaM& rPaM, sal_Bool bKeepEndingAttribs = sal_True ); + EditPaM ImpInsertParaBreak( const EditSelection& rEditSelection, sal_Bool bKeepEndingAttribs = sal_True ); + EditPaM ImpInsertText( EditSelection aCurEditSelection, const String& rStr ); + EditPaM ImpInsertFeature( EditSelection aEditSelection, const SfxPoolItem& rItem ); + void ImpRemoveChars( const EditPaM& rPaM, sal_uInt16 nChars, EditUndoRemoveChars* pCurUndo = 0 ); + void ImpRemoveParagraph( sal_uInt16 nPara ); + EditSelection ImpMoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos ); + + EditPaM ImpFastInsertText( EditPaM aPaM, const String& rStr ); + EditPaM ImpFastInsertParagraph( sal_uInt16 nPara ); + + sal_Bool ImpCheckRefMapMode(); + + BOOL ImplHasText() const; + + void ImpFindKashidas( ContentNode* pNode, USHORT nStart, USHORT nEnd, SvUShorts& rArray ); + + void InsertContent( ContentNode* pNode, sal_uInt16 nPos ); + EditPaM SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos ); + EditPaM ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward ); + + void ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ); + sal_Bool IsParagraphVisible( sal_uInt16 nParagraph ); + + EditPaM PageUp( const EditPaM& rPaM, EditView* pView); + EditPaM PageDown( const EditPaM& rPaM, EditView* pView); + EditPaM CursorUp( const EditPaM& rPaM, EditView* pEditView ); + EditPaM CursorDown( const EditPaM& rPaM, EditView* pEditView ); + EditPaM CursorLeft( const EditPaM& rPaM, USHORT nCharacterIteratorMode = ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + EditPaM CursorRight( const EditPaM& rPaM, USHORT nCharacterIteratorMode = ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + EditPaM CursorStartOfLine( const EditPaM& rPaM ); + EditPaM CursorEndOfLine( const EditPaM& rPaM ); + EditPaM CursorStartOfParagraph( const EditPaM& rPaM ); + EditPaM CursorEndOfParagraph( const EditPaM& rPaM ); + EditPaM CursorStartOfDoc(); + EditPaM CursorEndOfDoc(); + EditPaM WordLeft( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM WordRight( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM StartOfWord( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM EndOfWord( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditSelection SelectWord( const EditSelection& rCurSelection, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, BOOL bAcceptStartOfWord = TRUE ); + EditSelection SelectSentence( const EditSelection& rCurSel ); + EditPaM CursorVisualLeftRight( EditView* pEditView, const EditPaM& rPaM, USHORT nCharacterIteratorMode, BOOL bToLeft ); + EditPaM CursorVisualStartEnd( EditView* pEditView, const EditPaM& rPaM, BOOL bStart ); + + + void InitScriptTypes( USHORT nPara ); + USHORT GetScriptType( const EditPaM& rPaM, USHORT* pEndPos = NULL ) const; + USHORT GetScriptType( const EditSelection& rSel ) const; + BOOL IsScriptChange( const EditPaM& rPaM ) const; + BOOL HasScriptType( USHORT nPara, USHORT nType ) const; + + BOOL ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, USHORT nStartPos, sal_Int32* pDXArray, USHORT n100thPercentFromMax, BOOL bManipulateDXArray ); + void ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth ); + + void ImplInitLayoutMode( OutputDevice* pOutDev, USHORT nPara, USHORT nIndex ); + void ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eLang ); + + EditPaM ReadText( SvStream& rInput, EditSelection aSel ); + EditPaM ReadRTF( SvStream& rInput, EditSelection aSel ); + EditPaM ReadXML( SvStream& rInput, EditSelection aSel ); + EditPaM ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ); + EditPaM ReadBin( SvStream& rInput, EditSelection aSel ); + sal_uInt32 WriteText( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteRTF( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteXML( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteHTML( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteBin( SvStream& rOutput, EditSelection aSel, BOOL bStoreUnicode = FALSE ) const; + + void WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ); + sal_Bool WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ); + long LogicToTwips( long n ); + + inline short GetXValue( short nXValue ) const; + inline sal_uInt16 GetXValue( sal_uInt16 nXValue ) const; + inline long GetXValue( long nXValue ) const; + + inline short GetYValue( short nYValue ) const; + inline sal_uInt16 GetYValue( sal_uInt16 nYValue ) const; + + ContentNode* GetPrevVisNode( ContentNode* pCurNode ); + ContentNode* GetNextVisNode( ContentNode* pCurNode ); + + ParaPortion* GetPrevVisPortion( ParaPortion* pCurPortion ); + ParaPortion* GetNextVisPortion( ParaPortion* pCurPortion ); + + void SetBackgroundColor( const Color& rColor ) { maBackgroundColor = rColor; } + Color GetBackgroundColor() const { return maBackgroundColor; } + + Color GetAutoColor() const; + void EnableAutoColor( BOOL b ) { bUseAutoColor = b; } + BOOL IsAutoColorEnabled() const { return bUseAutoColor; } + void ForceAutoColor( BOOL b ) { bForceAutoColor = b; } + BOOL IsForceAutoColor() const { return bForceAutoColor; } + + inline VirtualDevice* GetVirtualDevice( const MapMode& rMapMode, ULONG nDrawMode ); + inline void EraseVirtualDevice(); + + DECL_LINK( StatusTimerHdl, Timer * ); + DECL_LINK( IdleFormatHdl, Timer * ); + DECL_LINK( OnlineSpellHdl, Timer * ); + DECL_LINK( DocModified, void* ); + + void CheckIdleFormatter(); + + inline ParaPortion* FindParaPortion( ContentNode* pNode ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > CreateTransferable( const EditSelection& rSelection ) const; + + void SetValidPaperSize( const Size& rSz ); + + ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > ImplGetBreakIterator() const; + ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > ImplGetInputSequenceChecker() const; + + /** Decorate metafile output with verbose text comments + + This method is used to wrap SvxFont::QuickDrawText, to + determine character-by-character wise, which logical text + units like characters, words and sentences are contained in + the output string at hand. This is necessary for slideshow + text effects. + */ + void ImplFillTextMarkingVector(const ::com::sun::star::lang::Locale& rLocale, EEngineData::TextMarkingVector& rTextMarkingVector, const String& rTxt, const USHORT nIdx, const USHORT nLen) const; + +protected: + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + +public: + ImpEditEngine( EditEngine* pEditEngine, SfxItemPool* pPool ); + ~ImpEditEngine(); + + void InitDoc( BOOL bKeepParaAttribs ); + EditDoc& GetEditDoc() { return aEditDoc; } + const EditDoc& GetEditDoc() const { return aEditDoc; } + + inline EditUndoManager& GetUndoManager(); + + void SetUpdateMode( sal_Bool bUp, EditView* pCurView = 0, sal_Bool bForceUpdate = sal_False ); + sal_Bool GetUpdateMode() const { return bUpdate; } + + const ParaPortionList& GetParaPortions() const { return aParaPortionList; } + ParaPortionList& GetParaPortions() { return aParaPortionList; } + EditViews& GetEditViews() { return aEditViews; } + + const Size& GetPaperSize() const { return aPaperSize; } + void SetPaperSize( const Size& rSz ) { aPaperSize = rSz; } + + void SetVertical( BOOL bVertical ); + BOOL IsVertical() const { return GetEditDoc().IsVertical(); } + + void SetFixedCellHeight( BOOL bUseFixedCellHeight ); + BOOL IsFixedCellHeight() const { return GetEditDoc().IsFixedCellHeight(); } + + void SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) { eDefaultHorizontalTextDirection = eHTextDir; } + EEHorizontalTextDirection GetDefaultHorizontalTextDirection() const { return eDefaultHorizontalTextDirection; } + + + void InitWritingDirections( USHORT nPara ); + BOOL IsRightToLeft( USHORT nPara ) const; + BYTE GetRightToLeft( USHORT nPara, USHORT nChar, USHORT* pStart = NULL, USHORT* pEnd = NULL ); + BOOL HasDifferentRTLLevels( const ContentNode* pNode ); + + void SetTextRanger( TextRanger* pRanger ); + TextRanger* GetTextRanger() const { return pTextRanger; } + + const Size& GetMinAutoPaperSize() const { return aMinAutoPaperSize; } + void SetMinAutoPaperSize( const Size& rSz ) { aMinAutoPaperSize = rSz; } + + const Size& GetMaxAutoPaperSize() const { return aMaxAutoPaperSize; } + void SetMaxAutoPaperSize( const Size& rSz ) { aMaxAutoPaperSize = rSz; } + + void FormatDoc(); + void FormatFullDoc(); + void UpdateViews( EditView* pCurView = 0 ); + void Paint( ImpEditView* pView, const Rectangle& rRect, sal_Bool bUseVirtDev = sal_False ); + void Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly = sal_False, short nOrientation = 0 ); + + sal_Bool MouseButtonUp( const MouseEvent& rMouseEvent, EditView* pView ); + sal_Bool MouseButtonDown( const MouseEvent& rMouseEvent, EditView* pView ); + sal_Bool MouseMove( const MouseEvent& rMouseEvent, EditView* pView ); + void Command( const CommandEvent& rCEvt, EditView* pView ); + + EditSelectionEngine& GetSelEngine() { return aSelEngine; } + XubString GetSelected( const EditSelection& rSel, const LineEnd eParaSep = LINEEND_LF ) const; + + const SfxItemSet& GetEmptyItemSet(); + + void UpdateSelections(); + + void EnableUndo( sal_Bool bEnable ); + sal_Bool IsUndoEnabled() { return bUndoEnabled; } + void SetUndoMode( sal_Bool b ) { bIsInUndo = b; } + sal_Bool IsInUndo() { return bIsInUndo; } + + void SetCallParaInsertedOrDeleted( sal_Bool b ) { bCallParaInsertedOrDeleted = b; } + sal_Bool IsCallParaInsertedOrDeleted() const { return bCallParaInsertedOrDeleted; } + + sal_Bool IsFormatted() const { return bFormatted; } + sal_Bool IsFormatting() const { return bIsFormatting; } + + void SetText( const String& rText ); + EditPaM DeleteSelected( EditSelection aEditSelection); + EditPaM InsertText( const EditSelection& rCurEditSelection, sal_Unicode c, sal_Bool bOverwrite, sal_Bool bIsUserInput = sal_False ); + EditPaM InsertText( EditSelection aCurEditSelection, const String& rStr ); + EditPaM AutoCorrect( const EditSelection& rCurEditSelection, sal_Unicode c, sal_Bool bOverwrite ); + EditPaM DeleteLeftOrRight( const EditSelection& rEditSelection, BYTE nMode, BYTE nDelMode = DELMODE_SIMPLE ); + EditPaM InsertParaBreak( EditSelection aEditSelection ); + EditPaM InsertLineBreak( EditSelection aEditSelection ); + EditPaM InsertTab( EditSelection aEditSelection ); + EditPaM InsertField( EditSelection aEditSelection, const SvxFieldItem& rFld ); + sal_Bool UpdateFields(); + + EditPaM Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs = NULL ); + void Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ); + + EditTextObject* CreateTextObject(); + EditTextObject* CreateTextObject( EditSelection aSel ); + void SetText( const EditTextObject& rTextObject ); + EditSelection InsertText( const EditTextObject& rTextObject, EditSelection aSel ); + + EditSelection MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView ); + + EditSelection MoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos, EditView* pCurView ); + + sal_uInt32 CalcTextHeight(); + sal_uInt32 GetTextHeight() const; + sal_uInt32 CalcTextWidth( BOOL bIgnoreExtraSpace ); + sal_uInt32 CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, BOOL bIgnoreExtraSpace ); + sal_uInt16 GetLineCount( sal_uInt16 nParagraph ) const; + sal_uInt16 GetLineLen( sal_uInt16 nParagraph, sal_uInt16 nLine ) const; + void GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const; + USHORT GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const; + sal_uInt16 GetLineHeight( sal_uInt16 nParagraph, sal_uInt16 nLine ); + sal_uInt32 GetParaHeight( sal_uInt16 nParagraph ); + + SfxItemSet GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags = 0xFF ) const; + SfxItemSet GetAttribs( EditSelection aSel, BOOL bOnlyHardAttrib = FALSE ); + void SetAttribs( EditSelection aSel, const SfxItemSet& rSet, BYTE nSpecial = 0 ); + void RemoveCharAttribs( EditSelection aSel, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich = 0 ); + void RemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich = 0, sal_Bool bRemoveFeatures = sal_False ); + void SetFlatMode( sal_Bool bFlat ); + + void SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet ); + const SfxItemSet& GetParaAttribs( sal_uInt16 nPara ) const; + + sal_Bool HasParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const; + const SfxPoolItem& GetParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const; + + Rectangle PaMtoEditCursor( EditPaM aPaM, sal_uInt16 nFlags = 0 ); + Rectangle GetEditCursor( ParaPortion* pPortion, sal_uInt16 nIndex, sal_uInt16 nFlags = 0 ); + + sal_Bool IsModified() const { return aEditDoc.IsModified(); } + void SetModifyFlag( sal_Bool b ) { aEditDoc.SetModified( b ); } + void SetModifyHdl( const Link& rLink ) { aModifyHdl = rLink; } + Link GetModifyHdl() const { return aModifyHdl; } + + + sal_Bool IsInSelectionMode() { return bInSelection; } + void StopSelectionMode(); + + void IndentBlock( EditView* pView, sal_Bool bRight ); + +// Fuer Undo/Redo + sal_Bool Undo( EditView* pView ); + sal_Bool Redo( EditView* pView ); + sal_Bool Repeat( EditView* pView ); + +// OV-Special + void InvalidateFromParagraph( sal_uInt16 nFirstInvPara ); + EditPaM InsertParagraph( sal_uInt16 nPara ); + EditSelection* SelectParagraph( sal_uInt16 nPara ); + + void SetStatusEventHdl( const Link& rLink ) { aStatusHdlLink = rLink; } + Link GetStatusEventHdl() const { return aStatusHdlLink; } + + void SetNotifyHdl( const Link& rLink ) { aNotifyHdl = rLink; } + Link GetNotifyHdl() const { return aNotifyHdl; } + + void FormatAndUpdate( EditView* pCurView = 0 ); + inline void IdleFormatAndUpdate( EditView* pCurView = 0 ); + + svtools::ColorConfig& GetColorConfig(); + BOOL IsVisualCursorTravelingEnabled(); + BOOL DoVisualCursorTraveling( const ContentNode* pNode ); + + EditSelection ConvertSelection( sal_uInt16 nStartPara, sal_uInt16 nStartPos, sal_uInt16 nEndPara, sal_uInt16 nEndPos ) const; + inline EPaM CreateEPaM( const EditPaM& rPaM ); + inline EditPaM CreateEditPaM( const EPaM& rEPaM ); + inline ESelection CreateESel( const EditSelection& rSel ); + inline EditSelection CreateSel( const ESelection& rSel ); + + + void SetStyleSheetPool( SfxStyleSheetPool* pSPool ); + SfxStyleSheetPool* GetStyleSheetPool() const { return pStylePool; } + + void SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle ); + void SetStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pStyle ); + SfxStyleSheet* GetStyleSheet( sal_uInt16 nPara ) const; + + void UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle ); + void RemoveStyleFromParagraphs( SfxStyleSheet* pStyle ); + + OutputDevice* GetRefDevice() const { return pRefDev; } + void SetRefDevice( OutputDevice* pRefDef ); + + const MapMode& GetRefMapMode() { return pRefDev->GetMapMode(); } + void SetRefMapMode( const MapMode& rMapMode ); + + InternalEditStatus& GetStatus() { return aStatus; } + void CallStatusHdl(); + void DelayedCallStatusHdl() { aStatusTimer.Start(); } + + void CallNotify( EENotify& rNotify ); + void EnterBlockNotifications(); + void LeaveBlockNotifications(); + + + EditSelection MatchGroup( const EditSelection& rSel ); + + void UndoActionStart( sal_uInt16 nId ); + void UndoActionStart( sal_uInt16 nId, const ESelection& rSel ); + void UndoActionEnd( sal_uInt16 nId ); + + EditView* GetActiveView() const { return pActiveView; } + void SetActiveView( EditView* pView ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > + GetSpeller(); + void SetSpeller( ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > &xSpl ) + { xSpeller = xSpl; } + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > + GetHyphenator() const { return xHyphenator; } + void SetHyphenator( ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > &xHyph ) + { xHyphenator = xHyph; } + SpellInfo* GetSpellInfo() const { return pSpellInfo; } + + void SetDefaultLanguage( LanguageType eLang ) { eDefLanguage = eLang; } + LanguageType GetDefaultLanguage() const { return eDefLanguage; } + + + LanguageType GetLanguage( const EditSelection rSelection ) const; + LanguageType GetLanguage( const EditPaM& rPaM, USHORT* pEndPos = NULL ) const; + ::com::sun::star::lang::Locale GetLocale( const EditPaM& rPaM ) const; + + void DoOnlineSpelling( ContentNode* pThisNodeOnly = 0, sal_Bool bSpellAtCursorPos = sal_False, sal_Bool bInteruptable = sal_True ); + EESpellState Spell( EditView* pEditView, sal_Bool bMultipleDoc ); + EESpellState HasSpellErrors(); + EESpellState StartThesaurus( EditView* pEditView ); + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > + ImpSpell( EditView* pEditView ); + + // text conversion functions + void Convert( EditView* pEditView, LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, INT32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ); + void ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, + sal_Bool bAllowImplicitChangesForNotConvertibleText, LanguageType nTargetLang, const Font *pTargetFont ); + ConvInfo * GetConvInfo() const { return pConvInfo; } + sal_Bool HasConvertibleTextPortion( LanguageType nLang ); + void SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ); + + // returns true if input sequence checking should be applied + sal_Bool IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const; + + //find the next error within the given selection - forward only! + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > + ImpFindNextError(EditSelection& rSelection); + //initialize sentence spelling + void StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc); + //spell and return a sentence + bool SpellSentence(EditView& rView, ::svx::SpellPortions& rToFill, bool bIsGrammarChecking ); + //put spelling back to start of current sentence - needed after switch of grammar support + void PutSpellingToSentenceStart( EditView& rEditView ); + //applies a changed sentence + void ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool bIsGrammarChecking ); + //deinitialize sentence spelling + void EndSpelling(); + //adds one or more portions of text to the SpellPortions depending on language changes + void AddPortionIterated( + EditView& rEditView, + const EditSelection rSel, + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill); + //adds one portion to the SpellPortions + void AddPortion( + const EditSelection rSel, + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill, + bool bIsField ); + + sal_Bool Search( const SvxSearchItem& rSearchItem, EditView* pView ); + sal_Bool ImpSearch( const SvxSearchItem& rSearchItem, const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ); + sal_uInt16 StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ); + sal_Bool HasText( const SvxSearchItem& rSearchItem ); + + void SetEditTextObjectPool( SfxItemPool* pP ) { pTextObjectPool = pP; } + SfxItemPool* GetEditTextObjectPool() const { return pTextObjectPool; } + + const SvxNumberFormat * GetNumberFormat( const ContentNode* pNode ) const; + sal_Int32 GetSpaceBeforeAndMinLabelWidth( const ContentNode *pNode, sal_Int32 *pnSpaceBefore = 0, sal_Int32 *pnMinLabelWidth = 0 ) const; + + const SvxLRSpaceItem& GetLRSpaceItem( ContentNode* pNode ); + SvxAdjust GetJustification( USHORT nPara ) const; + + void SetCharStretching( sal_uInt16 nX, sal_uInt16 nY ); + inline void GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ); + void DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ); + + void SetBigTextObjectStart( sal_uInt16 nStartAtPortionCount ) { nBigTextObjectStart = nStartAtPortionCount; } + sal_uInt16 GetBigTextObjectStart() const { return nBigTextObjectStart; } + + inline EditEngine* GetEditEnginePtr() const { return pEditEngine; } + + void StartOnlineSpellTimer() { aOnlineSpellTimer.Start(); } + void StopOnlineSpellTimer() { aOnlineSpellTimer.Stop(); } + + const XubString& GetAutoCompleteText() const { return aAutoCompleteText; } + void SetAutoCompleteText( const String& rStr, sal_Bool bUpdateTipWindow ); + + EditSelection TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ); + + void SetAsianCompressionMode( USHORT n ); + USHORT GetAsianCompressionMode() const { return nAsianCompressionMode; } + + void SetKernAsianPunctuation( BOOL b ); + BOOL IsKernAsianPunctuation() const { return bKernAsianPunctuation; } + + void SetAddExtLeading( BOOL b ); + BOOL IsAddExtLeading() const { return bAddExtLeading; } + + vos::ORef<SvxForbiddenCharactersTable> GetForbiddenCharsTable( BOOL bGetInternal = TRUE ) const; + void SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ); + + BOOL mbLastTryMerge; + + /** sets a link that is called at the beginning of a drag operation at an edit view */ + void SetBeginDropHdl( const Link& rLink ) { maBeginDropHdl = rLink; } + Link GetBeginDropHdl() const { return maBeginDropHdl; } + + /** sets a link that is called at the end of a drag operation at an edit view */ + void SetEndDropHdl( const Link& rLink ) { maEndDropHdl = rLink; } + Link GetEndDropHdl() const { return maEndDropHdl; } + + /// specifies if auto-correction should capitalize the first word or not (default is on) + void SetFirstWordCapitalization( BOOL bCapitalize ) { bFirstWordCapitalization = bCapitalize; } + BOOL IsFirstWordCapitalization() const { return bFirstWordCapitalization; } +}; + +inline EPaM ImpEditEngine::CreateEPaM( const EditPaM& rPaM ) +{ + ContentNode* pNode = rPaM.GetNode(); + return EPaM( aEditDoc.GetPos( pNode ), rPaM.GetIndex() ); +} + +inline EditPaM ImpEditEngine::CreateEditPaM( const EPaM& rEPaM ) +{ + DBG_ASSERT( rEPaM.nPara < aEditDoc.Count(), "CreateEditPaM: Ungueltiger Absatz" ); + DBG_ASSERT( aEditDoc[ rEPaM.nPara ]->Len() >= rEPaM.nIndex, "CreateEditPaM: Ungueltiger Index" ); + return EditPaM( aEditDoc[ rEPaM.nPara], rEPaM.nIndex ); +} + +inline ESelection ImpEditEngine::CreateESel( const EditSelection& rSel ) +{ + ContentNode* pStartNode = rSel.Min().GetNode(); + ContentNode* pEndNode = rSel.Max().GetNode(); + ESelection aESel; + aESel.nStartPara = aEditDoc.GetPos( pStartNode ); + aESel.nStartPos = rSel.Min().GetIndex(); + aESel.nEndPara = aEditDoc.GetPos( pEndNode ); + aESel.nEndPos = rSel.Max().GetIndex(); + return aESel; +} + +inline EditSelection ImpEditEngine::CreateSel( const ESelection& rSel ) +{ + DBG_ASSERT( rSel.nStartPara < aEditDoc.Count(), "CreateSel: Ungueltiger Start-Absatz" ); + DBG_ASSERT( rSel.nEndPara < aEditDoc.Count(), "CreateSel: Ungueltiger End-Absatz" ); + EditSelection aSel; + aSel.Min().SetNode( aEditDoc[ rSel.nStartPara ] ); + aSel.Min().SetIndex( rSel.nStartPos ); + aSel.Max().SetNode( aEditDoc[ rSel.nEndPara ] ); + aSel.Max().SetIndex( rSel.nEndPos ); + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateSel: Fehlerhafte Selektion!" ); + return aSel; +} + +inline VirtualDevice* ImpEditEngine::GetVirtualDevice( const MapMode& rMapMode, ULONG nDrawMode ) +{ + if ( !pVirtDev ) + pVirtDev = new VirtualDevice; + + if ( ( pVirtDev->GetMapMode().GetMapUnit() != rMapMode.GetMapUnit() ) || + ( pVirtDev->GetMapMode().GetScaleX() != rMapMode.GetScaleX() ) || + ( pVirtDev->GetMapMode().GetScaleY() != rMapMode.GetScaleY() ) ) + { + MapMode aMapMode( rMapMode ); + aMapMode.SetOrigin( Point( 0, 0 ) ); + pVirtDev->SetMapMode( aMapMode ); + } + + pVirtDev->SetDrawMode( nDrawMode ); + + return pVirtDev; +} + +inline void ImpEditEngine::EraseVirtualDevice() +{ + delete pVirtDev; + pVirtDev = 0; +} + +inline void ImpEditEngine::IdleFormatAndUpdate( EditView* pCurView ) +{ + aIdleFormatter.DoIdleFormat( pCurView ); +} + +#ifndef SVX_LIGHT +inline EditUndoManager& ImpEditEngine::GetUndoManager() +{ + if ( !pUndoManager ) + pUndoManager = new EditUndoManager( this ); + return *pUndoManager; +} +#endif + +inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode* pNode ) const +{ + sal_uInt16 nPos = aEditDoc.GetPos( pNode ); + DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" ); + return GetParaPortions()[ nPos ]; +} + +inline void ImpEditEngine::GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ) +{ + rX = nStretchX; + rY = nStretchY; +} + +inline short ImpEditEngine::GetXValue( short nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return (short) ((long)nXValue*nStretchX/100); +} + +inline sal_uInt16 ImpEditEngine::GetXValue( sal_uInt16 nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return (sal_uInt16) ((long)nXValue*nStretchX/100); +} + +inline long ImpEditEngine::GetXValue( long nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return nXValue*nStretchX/100; +} + +inline short ImpEditEngine::GetYValue( short nYValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchY == 100 ) ) + return nYValue; + + return (short) ((long)nYValue*nStretchY/100); +} + +inline sal_uInt16 ImpEditEngine::GetYValue( sal_uInt16 nYValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchY == 100 ) ) + return nYValue; + + return (sal_uInt16) ((long)nYValue*nStretchY/100); +} + +inline void ImpEditView::SetPointer( const Pointer& rPointer ) +{ + delete pPointer; + pPointer = new Pointer( rPointer ); +} + +inline const Pointer& ImpEditView::GetPointer() +{ + if ( !pPointer ) + { + pPointer = new Pointer( IsVertical() ? POINTER_TEXT_VERTICAL : POINTER_TEXT ); + return *pPointer; + } + + if(POINTER_TEXT == pPointer->GetStyle() && IsVertical()) + { + delete pPointer; + pPointer = new Pointer(POINTER_TEXT_VERTICAL); + } + else if(POINTER_TEXT_VERTICAL == pPointer->GetStyle() && !IsVertical()) + { + delete pPointer; + pPointer = new Pointer(POINTER_TEXT); + } + + return *pPointer; +} + +inline void ImpEditView::SetCursor( const Cursor& rCursor ) +{ + delete pCursor; + pCursor = new Cursor( rCursor ); +} + +inline Cursor* ImpEditView::GetCursor() +{ + if ( !pCursor ) + pCursor = new Cursor; + return pCursor; +} + +void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit ); +void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit = NULL, const MapUnit* pDestUnit = NULL ); +BYTE GetCharTypeForCompression( xub_Unicode cChar ); +Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin ); + +#endif // _IMPEDIT_HXX + + diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx new file mode 100644 index 000000000000..bbdfa47e6a57 --- /dev/null +++ b/editeng/source/editeng/impedit2.cxx @@ -0,0 +1,4632 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/lspcitem.hxx> +#include <editeng/flditem.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editdbg.hxx> +#include <eerdll2.hxx> +#include <editeng/eerdll.hxx> +#include <edtspell.hxx> +#include <eeobj.hxx> +#include <editeng/txtrange.hxx> +#include <svl/urlbmk.hxx> +#include <svtools/colorcfg.hxx> +#include <svl/ctloptions.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/fontitem.hxx> +#include <vcl/cmdevt.h> + +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/text/CharacterCompressionType.hpp> +#include <com/sun/star/i18n/InputSequenceCheckMode.hpp> + +#include <comphelper/processfactory.hxx> + +#include <sot/formats.hxx> + +#include <unicode/ubidi.h> + +using namespace ::com::sun::star; + +USHORT lcl_CalcExtraSpace( ParaPortion*, const SvxLineSpacingItem& rLSItem ) +{ + USHORT nExtra = 0; + /* if ( ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + // ULONG nH = pPortion->GetNode()->GetCharAttribs().GetDefFont().GetSize().Height(); + ULONG nH = pPortion->GetLines().GetObject( 0 )->GetHeight(); + long n = nH * rLSItem.GetPropLineSpace(); + n /= 100; + n -= nH; // nur den Abstand + if ( n > 0 ) + nExtra = (USHORT)n; + } + else */ + if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + { + nExtra = rLSItem.GetInterLineSpace(); + } + + return nExtra; +} + +// ---------------------------------------------------------------------- +// class ImpEditEngine +// ---------------------------------------------------------------------- + +ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) : + aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), + aMinAutoPaperSize( 0x0, 0x0 ), + aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), + aEditDoc( pItemPool ), + aWordDelimiters( RTL_CONSTASCII_USTRINGPARAM( " .,;:-'`'?!_=\"{}()[]\0xFF" ) ), + aGroupChars( RTL_CONSTASCII_USTRINGPARAM( "{}()[]" ) ) +{ + pEditEngine = pEE; + pRefDev = NULL; + pVirtDev = NULL; + pEmptyItemSet = NULL; + pActiveView = NULL; + pSpellInfo = NULL; + pConvInfo = NULL; + pTextObjectPool = NULL; + mpIMEInfos = NULL; + pStylePool = NULL; + pUndoManager = NULL; + pUndoMarkSelection = NULL; + pTextRanger = NULL; + pColorConfig = NULL; + pCTLOptions = NULL; + + nCurTextHeight = 0; + nBlockNotifications = 0; + nBigTextObjectStart = 20; + + nStretchX = 100; + nStretchY = 100; + + bInSelection = FALSE; + bOwnerOfRefDev = FALSE; + bDowning = FALSE; + bIsInUndo = FALSE; + bIsFormatting = FALSE; + bFormatted = FALSE; + bUpdate = TRUE; + bUseAutoColor = TRUE; + bForceAutoColor = FALSE; + bAddExtLeading = FALSE; + bUndoEnabled = TRUE; + bCallParaInsertedOrDeleted = FALSE; + bImpConvertFirstCall= FALSE; + bFirstWordCapitalization = TRUE; + + eDefLanguage = LANGUAGE_DONTKNOW; + maBackgroundColor = COL_AUTO; + + nAsianCompressionMode = text::CharacterCompressionType::NONE; + bKernAsianPunctuation = FALSE; + + eDefaultHorizontalTextDirection = EE_HTEXTDIR_DEFAULT; + + + aStatus.GetControlWord() = EE_CNTRL_USECHARATTRIBS | EE_CNTRL_DOIDLEFORMAT | + EE_CNTRL_PASTESPECIAL | EE_CNTRL_UNDOATTRIBS | + EE_CNTRL_ALLOWBIGOBJS | EE_CNTRL_RTFSTYLESHEETS | + EE_CNTRL_FORMAT100; + + aSelEngine.SetFunctionSet( &aSelFuncSet ); + + aStatusTimer.SetTimeout( 200 ); + aStatusTimer.SetTimeoutHdl( LINK( this, ImpEditEngine, StatusTimerHdl ) ); + + aIdleFormatter.SetTimeout( 5 ); + aIdleFormatter.SetTimeoutHdl( LINK( this, ImpEditEngine, IdleFormatHdl ) ); + + aOnlineSpellTimer.SetTimeout( 100 ); + aOnlineSpellTimer.SetTimeoutHdl( LINK( this, ImpEditEngine, OnlineSpellHdl ) ); + + pRefDev = EE_DLL()->GetGlobalData()->GetStdRefDevice(); + + // Ab hier wird schon auf Daten zugegriffen! + SetRefDevice( pRefDev ); + InitDoc( FALSE ); + + bCallParaInsertedOrDeleted = TRUE; + + aEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified ) ); + + mbLastTryMerge = FALSE; +} + +ImpEditEngine::~ImpEditEngine() +{ + aStatusTimer.Stop(); + aOnlineSpellTimer.Stop(); + aIdleFormatter.Stop(); + + // das Zerstoeren von Vorlagen kann sonst unnoetiges Formatieren ausloesen, + // wenn eine Parent-Vorlage zerstoert wird. + // Und das nach dem Zerstoeren der Daten! + bDowning = TRUE; + SetUpdateMode( FALSE ); + + delete pVirtDev; + delete pEmptyItemSet; + delete pUndoManager; + delete pTextRanger; + delete mpIMEInfos; + delete pColorConfig; + delete pCTLOptions; + if ( bOwnerOfRefDev ) + delete pRefDev; + delete pSpellInfo; +} + +void ImpEditEngine::SetRefDevice( OutputDevice* pRef ) +{ + if ( bOwnerOfRefDev ) + delete pRefDev; + + pRefDev = pRef; + bOwnerOfRefDev = FALSE; + + if ( !pRef ) + pRefDev = EE_DLL()->GetGlobalData()->GetStdRefDevice(); + + nOnePixelInRef = (USHORT)pRefDev->PixelToLogic( Size( 1, 0 ) ).Width(); + + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( (EditView*) 0); + } +} + +void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode ) +{ + if ( GetRefDevice()->GetMapMode() == rMapMode ) + return; + + // Wenn RefDev == GlobalRefDev => eigenes anlegen! + if ( !bOwnerOfRefDev && ( pRefDev == EE_DLL()->GetGlobalData()->GetStdRefDevice() ) ) + { + pRefDev = new VirtualDevice; + pRefDev->SetMapMode( MAP_TWIP ); + SetRefDevice( pRefDev ); + bOwnerOfRefDev = TRUE; + } + pRefDev->SetMapMode( rMapMode ); + nOnePixelInRef = (USHORT)pRefDev->PixelToLogic( Size( 1, 0 ) ).Width(); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( (EditView*) 0); + } +} + +void ImpEditEngine::InitDoc( BOOL bKeepParaAttribs ) +{ + USHORT nParas = aEditDoc.Count(); + for ( USHORT n = bKeepParaAttribs ? 1 : 0; n < nParas; n++ ) + { + if ( aEditDoc[n]->GetStyleSheet() ) + EndListening( *aEditDoc[n]->GetStyleSheet(), FALSE ); + } + + if ( bKeepParaAttribs ) + aEditDoc.RemoveText(); + else + aEditDoc.Clear(); + + GetParaPortions().Reset(); + + ParaPortion* pIniPortion = new ParaPortion( aEditDoc[0] ); + GetParaPortions().Insert( pIniPortion, 0 ); + + bFormatted = FALSE; + + if ( IsCallParaInsertedOrDeleted() ) + { + GetEditEnginePtr()->ParagraphDeleted( EE_PARA_ALL ); + GetEditEnginePtr()->ParagraphInserted( 0 ); + } + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + aEditDoc.GetObject( 0 )->CreateWrongList(); +#endif // !SVX_LIGHT +} + +EditPaM ImpEditEngine::DeleteSelected( EditSelection aSel ) +{ + EditPaM aPaM ( ImpDeleteSelection( aSel ) ); + return aPaM; +} + +XubString ImpEditEngine::GetSelected( const EditSelection& rSel, const LineEnd eEnd ) const +{ + XubString aText; + if ( !rSel.HasRange() ) + return aText; + + String aSep = EditDoc::GetSepStr( eEnd ); + + EditSelection aSel( rSel ); + aSel.Adjust( aEditDoc ); + + ContentNode* pStartNode = aSel.Min().GetNode(); + ContentNode* pEndNode = aSel.Max().GetNode(); + USHORT nStartNode = aEditDoc.GetPos( pStartNode ); + USHORT nEndNode = aEditDoc.GetPos( pEndNode ); + + DBG_ASSERT( nStartNode <= nEndNode, "Selektion nicht sortiert ?" ); + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetSelected" ); + ContentNode* pNode = aEditDoc.GetObject( nNode ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + aText += aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); + if ( nNode < nEndNode ) + aText += aSep; + } + return aText; +} + +BOOL ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + SetActiveView( pView ); + + if ( GetAutoCompleteText().Len() ) + SetAutoCompleteText( String(), TRUE ); + + GetSelEngine().SelMouseButtonDown( rMEvt ); + // Sonderbehandlungen + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + if ( !rMEvt.IsShift() ) + { + if ( rMEvt.GetClicks() == 2 ) + { + // damit die SelectionEngine weiss, dass Anker. + aSelEngine.CursorPosChanging( TRUE, FALSE ); + + EditSelection aNewSelection( SelectWord( aCurSel ) ); + pView->pImpEditView->DrawSelection(); + pView->pImpEditView->SetEditSelection( aNewSelection ); + pView->pImpEditView->DrawSelection(); + pView->ShowCursor( TRUE, TRUE ); + } + else if ( rMEvt.GetClicks() == 3 ) + { + // damit die SelectionEngine weiss, dass Anker. + aSelEngine.CursorPosChanging( TRUE, FALSE ); + + EditSelection aNewSelection( aCurSel ); + aNewSelection.Min().SetIndex( 0 ); + aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() ); + pView->pImpEditView->DrawSelection(); + pView->pImpEditView->SetEditSelection( aNewSelection ); + pView->pImpEditView->DrawSelection(); + pView->ShowCursor( TRUE, TRUE ); + } + } + return TRUE; +} + +void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + SetActiveView( pView ); + if ( rCEvt.GetCommand() == COMMAND_VOICE ) + { + const CommandVoiceData* pData = rCEvt.GetVoiceData(); + if ( pData->GetType() == VOICECOMMANDTYPE_DICTATION ) + { + // Funktionen auf KeyEvents umbiegen, wenn keine entsprechende + // Methode an EditView/EditEngine, damit Undo konsistent bleibt. + + SfxPoolItem* pNewAttr = NULL; + + switch ( pData->GetCommand() ) + { + case DICTATIONCOMMAND_UNKNOWN: + { + pView->InsertText( pData->GetText() ); + } + break; + case DICTATIONCOMMAND_NEWPARAGRAPH: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_NEWLINE: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN, KEY_SHIFT ) ) ); + } + break; + case DICTATIONCOMMAND_TAB: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_TAB, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_LEFT: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1 ) ) ); + } + break; + case DICTATIONCOMMAND_RIGHT: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT, KEY_MOD1 ) ) ); + } + break; + case DICTATIONCOMMAND_UP: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_DOWN: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_UNDO: + { + pView->Undo(); + } + break; + case DICTATIONCOMMAND_DEL: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1|KEY_SHIFT ) ) ); + pView->DeleteSelected(); + } + break; + case DICTATIONCOMMAND_BOLD_ON: + { + pNewAttr = new SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ); + } + break; + case DICTATIONCOMMAND_BOLD_OFF: + { + pNewAttr = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ); + } + break; + case DICTATIONCOMMAND_ITALIC_ON: + { + pNewAttr = new SvxPostureItem( ITALIC_NORMAL, EE_CHAR_ITALIC ); + } + break; + case DICTATIONCOMMAND_ITALIC_OFF: + { + pNewAttr = new SvxPostureItem( ITALIC_NORMAL, EE_CHAR_ITALIC ); + } + break; + case DICTATIONCOMMAND_UNDERLINE_ON: + { + pNewAttr = new SvxUnderlineItem( UNDERLINE_SINGLE, EE_CHAR_UNDERLINE ); + } + break; + case DICTATIONCOMMAND_UNDERLINE_OFF: + { + pNewAttr = new SvxUnderlineItem( UNDERLINE_NONE, EE_CHAR_UNDERLINE ); + } + break; + } + + if ( pNewAttr ) + { + SfxItemSet aSet( GetEmptyItemSet() ); + aSet.Put( *pNewAttr ); + pView->SetAttribs( aSet ); + delete pNewAttr; + } + } + } + else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT ) + { + pView->DeleteSelected(); + delete mpIMEInfos; + EditPaM aPaM = pView->GetImpEditView()->GetEditSelection().Max(); + String aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() ); + USHORT nMax = aOldTextAfterStartPos.Search( CH_FEATURE ); + if ( nMax != STRING_NOTFOUND ) // don't overwrite features! + aOldTextAfterStartPos.Erase( nMax ); + mpIMEInfos = new ImplIMEInfos( aPaM, aOldTextAfterStartPos ); + mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode(); + UndoActionStart( EDITUNDO_INSERT ); + } + else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT ) + { + DBG_ASSERT( mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" ); + if( mpIMEInfos ) + { + // #102812# convert quotes in IME text + // works on the last input character, this is escpecially in Korean text often done + // quotes that are inside of the string are not replaced! + // Borrowed from sw: edtwin.cxx + if ( mpIMEInfos->nLen ) + { + EditSelection aSel( mpIMEInfos->aPos ); + aSel.Min().GetIndex() += mpIMEInfos->nLen-1; + aSel.Max().GetIndex() = + aSel.Max().GetIndex() + mpIMEInfos->nLen; + // #102812# convert quotes in IME text + // works on the last input character, this is escpecially in Korean text often done + // quotes that are inside of the string are not replaced! + const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() ); + if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode == '\"' ) || ( nCharCode == '\'' ) ) ) + { + aSel = DeleteSelected( aSel ); + aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite ); + pView->pImpEditView->SetEditSelection( aSel ); + } + } + + ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); + pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex(), 0 ); + + BOOL bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite; + + delete mpIMEInfos; + mpIMEInfos = NULL; + + FormatAndUpdate( pView ); + + pView->SetInsertMode( !bWasCursorOverwrite ); + } + UndoActionEnd( EDITUNDO_INSERT ); + } + else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT ) + { + DBG_ASSERT( mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" ); + if( mpIMEInfos ) + { + const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); + + if ( !pData->IsOnlyCursorChanged() ) + { + EditSelection aSel( mpIMEInfos->aPos ); + aSel.Max().GetIndex() = + aSel.Max().GetIndex() + mpIMEInfos->nLen; + aSel = DeleteSelected( aSel ); + aSel = ImpInsertText( aSel, pData->GetText() ); + + if ( mpIMEInfos->bWasCursorOverwrite ) + { + USHORT nOldIMETextLen = mpIMEInfos->nLen; + USHORT nNewIMETextLen = pData->GetText().Len(); + + if ( ( nOldIMETextLen > nNewIMETextLen ) && + ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // restore old characters + USHORT nRestore = nOldIMETextLen - nNewIMETextLen; + EditPaM aPaM( mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + ImpInsertText( aPaM, mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) ); + } + else if ( ( nOldIMETextLen < nNewIMETextLen ) && + ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // overwrite + USHORT nOverwrite = nNewIMETextLen - nOldIMETextLen; + if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.Len() ) + nOverwrite = mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen; + DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" ); + EditPaM aPaM( mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + EditSelection _aSel( aPaM ); + _aSel.Max().GetIndex() = + _aSel.Max().GetIndex() + nOverwrite; + DeleteSelected( _aSel ); + } + } + if ( pData->GetTextAttr() ) + { + mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() ); + mpIMEInfos->bCursor = pData->IsCursorVisible(); + } + else + { + mpIMEInfos->DestroyAttribs(); + mpIMEInfos->nLen = pData->GetText().Len(); + } + + ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); + pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex(), 0 ); + FormatAndUpdate( pView ); + } + + EditSelection aNewSel = EditPaM( mpIMEInfos->aPos.GetNode(), mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); + pView->SetSelection( CreateESel( aNewSel ) ); + pView->SetInsertMode( !pData->IsCursorOverwrite() ); + + if ( pData->IsCursorVisible() ) + pView->ShowCursor(); + else + pView->HideCursor(); + } + } + else if ( rCEvt.GetCommand() == COMMAND_INPUTCONTEXTCHANGE ) + { + } + else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS ) + { + if ( mpIMEInfos && mpIMEInfos->nLen ) + { + EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() ); + Rectangle aR1 = PaMtoEditCursor( aPaM, 0 ); + + USHORT nInputEnd = mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen; + + if ( !IsFormatted() ) + FormatDoc(); + + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) ); + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_True ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + if ( pLine && ( nInputEnd > pLine->GetEnd() ) ) + nInputEnd = pLine->GetEnd(); + Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), GETCRSR_ENDOFLINE ); + Rectangle aRect = pView->GetImpEditView()->GetWindowPos( aR1 ); + pView->GetWindow()->SetCursorRect( &aRect, aR2.Left()-aR1.Right() ); + } + else + { + pView->GetWindow()->SetCursorRect(); + } + } + else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE ) + { + const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData(); + + ESelection aSelection = pView->GetSelection(); + aSelection.Adjust(); + + if( pView->HasSelection() ) + { + aSelection.nEndPos = aSelection.nStartPos; + aSelection.nStartPos += pData->GetStart(); + aSelection.nEndPos += pData->GetEnd(); + } + else + { + aSelection.nStartPos = pData->GetStart(); + aSelection.nEndPos = pData->GetEnd(); + } + pView->SetSelection( aSelection ); + } + else if ( rCEvt.GetCommand() == COMMAND_PREPARERECONVERSION ) + { + if ( pView->HasSelection() ) + { + ESelection aSelection = pView->GetSelection(); + aSelection.Adjust(); + + if ( aSelection.nStartPara != aSelection.nEndPara ) + { + xub_StrLen aParaLen = pEditEngine->GetTextLen( aSelection.nStartPara ); + aSelection.nEndPara = aSelection.nStartPara; + aSelection.nEndPos = aParaLen; + pView->SetSelection( aSelection ); + } + } + } + + GetSelEngine().Command( rCEvt ); +} + +BOOL ImpEditEngine::MouseButtonUp( const MouseEvent& rMEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + GetSelEngine().SelMouseButtonUp( rMEvt ); + bInSelection = FALSE; + // Sonderbehandlungen + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + if ( !aCurSel.HasRange() ) + { + if ( ( rMEvt.GetClicks() == 1 ) && rMEvt.IsLeft() && !rMEvt.IsMod2() ) + { + const SvxFieldItem* pFld = pView->GetFieldUnderMousePointer(); + if ( pFld ) + { + EditPaM aPaM( aCurSel.Max() ); + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + GetEditEnginePtr()->FieldClicked( *pFld, nPara, aPaM.GetIndex() ); + } + } + } + return TRUE; +} + +BOOL ImpEditEngine::MouseMove( const MouseEvent& rMEvt, EditView* pView ) +{ + // MouseMove wird sofort nach ShowQuickHelp() gerufen! +// if ( GetAutoCompleteText().Len() ) +// SetAutoCompleteText( String(), TRUE ); + GetSelEngine().SetCurView( pView ); + GetSelEngine().SelMouseMove( rMEvt ); + return TRUE; +} + +EditPaM ImpEditEngine::InsertText( EditSelection aSel, const XubString& rStr ) +{ + EditPaM aPaM = ImpInsertText( aSel, rStr ); + return aPaM; +} + +EditPaM ImpEditEngine::Clear() +{ + InitDoc( FALSE ); + + EditPaM aPaM = aEditDoc.GetStartPaM(); + EditSelection aSel( aPaM ); + + nCurTextHeight = 0; + + ResetUndoManager(); + + for ( USHORT nView = aEditViews.Count(); nView; ) + { + EditView* pView = aEditViews[--nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( aSel ); + } + + return aPaM; +} + +EditPaM ImpEditEngine::RemoveText() +{ + InitDoc( TRUE ); + + EditPaM aStartPaM = aEditDoc.GetStartPaM(); + EditSelection aEmptySel( aStartPaM, aStartPaM ); + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews.GetObject(nView); + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( aEmptySel ); + } + ResetUndoManager(); + return aEditDoc.GetStartPaM(); +} + + +void ImpEditEngine::SetText( const XubString& rText ) +{ + // RemoveText loescht die Undo-Liste! + EditPaM aStartPaM = RemoveText(); + BOOL bUndoCurrentlyEnabled = IsUndoEnabled(); + // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden. + EnableUndo( FALSE ); + + EditSelection aEmptySel( aStartPaM, aStartPaM ); + EditPaM aPaM = aStartPaM; + if ( rText.Len() ) + aPaM = ImpInsertText( aEmptySel, rText ); + + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) ); + // Wenn kein Text, dann auch Kein Format&Update + // => Der Text bleibt stehen. + if ( !rText.Len() && GetUpdateMode() ) + { + Rectangle aTmpRec( pView->GetOutputArea().TopLeft(), + Size( aPaperSize.Width(), nCurTextHeight ) ); + aTmpRec.Intersection( pView->GetOutputArea() ); + pView->GetWindow()->Invalidate( aTmpRec ); + } + } + if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht. + nCurTextHeight = 0; + EnableUndo( bUndoCurrentlyEnabled ); +#ifndef SVX_LIGHT + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" ); +#endif +} + + +const SfxItemSet& ImpEditEngine::GetEmptyItemSet() +{ + if ( !pEmptyItemSet ) + { + pEmptyItemSet = new SfxItemSet( aEditDoc.GetItemPool(), EE_ITEMS_START, EE_ITEMS_END ); + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + pEmptyItemSet->ClearItem( nWhich ); + } + } + return *pEmptyItemSet; +} + +// ---------------------------------------------------------------------- +// MISC +// ---------------------------------------------------------------------- +void ImpEditEngine::CursorMoved( ContentNode* pPrevNode ) +{ + // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer! + if ( pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len() ) + pPrevNode->GetCharAttribs().DeleteEmptyAttribs( aEditDoc.GetItemPool() ); +} + +void ImpEditEngine::TextModified() +{ + bFormatted = FALSE; + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTMODIFIED ); + aNotify.pEditEngine = GetEditEnginePtr(); + CallNotify( aNotify ); + } +} + + +void ImpEditEngine::ParaAttribsChanged( ContentNode* pNode ) +{ + DBG_ASSERT( pNode, "ParaAttribsChanged: Welcher?" ); + + aEditDoc.SetModified( TRUE ); + bFormatted = FALSE; + + ParaPortion* pPortion = FindParaPortion( pNode ); + DBG_ASSERT( pPortion, "ParaAttribsChanged: Portion?" ); + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); + + USHORT nPara = aEditDoc.GetPos( pNode ); + pEditEngine->ParaAttribsChanged( nPara ); + + ParaPortion* pNextPortion = GetParaPortions().SaveGetObject( nPara+1 ); + // => wird sowieso noch formatiert, wenn Invalid. + if ( pNextPortion && !pNextPortion->IsInvalid() ) + CalcHeight( pNextPortion ); +} + +// ---------------------------------------------------------------------- +// Cursorbewegungen +// ---------------------------------------------------------------------- + +EditSelection ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView ) +{ + // Eigentlich nur bei Up/Down noetig, aber was solls. + CheckIdleFormatter(); + + EditPaM aPaM( pEditView->pImpEditView->GetEditSelection().Max() ); + + EditPaM aOldPaM( aPaM ); + + TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom; + if ( IsVertical() ) + eTextDirection = TextDirectionality_TopToBottom_RightToLeft; + else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM.GetNode() ) ) ) + eTextDirection = TextDirectionality_RightToLeft_TopToBottom; + + KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); + + BOOL bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? TRUE : FALSE; + USHORT nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); + + if ( DoVisualCursorTraveling( aPaM.GetNode() ) ) + { + // Only for simple cursor movement... + if ( !bCtrl && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) ) + { + aPaM = CursorVisualLeftRight( pEditView, aPaM, rKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL, rKeyEvent.GetKeyCode().GetCode() == KEY_LEFT ); + nCode = 0; // skip switch statement + } + /* + else if ( !bCtrl && ( ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) ) + { + aPaM = CursorVisualStartEnd( pEditView, aPaM, nCode == KEY_HOME ); + nCode = 0; // skip switch statement + } + */ + } + + bool bKeyModifySelection = aTranslatedKeyEvent.GetKeyCode().IsShift(); + switch ( nCode ) + { + case KEY_UP: aPaM = CursorUp( aPaM, pEditView ); + break; + case KEY_DOWN: aPaM = CursorDown( aPaM, pEditView ); + break; + case KEY_LEFT: aPaM = bCtrl ? WordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); + break; + case KEY_RIGHT: aPaM = bCtrl ? WordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); + break; + case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); + break; + case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); + break; + case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM, pEditView ); + break; + case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM, pEditView ); + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + aPaM = CursorStartOfLine( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + aPaM = CursorEndOfLine( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + aPaM = WordLeft( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + aPaM = WordRight( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + aPaM = CursorStartOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorStartOfParagraph( aPaM ); + } + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + aPaM = CursorEndOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorEndOfParagraph( aPaM ); + } + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + aPaM = CursorStartOfDoc(); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + aPaM = CursorEndOfDoc(); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + aPaM = CursorStartOfLine( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + aPaM = CursorEndOfLine( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_BACKWARD: + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_FORWARD: + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + aPaM = WordLeft( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + aPaM = WordRight( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + aPaM = CursorStartOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorStartOfParagraph( aPaM ); + } + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + aPaM = CursorEndOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorEndOfParagraph( aPaM ); + } + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + aPaM = CursorStartOfDoc(); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + aPaM = CursorEndOfDoc(); + bKeyModifySelection = true; + break; + } + + if ( aOldPaM != aPaM ) + { + CursorMoved( aOldPaM.GetNode() ); + if ( aStatus.NotifyCursorMovements() && ( aOldPaM.GetNode() != aPaM.GetNode() ) ) + { + aStatus.GetStatusWord() = aStatus.GetStatusWord() | EE_STAT_CRSRLEFTPARA; + aStatus.GetPrevParagraph() = aEditDoc.GetPos( aOldPaM.GetNode() ); + } + } + else + aStatus.GetStatusWord() = aStatus.GetStatusWord() | EE_STAT_CRSRMOVEFAIL; + + // Bewirkt evtl. ein CreateAnchor oder Deselection all + aSelEngine.SetCurView( pEditView ); + aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); + EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() ); + pEditView->pImpEditView->GetEditSelection().Max() = aPaM; + if ( bKeyModifySelection ) + { + // Dann wird die Selektion erweitert... + EditSelection aTmpNewSel( aOldEnd, aPaM ); + pEditView->pImpEditView->DrawSelection( aTmpNewSel ); + } + else + pEditView->pImpEditView->GetEditSelection().Min() = aPaM; + + return pEditView->pImpEditView->GetEditSelection(); +} + +EditPaM ImpEditEngine::CursorVisualStartEnd( EditView* pEditView, const EditPaM& rPaM, BOOL bStart ) +{ + EditPaM aPaM( rPaM ); + + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_False ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + BOOL bEmptyLine = pLine->GetStart() == pLine->GetEnd(); + + pEditView->pImpEditView->nExtraCursorFlags = 0; + + if ( !bEmptyLine ) + { + String aLine( *aPaM.GetNode(), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); +// USHORT nPosInLine = aPaM.GetIndex() - pLine->GetStart(); + + const sal_Unicode* pLineString = aLine.GetBuffer(); + + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aLine.Len(), 0, &nError ); + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), aLine.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + + USHORT nVisPos = bStart ? 0 : aLine.Len()-1; + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + + ubidi_close( pBidi ); + + aPaM.GetIndex() = nLogPos + pLine->GetStart(); + + USHORT nTmp; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTmp, TRUE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); +// BOOL bParaRTL = IsRightToLeft( nPara ); + BOOL bPortionRTL = nRTLLevel%2 ? TRUE : FALSE; + + if ( bStart ) + { + pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 0 : 1 ); + // Maybe we must be *behind* the character + if ( bPortionRTL && pEditView->IsInsertMode() ) + aPaM.GetIndex()++; + } + else + { + pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 1 : 0 ); + if ( !bPortionRTL && pEditView->IsInsertMode() ) + aPaM.GetIndex()++; + } + } + + return aPaM; +} + +EditPaM ImpEditEngine::CursorVisualLeftRight( EditView* pEditView, const EditPaM& rPaM, USHORT nCharacterIteratorMode, BOOL bVisualToLeft ) +{ + EditPaM aPaM( rPaM ); + + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_False ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + BOOL bEmptyLine = pLine->GetStart() == pLine->GetEnd(); + +// USHORT nCurrentCursorFlags = pEditView->pImpEditView->nExtraCursorFlags; + pEditView->pImpEditView->nExtraCursorFlags = 0; + + BOOL bParaRTL = IsRightToLeft( nPara ); + + BOOL bDone = FALSE; + + if ( bEmptyLine ) + { + if ( bVisualToLeft ) + { + aPaM = CursorUp( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, FALSE ); + } + else + { + aPaM = CursorDown( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, TRUE ); + } + + bDone = TRUE; + } + + BOOL bLogicalBackward = bParaRTL ? !bVisualToLeft : bVisualToLeft; + + if ( !bDone && pEditView->IsInsertMode() ) + { + // Check if we are within a portion and don't have overwrite mode, then it's easy... + USHORT nPortionStart; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, FALSE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + + BOOL bPortionBoundary = ( aPaM.GetIndex() == nPortionStart ) || ( aPaM.GetIndex() == (nPortionStart+pTextPortion->GetLen()) ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); + + // Portion boundary doesn't matter if both have same RTL level + USHORT nRTLLevelNextPortion = 0xFFFF; + if ( bPortionBoundary && aPaM.GetIndex() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) + { + USHORT nTmp; + USHORT nNextTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex()+1, nTmp, bLogicalBackward ? FALSE : TRUE ); + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nNextTextPortion ); + nRTLLevelNextPortion = pNextTextPortion->GetRightToLeft(); + } + + if ( !bPortionBoundary || ( nRTLLevel == nRTLLevelNextPortion ) ) + { + if ( ( bVisualToLeft && !(nRTLLevel%2) ) || ( !bVisualToLeft && (nRTLLevel%2) ) ) + { + aPaM = CursorLeft( aPaM, nCharacterIteratorMode ); + pEditView->pImpEditView->SetCursorBidiLevel( 1 ); + } + else + { + aPaM = CursorRight( aPaM, nCharacterIteratorMode ); + pEditView->pImpEditView->SetCursorBidiLevel( 0 ); + } + bDone = TRUE; + } + } + + if ( !bDone ) + { + BOOL bGotoStartOfNextLine = FALSE; + BOOL bGotoEndOfPrevLine = FALSE; + + String aLine( *aPaM.GetNode(), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); + USHORT nPosInLine = aPaM.GetIndex() - pLine->GetStart(); + + const sal_Unicode* pLineString = aLine.GetBuffer(); + + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aLine.Len(), 0, &nError ); + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), aLine.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + + if ( !pEditView->IsInsertMode() ) + { + BOOL bEndOfLine = nPosInLine == aLine.Len(); + USHORT nVisPos = (USHORT)ubidi_getVisualIndex( pBidi, !bEndOfLine ? nPosInLine : nPosInLine-1, &nError ); + if ( bVisualToLeft ) + { + bGotoEndOfPrevLine = nVisPos == 0; + if ( !bEndOfLine ) + nVisPos--; + } + else + { + bGotoStartOfNextLine = nVisPos == (aLine.Len() - 1); + if ( !bEndOfLine ) + nVisPos++; + } + + if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) + { + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + aPaM.GetIndex() = pLine->GetStart() + nLogPos; + pEditView->pImpEditView->SetCursorBidiLevel( 0 ); + } + } + else + { + BOOL bWasBehind = FALSE; + BOOL bBeforePortion = !nPosInLine || pEditView->pImpEditView->GetCursorBidiLevel() == 1; + if ( nPosInLine && ( !bBeforePortion ) ) // before the next portion + bWasBehind = TRUE; // step one back, otherwise visual will be unusable when rtl portion follows. + + USHORT nPortionStart; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, bBeforePortion ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + BOOL bRTLPortion = (pTextPortion->GetRightToLeft() % 2) != 0; + + // -1: We are 'behind' the character + long nVisPos = (long)ubidi_getVisualIndex( pBidi, bWasBehind ? nPosInLine-1 : nPosInLine, &nError ); + if ( bVisualToLeft ) + { + if ( !bWasBehind || bRTLPortion ) + nVisPos--; + } + else + { + if ( bWasBehind || bRTLPortion || bBeforePortion ) + nVisPos++; +// if ( bWasBehind && bRTLPortion ) +// nVisPos++; + } + + bGotoEndOfPrevLine = nVisPos < 0; + bGotoStartOfNextLine = nVisPos >= aLine.Len(); + + if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) + { + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + +/* + if ( nLogPos == aPaM.GetIndex() ) + { + if ( bVisualToLeft ) + bGotoEndOfPrevLine = TRUE; + else + bGotoStartOfNextLine = TRUE; + } + else +*/ + { + aPaM.GetIndex() = pLine->GetStart() + nLogPos; + + // RTL portion, stay visually on the left side. + USHORT _nPortionStart; + // USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, !bRTLPortion ); + USHORT _nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), _nPortionStart, TRUE ); + TextPortion* _pTextPortion = pParaPortion->GetTextPortions().GetObject( _nTextPortion ); + if ( bVisualToLeft && !bRTLPortion && ( _pTextPortion->GetRightToLeft() % 2 ) ) + aPaM.GetIndex()++; + else if ( !bVisualToLeft && bRTLPortion && ( bWasBehind || !(_pTextPortion->GetRightToLeft() % 2 )) ) + aPaM.GetIndex()++; + + pEditView->pImpEditView->SetCursorBidiLevel( _nPortionStart ); + } + } + } + + ubidi_close( pBidi ); + + if ( bGotoEndOfPrevLine ) + { + aPaM = CursorUp( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, FALSE ); + } + else if ( bGotoStartOfNextLine ) + { + aPaM = CursorDown( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, TRUE ); + } + } + return aPaM; +} + + +EditPaM ImpEditEngine::CursorLeft( const EditPaM& rPaM, USHORT nCharacterIteratorMode ) +{ + EditPaM aCurPaM( rPaM ); + EditPaM aNewPaM( aCurPaM ); + + if ( aCurPaM.GetIndex() ) + { + sal_Int32 nCount = 1; + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + aNewPaM.SetIndex( (USHORT)_xBI->previousCharacters( *aNewPaM.GetNode(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount ) ); + } + else + { + ContentNode* pNode = aCurPaM.GetNode(); + pNode = GetPrevVisNode( pNode ); + if ( pNode ) + { + aNewPaM.SetNode( pNode ); + aNewPaM.SetIndex( pNode->Len() ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorRight( const EditPaM& rPaM, USHORT nCharacterIteratorMode ) +{ + EditPaM aCurPaM( rPaM ); + EditPaM aNewPaM( aCurPaM ); + + if ( aCurPaM.GetIndex() < aCurPaM.GetNode()->Len() ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int32 nCount = 1; + aNewPaM.SetIndex( (USHORT)_xBI->nextCharacters( *aNewPaM.GetNode(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount ) ); + } + else + { + ContentNode* pNode = aCurPaM.GetNode(); + pNode = GetNextVisNode( pNode ); + if ( pNode ) + { + aNewPaM.SetNode( pNode ); + aNewPaM.SetIndex( 0 ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView* pView ) +{ + DBG_ASSERT( pView, "Keine View - Keine Cursorbewegung!" ); + + ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPPortion, "Keine passende Portion gefunden: CursorUp" ); + USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + + long nX; + if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW ) + { + nX = GetXPos( pPPortion, pLine, rPaM.GetIndex() ); + pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; + } + else + nX = pView->pImpEditView->nTravelXPos; + + EditPaM aNewPaM( rPaM ); + if ( nLine ) // gleicher Absatz + { + EditLine* pPrevLine = pPPortion->GetLines().GetObject(nLine-1); + aNewPaM.SetIndex( GetChar( pPPortion, pPrevLine, nX ) ); + // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das + // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang + // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor + if ( aNewPaM.GetIndex() && ( aNewPaM.GetIndex() == pLine->GetStart() ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else // vorheriger Absatz + { + ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion ); + if ( pPrevPortion ) + { + pLine = pPrevPortion->GetLines().GetObject( pPrevPortion->GetLines().Count()-1 ); + DBG_ASSERT( pLine, "Zeile davor nicht gefunden: CursorUp" ); + aNewPaM.SetNode( pPrevPortion->GetNode() ); + aNewPaM.SetIndex( GetChar( pPrevPortion, pLine, nX+nOnePixelInRef ) ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView* pView ) +{ + DBG_ASSERT( pView, "Keine View - Keine Cursorbewegung!" ); + + ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPPortion, "Keine passende Portion gefunden: CursorDown" ); + USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); + + long nX; + if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW ) + { + EditLine* pLine = pPPortion->GetLines().GetObject(nLine); + nX = GetXPos( pPPortion, pLine, rPaM.GetIndex() ); + pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; + } + else + nX = pView->pImpEditView->nTravelXPos; + + EditPaM aNewPaM( rPaM ); + if ( nLine < pPPortion->GetLines().Count()-1 ) + { + EditLine* pNextLine = pPPortion->GetLines().GetObject(nLine+1); + aNewPaM.SetIndex( GetChar( pPPortion, pNextLine, nX ) ); + // Sonderbehandlung siehe CursorUp... + if ( ( aNewPaM.GetIndex() == pNextLine->GetEnd() ) && ( aNewPaM.GetIndex() > pNextLine->GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else // naechster Absatz + { + ParaPortion* pNextPortion = GetNextVisPortion( pPPortion ); + if ( pNextPortion ) + { + EditLine* pLine = pNextPortion->GetLines().GetObject(0); + DBG_ASSERT( pLine, "Zeile davor nicht gefunden: CursorUp" ); + aNewPaM.SetNode( pNextPortion->GetNode() ); + // Nie ganz ans Ende wenn mehrere Zeilen, da dann eine + // Zeile darunter der Cursor angezeigt wird. + aNewPaM.SetIndex( GetChar( pNextPortion, pLine, nX+nOnePixelInRef ) ); + if ( ( aNewPaM.GetIndex() == pLine->GetEnd() ) && ( aNewPaM.GetIndex() > pLine->GetStart() ) && ( pNextPortion->GetLines().Count() > 1 ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM ) +{ + ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pCurPortion, "Keine Portion fuer den PaM ?" ); + USHORT nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pCurPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "Aktuelle Zeile nicht gefunden ?!" ); + + EditPaM aNewPaM( rPaM ); + aNewPaM.SetIndex( pLine->GetStart() ); + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM ) +{ + ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pCurPortion, "Keine Portion fuer den PaM ?" ); + USHORT nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pCurPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "Aktuelle Zeile nicht gefunden ?!" ); + + EditPaM aNewPaM( rPaM ); + aNewPaM.SetIndex( pLine->GetEnd() ); + if ( pLine->GetEnd() > pLine->GetStart() ) + { +// xub_Unicode cLastChar = aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex()-1 ); + if ( aNewPaM.GetNode()->IsFeature( aNewPaM.GetIndex() - 1 ) ) + { + // Bei einem weichen Umbruch muss ich davor stehen! + EditCharAttrib* pNextFeature = aNewPaM.GetNode()->GetCharAttribs().FindFeature( aNewPaM.GetIndex()-1 ); + if ( pNextFeature && ( pNextFeature->GetItem()->Which() == EE_FEATURE_LINEBR ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else if ( ( aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex() - 1 ) == ' ' ) && ( aNewPaM.GetIndex() != aNewPaM.GetNode()->Len() ) ) + { + // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn, + // davor zu stehen, da der Anwender hinter das Wort will. + // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End! + aNewPaM = CursorLeft( aNewPaM ); + } + } + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorStartOfParagraph( const EditPaM& rPaM ) +{ + EditPaM aPaM( rPaM.GetNode(), 0 ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorEndOfParagraph( const EditPaM& rPaM ) +{ + EditPaM aPaM( rPaM.GetNode(), rPaM.GetNode()->Len() ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorStartOfDoc() +{ + EditPaM aPaM( aEditDoc.SaveGetObject( 0 ), 0 ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorEndOfDoc() +{ + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + ParaPortion* pLastPortion = GetParaPortions().SaveGetObject( aEditDoc.Count()-1 ); + DBG_ASSERT( pLastNode && pLastPortion, "CursorEndOfDoc: Node oder Portion nicht gefunden" ); + + if ( !pLastPortion->IsVisible() ) + { + pLastNode = GetPrevVisNode( pLastPortion->GetNode() ); + DBG_ASSERT( pLastNode, "Kein sichtbarer Absatz?" ); + if ( !pLastNode ) + pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + } + + EditPaM aPaM( pLastNode, pLastNode->Len() ); + return aPaM; +} + +EditPaM ImpEditEngine::PageUp( const EditPaM& rPaM, EditView* pView ) +{ + Rectangle aRec = PaMtoEditCursor( rPaM ); + Point aTopLeft = aRec.TopLeft(); + aTopLeft.Y() -= pView->GetVisArea().GetHeight() *9/10; + aTopLeft.X() += nOnePixelInRef; + if ( aTopLeft.Y() < 0 ) + { + aTopLeft.Y() = 0; + } + return GetPaM( aTopLeft ); +} + +EditPaM ImpEditEngine::PageDown( const EditPaM& rPaM, EditView* pView ) +{ + Rectangle aRec = PaMtoEditCursor( rPaM ); + Point aBottomRight = aRec.BottomRight(); + aBottomRight.Y() += pView->GetVisArea().GetHeight() *9/10; + aBottomRight.X() += nOnePixelInRef; + long nHeight = GetTextHeight(); + if ( aBottomRight.Y() > nHeight ) + { + aBottomRight.Y() = nHeight-2; + } + return GetPaM( aBottomRight ); +} + +EditPaM ImpEditEngine::WordLeft( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + USHORT nCurrentPos = rPaM.GetIndex(); + EditPaM aNewPaM( rPaM ); + if ( nCurrentPos == 0 ) + { + // Vorheriger Absatz... + USHORT nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); + ContentNode* pPrevNode = aEditDoc.SaveGetObject( --nCurPara ); + if ( pPrevNode ) + { + aNewPaM.SetNode( pPrevNode ); + aNewPaM.SetIndex( pPrevNode->Len() ); + } + } + else + { + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *aNewPaM.GetNode(), nCurrentPos, aLocale, nWordType, sal_True ); + if ( aBoundary.startPos >= nCurrentPos ) + aBoundary = _xBI->previousWord( *aNewPaM.GetNode(), nCurrentPos, aLocale, nWordType ); + aNewPaM.SetIndex( ( aBoundary.startPos != (-1) ) ? (USHORT)aBoundary.startPos : 0 ); + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::WordRight( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + xub_StrLen nMax = rPaM.GetNode()->Len(); + EditPaM aNewPaM( rPaM ); + if ( aNewPaM.GetIndex() < nMax ) + { + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->nextWord( *aNewPaM.GetNode(), aNewPaM.GetIndex(), aLocale, nWordType ); + aNewPaM.SetIndex( (USHORT)aBoundary.startPos ); + } + // not 'else', maybe the index reached nMax now... + if ( aNewPaM.GetIndex() >= nMax ) + { + // Naechster Absatz... + USHORT nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); + ContentNode* pNextNode = aEditDoc.SaveGetObject( ++nCurPara ); + if ( pNextNode ) + { + aNewPaM.SetNode( pNextNode ); + aNewPaM.SetIndex( 0 ); + } + } + return aNewPaM; +} + +EditPaM ImpEditEngine::StartOfWord( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + EditPaM aNewPaM( rPaM ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *rPaM.GetNode(), rPaM.GetIndex(), aLocale, nWordType, sal_True ); + aNewPaM.SetIndex( (USHORT)aBoundary.startPos ); + return aNewPaM; +} + +EditPaM ImpEditEngine::EndOfWord( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + EditPaM aNewPaM( rPaM ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *rPaM.GetNode(), rPaM.GetIndex(), aLocale, nWordType, sal_True ); + aNewPaM.SetIndex( (USHORT)aBoundary.endPos ); + return aNewPaM; +} + +EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, BOOL bAcceptStartOfWord ) +{ + EditSelection aNewSel( rCurSel ); + EditPaM aPaM( rCurSel.Max() ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aPaM ); + xub_StrLen nMax = aPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int16 nType = _xBI->getWordType( *aPaM.GetNode(), aPaM.GetIndex(), aLocale ); + if ( nType == i18n::WordType::ANY_WORD ) + { + i18n::Boundary aBoundary = _xBI->getWordBoundary( *aPaM.GetNode(), aPaM.GetIndex(), aLocale, nWordType, sal_True ); + // don't select when curser at end of word + if ( ( aBoundary.endPos > aPaM.GetIndex() ) && + ( ( aBoundary.startPos < aPaM.GetIndex() ) || ( bAcceptStartOfWord && ( aBoundary.startPos == aPaM.GetIndex() ) ) ) ) + { + aNewSel.Min().SetIndex( (USHORT)aBoundary.startPos ); + aNewSel.Max().SetIndex( (USHORT)aBoundary.endPos ); + } + } + + return aNewSel; +} + +EditSelection ImpEditEngine::SelectSentence( const EditSelection& rCurSel ) +{ + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + const EditPaM& rPaM = rCurSel.Min(); + const ContentNode* pNode = rPaM.GetNode(); + // #i50710# line breaks are marked with 0x01 - the break iterator prefers 0x0a for that + String sParagraph(*pNode); + sParagraph.SearchAndReplaceAll(0x01,0x0a); + //return Null if search starts at the beginning of the string + long nStart = rPaM.GetIndex() ? _xBI->beginOfSentence( sParagraph, rPaM.GetIndex(), GetLocale( rPaM ) ) : 0; + + long nEnd = _xBI->endOfSentence( *pNode, rPaM.GetIndex(), GetLocale( rPaM ) ); + EditSelection aNewSel( rCurSel ); + DBG_ASSERT(nStart < pNode->Len() && nEnd <= pNode->Len(), "sentence indices out of range"); + aNewSel.Min().SetIndex( (USHORT)nStart ); + aNewSel.Max().SetIndex( (USHORT)nEnd ); + return aNewSel; +} + +sal_Bool ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const +{ + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + if (!pCTLOptions) + pCTLOptions = new SvtCTLOptions; + + // get the index that really is first + USHORT nFirstPos = rCurSel.Min().GetIndex(); + USHORT nMaxPos = rCurSel.Max().GetIndex(); + if (nMaxPos < nFirstPos) + nFirstPos = nMaxPos; + + sal_Bool bIsSequenceChecking = + pCTLOptions->IsCTLFontEnabled() && + pCTLOptions->IsCTLSequenceChecking() && + nFirstPos != 0 && /* first char needs not to be checked */ + _xBI.is() && i18n::ScriptType::COMPLEX == _xBI->getScriptType( rtl::OUString( nChar ), 0 ); + + return bIsSequenceChecking; +} + +/************************************************************************* + * lcl_HasStrongLTR + *************************************************************************/ + bool lcl_HasStrongLTR ( const String& rTxt, xub_StrLen nStart, xub_StrLen nEnd ) + { + for ( xub_StrLen nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx ) + { + const UCharDirection nCharDir = u_charDirection ( rTxt.GetChar ( nCharIdx )); + if ( nCharDir == U_LEFT_TO_RIGHT || + nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || + nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) + return true; + } + return false; + } + + + +void ImpEditEngine::InitScriptTypes( USHORT nPara ) +{ + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + rTypes.Remove( 0, rTypes.Count() ); + +// pParaPortion->aExtraCharInfos.Remove( 0, pParaPortion->aExtraCharInfos.Count() ); + + ContentNode* pNode = pParaPortion->GetNode(); + if ( pNode->Len() ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + + String aText( *pNode ); + + // To handle fields put the character from the field in the string, + // because endOfScript( ... ) will skip the CH_FEATURE, because this is WEAK + EditCharAttrib* pField = pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, 0 ); + while ( pField ) + { + ::rtl::OUString aFldText( ((EditCharAttribField*)pField)->GetFieldValue() ); + if ( aFldText.getLength() ) + { + aText.SetChar( pField->GetStart(), aFldText.getStr()[0] ); + short nFldScriptType = _xBI->getScriptType( aFldText, 0 ); + + for ( USHORT nCharInField = 1; nCharInField < aFldText.getLength(); nCharInField++ ) + { + short nTmpType = _xBI->getScriptType( aFldText, nCharInField ); + + // First char from field wins... + if ( nFldScriptType == i18n::ScriptType::WEAK ) + { + nFldScriptType = nTmpType; + aText.SetChar( pField->GetStart(), aFldText.getStr()[nCharInField] ); + } + + // ... but if the first one is LATIN, and there are CJK or CTL chars too, + // we prefer that ScripType because we need an other font. + if ( ( nTmpType == i18n::ScriptType::ASIAN ) || ( nTmpType == i18n::ScriptType::COMPLEX ) ) + { + aText.SetChar( pField->GetStart(), aFldText.getStr()[nCharInField] ); + break; + } + } + } + // #112831# Last Field might go from 0xffff to 0x0000 + pField = pField->GetEnd() ? pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, pField->GetEnd() ) : NULL; + } + + ::rtl::OUString aOUText( aText ); + USHORT nTextLen = (USHORT)aOUText.getLength(); + + sal_Int32 nPos = 0; + short nScriptType = _xBI->getScriptType( aOUText, nPos ); + rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() ); + nPos = _xBI->endOfScript( aOUText, nPos, nScriptType ); + while ( ( nPos != (-1) ) && ( nPos < nTextLen ) ) + { + rTypes[rTypes.Count()-1].nEndPos = (USHORT)nPos; + + nScriptType = _xBI->getScriptType( aOUText, nPos ); + long nEndPos = _xBI->endOfScript( aOUText, nPos, nScriptType ); + + if ( ( nScriptType == i18n::ScriptType::WEAK ) || ( nScriptType == rTypes[rTypes.Count()-1].nScriptType ) ) + { + // Expand last ScriptTypePosInfo, don't create weak or unecessary portions + rTypes[rTypes.Count()-1].nEndPos = (USHORT)nEndPos; + } + else + { + if ( _xBI->getScriptType( aOUText, nPos - 1 ) == i18n::ScriptType::WEAK ) + { + switch ( u_charType(aOUText.iterateCodePoints(&nPos, 0) ) ) { + case U_NON_SPACING_MARK: + case U_ENCLOSING_MARK: + case U_COMBINING_SPACING_MARK: + --nPos; + rTypes[rTypes.Count()-1].nEndPos--; + break; + } + } + rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() ); + } + + nPos = nEndPos; + } + + if ( rTypes[0].nScriptType == i18n::ScriptType::WEAK ) + rTypes[0].nScriptType = ( rTypes.Count() > 1 ) ? rTypes[1].nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); + + // create writing direction information: + if ( !pParaPortion->aWritingDirectionInfos.Count() ) + InitWritingDirections( nPara ); + + // i89825: Use CTL font for numbers embedded into an RTL run: + WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; + for ( USHORT n = 0; n < rDirInfos.Count(); ++n ) + { + const xub_StrLen nStart = rDirInfos[n].nStartPos; + const xub_StrLen nEnd = rDirInfos[n].nEndPos; + const BYTE nCurrDirType = rDirInfos[n].nType; + + if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run + ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( aText, nStart, nEnd ) ) ) // non-strong text in embedded LTR run + { + USHORT nIdx = 0; + + // Skip entries in ScriptArray which are not inside the RTL run: + while ( nIdx < rTypes.Count() && rTypes[nIdx].nStartPos < nStart ) + ++nIdx; + + // Remove any entries *inside* the current run: + while ( nIdx < rTypes.Count() && rTypes[nIdx].nEndPos <= nEnd ) + rTypes.Remove( nIdx ); + + // special case: + if(nIdx < rTypes.Count() && rTypes[nIdx].nStartPos < nStart && rTypes[nIdx].nEndPos > nEnd) + { + rTypes.Insert( ScriptTypePosInfo( rTypes[nIdx].nScriptType, (USHORT)nEnd, rTypes[nIdx].nEndPos ), nIdx ); + rTypes[nIdx].nEndPos = nStart; + } + + if( nIdx ) + rTypes[nIdx - 1].nEndPos = nStart; + + rTypes.Insert( ScriptTypePosInfo( i18n::ScriptType::COMPLEX, (USHORT)nStart, (USHORT)nEnd), nIdx ); + ++nIdx; + + if( nIdx < rTypes.Count() ) + rTypes[nIdx].nStartPos = nEnd; + } + } + +#if OSL_DEBUG_LEVEL > 1 + USHORT nDebugStt = 0; + USHORT nDebugEnd = 0; + short nDebugType = 0; + for ( USHORT n = 0; n < rTypes.Count(); ++n ) + { + nDebugStt = rTypes[n].nStartPos; + nDebugEnd = rTypes[n].nEndPos; + nDebugType = rTypes[n].nScriptType; + } +#endif + } +} + +USHORT ImpEditEngine::GetScriptType( const EditPaM& rPaM, USHORT* pEndPos ) const +{ + USHORT nScriptType = 0; + + if ( pEndPos ) + *pEndPos = rPaM.GetNode()->Len(); + + if ( rPaM.GetNode()->Len() ) + { + USHORT nPara = GetEditDoc().GetPos( rPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + USHORT nPos = rPaM.GetIndex(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( ( rTypes[n].nStartPos <= nPos ) && ( rTypes[n].nEndPos >= nPos ) ) + { + nScriptType = rTypes[n].nScriptType; + if( pEndPos ) + *pEndPos = rTypes[n].nEndPos; + break; + } + } + } + return nScriptType ? nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); +} + +USHORT ImpEditEngine::GetScriptType( const EditSelection& rSel ) const +{ + EditSelection aSel( rSel ); + aSel.Adjust( aEditDoc ); + + short nScriptType = 0; + + USHORT nStartPara = GetEditDoc().GetPos( aSel.Min().GetNode() ); + USHORT nEndPara = GetEditDoc().GetPos( aSel.Max().GetNode() ); + + for ( USHORT nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + + // find the first(!) script type position that holds the + // complete selection. Thus it will work for selections as + // well as with just moving the cursor from char to char. + USHORT nS = ( nPara == nStartPara ) ? aSel.Min().GetIndex() : 0; + USHORT nE = ( nPara == nEndPara ) ? aSel.Max().GetIndex() : pParaPortion->GetNode()->Len(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if (rTypes[n].nStartPos <= nS && nE <= rTypes[n].nEndPos) + { + if ( rTypes[n].nScriptType != i18n::ScriptType::WEAK ) + { + nScriptType |= GetItemScriptType ( rTypes[n].nScriptType ); + } + else + { + if ( !nScriptType && n ) + { + // #93548# When starting with WEAK, use prev ScriptType... + nScriptType = rTypes[n-1].nScriptType; + } + } + break; + } + } + } + return nScriptType ? nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); +} + +BOOL ImpEditEngine::IsScriptChange( const EditPaM& rPaM ) const +{ + BOOL bScriptChange = FALSE; + + if ( rPaM.GetNode()->Len() ) + { + USHORT nPara = GetEditDoc().GetPos( rPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + USHORT nPos = rPaM.GetIndex(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( rTypes[n].nStartPos == nPos ) + { + bScriptChange = TRUE; + break; + } + } + } + return bScriptChange; +} + +BOOL ImpEditEngine::HasScriptType( USHORT nPara, USHORT nType ) const +{ + BOOL bTypeFound = FALSE; + + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT n = rTypes.Count(); n && !bTypeFound; ) + { + if ( rTypes[--n].nScriptType == nType ) + bTypeFound = TRUE; + } + return bTypeFound; +} + +void ImpEditEngine::InitWritingDirections( USHORT nPara ) +{ + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + WritingDirectionInfos& rInfos = pParaPortion->aWritingDirectionInfos; + rInfos.Remove( 0, rInfos.Count() ); + + BOOL bCTL = FALSE; + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( rTypes[n].nScriptType == i18n::ScriptType::COMPLEX ) + { + bCTL = TRUE; + break; + } + } + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + if ( ( bCTL || ( nBidiLevel == 1 /*RTL*/ ) ) && pParaPortion->GetNode()->Len() ) + { + + String aText( *pParaPortion->GetNode() ); + + // + // Bidi functions from icu 2.0 + // + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError ); + nError = U_ZERO_ERROR; + + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + nError = U_ZERO_ERROR; + + long nCount = ubidi_countRuns( pBidi, &nError ); + + int32_t nStart = 0; + int32_t nEnd; + UBiDiLevel nCurrDir; + + for ( USHORT nIdx = 0; nIdx < nCount; ++nIdx ) + { + ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir ); + rInfos.Insert( WritingDirectionInfo( nCurrDir, (USHORT)nStart, (USHORT)nEnd ), rInfos.Count() ); + nStart = nEnd; + } + + ubidi_close( pBidi ); + } + + // No infos mean no CTL and default dir is L2R... + if ( !rInfos.Count() ) + rInfos.Insert( WritingDirectionInfo( 0, 0, (USHORT)pParaPortion->GetNode()->Len() ), rInfos.Count() ); + +} + +BOOL ImpEditEngine::IsRightToLeft( USHORT nPara ) const +{ + BOOL bR2L = FALSE; + const SvxFrameDirectionItem* pFrameDirItem = NULL; + + if ( !IsVertical() ) + { + bR2L = GetDefaultHorizontalTextDirection() == EE_HTEXTDIR_R2L; + pFrameDirItem = &(const SvxFrameDirectionItem&)GetParaAttrib( nPara, EE_PARA_WRITINGDIR ); + if ( pFrameDirItem->GetValue() == FRMDIR_ENVIRONMENT ) + { + // #103045# if DefaultHorizontalTextDirection is set, use that value, otherwise pool default. + if ( GetDefaultHorizontalTextDirection() != EE_HTEXTDIR_DEFAULT ) + { + pFrameDirItem = NULL; // bR2L allready set to default horizontal text direction + } + else + { + // Use pool default + pFrameDirItem = &(const SvxFrameDirectionItem&)((ImpEditEngine*)this)->GetEmptyItemSet().Get( EE_PARA_WRITINGDIR ); + } + } + } + + if ( pFrameDirItem ) + bR2L = pFrameDirItem->GetValue() == FRMDIR_HORI_RIGHT_TOP; + + return bR2L; +} + +BOOL ImpEditEngine::HasDifferentRTLLevels( const ContentNode* pNode ) +{ + USHORT nPara = GetEditDoc().GetPos( (ContentNode*)pNode ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + BOOL bHasDifferentRTLLevels = FALSE; + + USHORT nRTLLevel = IsRightToLeft( nPara ) ? 1 : 0; + for ( USHORT n = 0; n < pParaPortion->GetTextPortions().Count(); n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( n ); + if ( pTextPortion->GetRightToLeft() != nRTLLevel ) + { + bHasDifferentRTLLevels = TRUE; + break; + } + } + return bHasDifferentRTLLevels; +} + + +BYTE ImpEditEngine::GetRightToLeft( USHORT nPara, USHORT nPos, USHORT* pStart, USHORT* pEnd ) +{ +// BYTE nRightToLeft = IsRightToLeft( nPara ) ? 1 : 0; + BYTE nRightToLeft = 0; + + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + if ( pNode && pNode->Len() ) + { + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aWritingDirectionInfos.Count() ) + InitWritingDirections( nPara ); + +// BYTE nType = 0; + WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; + for ( USHORT n = 0; n < rDirInfos.Count(); n++ ) + { + if ( ( rDirInfos[n].nStartPos <= nPos ) && ( rDirInfos[n].nEndPos >= nPos ) ) + { + nRightToLeft = rDirInfos[n].nType; + if ( pStart ) + *pStart = rDirInfos[n].nStartPos; + if ( pEnd ) + *pEnd = rDirInfos[n].nEndPos; + break; + } + } + } + return nRightToLeft; +} + +SvxAdjust ImpEditEngine::GetJustification( USHORT nPara ) const +{ + SvxAdjust eJustification = SVX_ADJUST_LEFT; + + if ( !aStatus.IsOutliner() ) + { + eJustification = ((const SvxAdjustItem&) GetParaAttrib( nPara, EE_PARA_JUST )).GetAdjust(); + + if ( IsRightToLeft( nPara ) ) + { + if ( eJustification == SVX_ADJUST_LEFT ) + eJustification = SVX_ADJUST_RIGHT; + else if ( eJustification == SVX_ADJUST_RIGHT ) + eJustification = SVX_ADJUST_LEFT; + } + } + return eJustification; +} + + +// ---------------------------------------------------------------------- +// Textaenderung +// ---------------------------------------------------------------------- + +void ImpEditEngine::ImpRemoveChars( const EditPaM& rPaM, USHORT nChars, EditUndoRemoveChars* pCurUndo ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + XubString aStr( rPaM.GetNode()->Copy( rPaM.GetIndex(), nChars ) ); + + // Pruefen, ob Attribute geloescht oder geaendert werden: + USHORT nStart = rPaM.GetIndex(); + USHORT nEnd = nStart + nChars; + CharAttribArray& rAttribs = rPaM.GetNode()->GetCharAttribs().GetAttribs(); +// USHORT nAttrs = rAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) ) + { +#ifndef SVX_LIGHT + EditSelection aSel( rPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + nChars; + EditUndoSetAttribs* pAttrUndo = CreateAttribUndo( aSel, GetEmptyItemSet() ); + InsertUndo( pAttrUndo ); +#endif + break; // for + } + } + if ( pCurUndo && ( CreateEditPaM( pCurUndo->GetEPaM() ) == rPaM ) ) + pCurUndo->GetStr() += aStr; +#ifndef SVX_LIGHT + else + InsertUndo( new EditUndoRemoveChars( this, CreateEPaM( rPaM ), aStr ) ); +#endif + } + + aEditDoc.RemoveChars( rPaM, nChars ); + TextModified(); +} + +EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, USHORT nNewPos ) +{ + aOldPositions.Justify(); + BOOL bValidAction = ( (long)nNewPos < aOldPositions.Min() ) || ( (long)nNewPos > aOldPositions.Max() ); + DBG_ASSERT( bValidAction, "Move in sich selbst ?" ); + DBG_ASSERT( aOldPositions.Max() <= (long)GetParaPortions().Count(), "Voll drueber weg: MoveParagraphs" ); + + EditSelection aSelection; + + if ( !bValidAction ) + { + aSelection = aEditDoc.GetStartPaM(); + return aSelection; + } + + ULONG nParaCount = GetParaPortions().Count(); + + if ( nNewPos >= nParaCount ) + nNewPos = GetParaPortions().Count(); + + // Height may change when moving first or last Paragraph + ParaPortion* pRecalc1 = NULL; + ParaPortion* pRecalc2 = NULL; + ParaPortion* pRecalc3 = NULL; + ParaPortion* pRecalc4 = NULL; + + if ( nNewPos == 0 ) // Move to Start + { + pRecalc1 = GetParaPortions().GetObject( 0 ); + pRecalc2 = GetParaPortions().GetObject( (USHORT)aOldPositions.Min() ); + + } + else if ( nNewPos == nParaCount ) + { + pRecalc1 = GetParaPortions().GetObject( (USHORT)(nParaCount-1) ); + pRecalc2 = GetParaPortions().GetObject( (USHORT)aOldPositions.Max() ); + } + + if ( aOldPositions.Min() == 0 ) // Move from Start + { + pRecalc3 = GetParaPortions().GetObject( 0 ); + pRecalc4 = GetParaPortions().GetObject( + sal::static_int_cast< USHORT >( aOldPositions.Max()+1 ) ); + } + else if ( (USHORT)aOldPositions.Max() == (nParaCount-1) ) + { + pRecalc3 = GetParaPortions().GetObject( (USHORT)aOldPositions.Max() ); + pRecalc4 = GetParaPortions().GetObject( (USHORT)(aOldPositions.Min()-1) ); + } + + MoveParagraphsInfo aMoveParagraphsInfo( sal::static_int_cast< USHORT >(aOldPositions.Min()), sal::static_int_cast< USHORT >(aOldPositions.Max()), nNewPos ); + aBeginMovingParagraphsHdl.Call( &aMoveParagraphsInfo ); + + if ( IsUndoEnabled() && !IsInUndo()) + InsertUndo( new EditUndoMoveParagraphs( this, aOldPositions, nNewPos ) ); + + // Position nicht aus dem Auge verlieren! + ParaPortion* pDestPortion = GetParaPortions().SaveGetObject( nNewPos ); + + ParaPortionList aTmpPortionList; + USHORT i; + for ( i = (USHORT)aOldPositions.Min(); i <= (USHORT)aOldPositions.Max(); i++ ) + { + // Immer aOldPositions.Min(), da Remove(). + ParaPortion* pTmpPortion = GetParaPortions().GetObject( (USHORT)aOldPositions.Min() ); + GetParaPortions().Remove( (USHORT)aOldPositions.Min() ); + aEditDoc.Remove( (USHORT)aOldPositions.Min() ); + aTmpPortionList.Insert( pTmpPortion, aTmpPortionList.Count() ); + } + + USHORT nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count(); + DBG_ASSERT( nRealNewPos != USHRT_MAX, "ImpMoveParagraphs: Ungueltige Position!" ); + + for ( i = 0; i < (USHORT)aTmpPortionList.Count(); i++ ) + { + ParaPortion* pTmpPortion = aTmpPortionList.GetObject( i ); + if ( i == 0 ) + aSelection.Min().SetNode( pTmpPortion->GetNode() ); + + aSelection.Max().SetNode( pTmpPortion->GetNode() ); + aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() ); + + ContentNode* pN = pTmpPortion->GetNode(); + aEditDoc.Insert( pN, nRealNewPos+i ); + + GetParaPortions().Insert( pTmpPortion, nRealNewPos+i ); + } + + aEndMovingParagraphsHdl.Call( &aMoveParagraphsInfo ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHSMOVED ); + aNotify.pEditEngine = GetEditEnginePtr(); + aNotify.nParagraph = nNewPos; + aNotify.nParam1 = sal::static_int_cast< USHORT >(aOldPositions.Min()); + aNotify.nParam2 = sal::static_int_cast< USHORT >(aOldPositions.Max()); + CallNotify( aNotify ); + } + + aEditDoc.SetModified( TRUE ); + + if ( pRecalc1 ) + CalcHeight( pRecalc1 ); + if ( pRecalc2 ) + CalcHeight( pRecalc2 ); + if ( pRecalc3 ) + CalcHeight( pRecalc3 ); + if ( pRecalc4 ) + CalcHeight( pRecalc4 ); + + aTmpPortionList.Remove( 0, aTmpPortionList.Count() ); // wichtig ! + +#ifdef EDITDEBUG + GetParaPortions().DbgCheck(aEditDoc); +#endif + return aSelection; +} + + +EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, BOOL bBackward ) +{ + DBG_ASSERT( pLeft != pRight, "Den gleichen Absatz zusammenfuegen ?" ); + DBG_ASSERT( aEditDoc.GetPos( pLeft ) != USHRT_MAX, "Einzufuegenden Node nicht gefunden(1)" ); + DBG_ASSERT( aEditDoc.GetPos( pRight ) != USHRT_MAX, "Einzufuegenden Node nicht gefunden(2)" ); + + USHORT nParagraphTobeDeleted = aEditDoc.GetPos( pRight ); + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pRight, nParagraphTobeDeleted ); + aDeletedNodes.Insert( pInf, aDeletedNodes.Count() ); + + GetEditEnginePtr()->ParagraphConnected( aEditDoc.GetPos( pLeft ), aEditDoc.GetPos( pRight ) ); + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + { + InsertUndo( new EditUndoConnectParas( this, + aEditDoc.GetPos( pLeft ), pLeft->Len(), + pLeft->GetContentAttribs().GetItems(), pRight->GetContentAttribs().GetItems(), + pLeft->GetStyleSheet(), pRight->GetStyleSheet(), bBackward ) ); + } +#endif + + if ( bBackward ) + { + pLeft->SetStyleSheet( pRight->GetStyleSheet(), TRUE ); + pLeft->GetContentAttribs().GetItems().Set( pRight->GetContentAttribs().GetItems() ); + pLeft->GetCharAttribs().GetDefFont() = pRight->GetCharAttribs().GetDefFont(); + } + + ParaAttribsChanged( pLeft ); + + // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg. + ParaPortion* pLeftPortion = FindParaPortion( pLeft ); + ParaPortion* pRightPortion = FindParaPortion( pRight ); + DBG_ASSERT( pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" ); + DBG_ASSERT( pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" ); + DBG_ASSERT( nParagraphTobeDeleted == GetParaPortions().GetPos( pRightPortion ), "NodePos != PortionPos?" ); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + { + xub_StrLen nEnd = pLeft->Len(); + xub_StrLen nInv = nEnd ? nEnd-1 : nEnd; + pLeft->GetWrongList()->ClearWrongs( nInv, 0xFFFF, pLeft ); // Evtl. einen wegnehmen + pLeft->GetWrongList()->MarkInvalid( nInv, nEnd+1 ); + // Falschgeschriebene Woerter ruebernehmen: + USHORT nRWrongs = pRight->GetWrongList()->Count(); + for ( USHORT nW = 0; nW < nRWrongs; nW++ ) + { + WrongRange aWrong = pRight->GetWrongList()->GetObject( nW ); + if ( aWrong.nStart != 0 ) // Nicht ein anschliessender + { + aWrong.nStart = aWrong.nStart + nEnd; + aWrong.nEnd = aWrong.nEnd + nEnd; + pLeft->GetWrongList()->InsertWrong( aWrong, pLeft->GetWrongList()->Count() ); + } + } + } +#endif + + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted ); + + EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight ); + GetParaPortions().Remove( nParagraphTobeDeleted ); + delete pRightPortion; + + pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->Len() ); + + // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht. + + if ( GetTextRanger() ) + { + // Durch das zusammenfuegen wird der linke zwar neu formatiert, aber + // wenn sich dessen Hoehe nicht aendert bekommt die Formatierung die + // Aenderung der Gesaamthoehe des Textes zu spaet mit... + for ( USHORT n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPP = GetParaPortions().GetObject( n ); + pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() ); + pPP->GetLines().Reset(); + } + } + + TextModified(); + + return aPaM; +} + +EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, BYTE nMode, BYTE nDelMode ) +{ + DBG_ASSERT( !EditSelection( rSel ).DbgIsBuggy( aEditDoc ), "Index im Wald in DeleteLeftOrRight" ); + + if ( rSel.HasRange() ) // dann nur Sel. loeschen + return ImpDeleteSelection( rSel ); + + const EditPaM aCurPos( rSel.Max() ); + EditPaM aDelStart( aCurPos ); + EditPaM aDelEnd( aCurPos ); + if ( nMode == DEL_LEFT ) + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aDelStart = CursorLeft( aCurPos, i18n::CharacterIteratorMode::SKIPCHARACTER ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + aDelStart = StartOfWord( aCurPos ); + if ( aDelStart.GetIndex() == aCurPos.GetIndex() ) + aDelStart = WordLeft( aCurPos ); + } + else // DELMODE_RESTOFCONTENT + { + aDelStart.SetIndex( 0 ); + if ( aDelStart == aCurPos ) + { + // kompletter Absatz davor + ContentNode* pPrev = GetPrevVisNode( aCurPos.GetNode() ); + if ( pPrev ) + aDelStart = EditPaM( pPrev, 0 ); + } + } + } + else + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aDelEnd = CursorRight( aCurPos ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + aDelEnd = EndOfWord( aCurPos ); + if (aDelEnd.GetIndex() == aCurPos.GetIndex()) + { + xub_StrLen nLen = aCurPos.GetNode()->Len(); + // end of para? + if (aDelEnd.GetIndex() == nLen) + aDelEnd = WordLeft( aCurPos ); + else // there's still sth to delete on the right + { + aDelEnd = EndOfWord( WordRight( aCurPos ) ); + // if there'n no next word... + if (aDelEnd.GetIndex() == nLen ) + aDelEnd.SetIndex( nLen ); + } + } + } + else // DELMODE_RESTOFCONTENT + { + aDelEnd.SetIndex( aCurPos.GetNode()->Len() ); + if ( aDelEnd == aCurPos ) + { + // kompletter Absatz dahinter + ContentNode* pNext = GetNextVisNode( aCurPos.GetNode() ); + if ( pNext ) + aDelEnd = EditPaM( pNext, pNext->Len() ); + } + } + } + + // Bei DELMODE_RESTOFCONTENT reicht bei verschiedenen Nodes + // kein ConnectParagraphs. + if ( ( nDelMode == DELMODE_RESTOFCONTENT ) || ( aDelStart.GetNode() == aDelEnd.GetNode() ) ) + return ImpDeleteSelection( EditSelection( aDelStart, aDelEnd ) ); + + // Jetzt entscheiden, ob noch Selektion loeschen (RESTOFCONTENTS) + BOOL bSpecialBackward = ( ( nMode == DEL_LEFT ) && ( nDelMode == DELMODE_SIMPLE ) ) + ? TRUE : FALSE; + if ( aStatus.IsAnyOutliner() ) + bSpecialBackward = FALSE; + + return ImpConnectParagraphs( aDelStart.GetNode(), aDelEnd.GetNode(), bSpecialBackward ); +} + +EditPaM ImpEditEngine::ImpDeleteSelection( EditSelection aSel ) +{ + if ( !aSel.HasRange() ) + return aSel.Min(); + + aSel.Adjust( aEditDoc ); + EditPaM aStartPaM( aSel.Min() ); + EditPaM aEndPaM( aSel.Max() ); + + CursorMoved( aStartPaM.GetNode() ); // nur damit neu eingestellte Attribute verschwinden... + CursorMoved( aEndPaM.GetNode() ); // nur damit neu eingestellte Attribute verschwinden... + + DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" ); + DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" ); + + USHORT nStartNode = aEditDoc.GetPos( aStartPaM.GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aEndPaM.GetNode() ); + + DBG_ASSERT( nEndNode != USHRT_MAX, "Start > End ?!" ); + DBG_ASSERT( nStartNode <= nEndNode, "Start > End ?!" ); + + // Alle Nodes dazwischen entfernen.... + for ( ULONG z = nStartNode+1; z < nEndNode; z++ ) + { + // Immer nStartNode+1, wegen Remove()! + ImpRemoveParagraph( nStartNode+1 ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + USHORT nChars; + nChars = aStartPaM.GetNode()->Len() - aStartPaM.GetIndex(); + ImpRemoveChars( aStartPaM, nChars ); + ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(3)" ); + pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), aStartPaM.GetNode()->Len() ); + + // Den Anfang des EndNodes.... + nChars = aEndPaM.GetIndex(); + aEndPaM.SetIndex( 0 ); + ImpRemoveChars( aEndPaM, nChars ); + pPortion = FindParaPortion( aEndPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(4)" ); + pPortion->MarkSelectionInvalid( 0, aEndPaM.GetNode()->Len() ); + // Zusammenfuegen.... + aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() ); + } + else + { + USHORT nChars; + nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); + ImpRemoveChars( aStartPaM, nChars ); + ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(5)" ); + pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); + } + + UpdateSelections(); + TextModified(); + return aStartPaM; +} + +void ImpEditEngine::ImpRemoveParagraph( USHORT nPara ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + ContentNode* pNextNode = aEditDoc.SaveGetObject( nPara+1 ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara ); + + DBG_ASSERT( pNode, "Blinder Node in ImpRemoveParagraph" ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpRemoveParagraph(2)" ); + + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pNode, nPara ); + aDeletedNodes.Insert( pInf, aDeletedNodes.Count() ); + + // Der Node wird vom Undo verwaltet und ggf. zerstoert! + /* delete */ aEditDoc.Remove( nPara ); + GetParaPortions().Remove( nPara ); + delete pPortion; + + if ( IsCallParaInsertedOrDeleted() ) + { + GetEditEnginePtr()->ParagraphDeleted( nPara ); + } + + // Im folgenden muss ggf. Extra-Space neu ermittelt werden. + // Bei ParaAttribsChanged wird leider der Absatz neu formatiert, + // aber diese Methode sollte nicht Zeitkritsch sein! + if ( pNextNode ) + ParaAttribsChanged( pNextNode ); + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoDelContent( this, pNode, nPara ) ); + else +#endif + { + aEditDoc.RemoveItemsFromPool( pNode ); + if ( pNode->GetStyleSheet() ) + EndListening( *pNode->GetStyleSheet(), FALSE ); + delete pNode; + } +} + +EditPaM ImpEditEngine::AutoCorrect( const EditSelection& rCurSel, xub_Unicode c, BOOL bOverwrite ) +{ + EditSelection aSel( rCurSel ); +#ifndef SVX_LIGHT + SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get()->GetAutoCorrect(); + if ( pAutoCorrect ) + { + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( rCurSel ); + + // #i78661 allow application to turn off capitalization of + // start sentence explicitly. + // (This is done by setting IsFirstWordCapitalization to FALSE.) + BOOL bOldCptlSttSntnc = pAutoCorrect->IsAutoCorrFlag( CptlSttSntnc ); + if (!IsFirstWordCapitalization()) + { + ESelection aESel( CreateESel(aSel) ); + EditSelection aFirstWordSel; + EditSelection aSecondWordSel; + if (aESel.nEndPara == 0) // is this the first para? + { + // select first word... + // start by checking if para starts with word. + aFirstWordSel = SelectWord( CreateSel(ESelection()) ); + if (aFirstWordSel.Min().GetIndex() == 0 && aFirstWordSel.Max().GetIndex() == 0) + { + // para does not start with word -> select next/first word + EditPaM aRightWord( WordRight( aFirstWordSel.Max(), 1 ) ); + aFirstWordSel = SelectWord( EditSelection( aRightWord ) ); + } + + // select second word + // (sometimes aSel mightnot point to the end of the first word + // but to some following char like '.'. ':', ... + // In those cases we need aSecondWordSel to see if aSel + // will actually effect the first word.) + EditPaM aRight2Word( WordRight( aFirstWordSel.Max(), 1 ) ); + aSecondWordSel = SelectWord( EditSelection( aRight2Word ) ); + } + BOOL bIsFirstWordInFirstPara = aESel.nEndPara == 0 && + aFirstWordSel.Max().GetIndex() <= aSel.Max().GetIndex() && + aSel.Max().GetIndex() <= aSecondWordSel.Min().GetIndex(); + + if (bIsFirstWordInFirstPara) + pAutoCorrect->SetAutoCorrFlag( CptlSttSntnc, IsFirstWordCapitalization() ); + } + + ContentNode* pNode = aSel.Max().GetNode(); + USHORT nIndex = aSel.Max().GetIndex(); + EdtAutoCorrDoc aAuto( this, pNode, nIndex, c ); + pAutoCorrect->AutoCorrect( aAuto, *pNode, nIndex, c, !bOverwrite ); + aSel.Max().SetIndex( aAuto.GetCursor() ); + + // #i78661 since the SvxAutoCorrect object used here is + // shared we need to reset the value to it's original state. + pAutoCorrect->SetAutoCorrFlag( CptlSttSntnc, bOldCptlSttSntnc ); + } +#endif // !SVX_LIGHT + return aSel.Max(); +} + + +EditPaM ImpEditEngine::InsertText( const EditSelection& rCurSel, + xub_Unicode c, BOOL bOverwrite, sal_Bool bIsUserInput ) +{ + DBG_ASSERT( c != '\t', "Tab bei InsertText ?" ); + DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" ); + + EditPaM aPaM( rCurSel.Min() ); + + BOOL bDoOverwrite = ( bOverwrite && + ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) ? TRUE : FALSE; + + BOOL bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); + + if ( bUndoAction ) + UndoActionStart( EDITUNDO_INSERT ); + + if ( rCurSel.HasRange() ) + { + aPaM = ImpDeleteSelection( rCurSel ); + } + else if ( bDoOverwrite ) + { + // Wenn Selektion, dann nicht auch noch ein Zeichen ueberschreiben! + EditSelection aTmpSel( aPaM ); + aTmpSel.Max().GetIndex()++; + DBG_ASSERT( !aTmpSel.DbgIsBuggy( aEditDoc ), "Overwrite: Fehlerhafte Selektion!" ); + ImpDeleteSelection( aTmpSel ); + } + + if ( aPaM.GetNode()->Len() < MAXCHARSINPARA ) + { + if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) + { + uno::Reference < i18n::XExtendedInputSequenceChecker > _xISC( ImplGetInputSequenceChecker() ); + if (!pCTLOptions) + pCTLOptions = new SvtCTLOptions; + + if (_xISC.is() || pCTLOptions) + { + xub_StrLen nTmpPos = aPaM.GetIndex(); + sal_Int16 nCheckMode = pCTLOptions->IsCTLSequenceCheckingRestricted() ? + i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; + + // the text that needs to be checked is only the one + // before the current cursor position + rtl::OUString aOldText( aPaM.GetNode()->Copy(0, nTmpPos) ); + rtl::OUString aNewText( aOldText ); + if (pCTLOptions->IsCTLSequenceCheckingTypeAndReplace()) + { + /*const xub_StrLen nPrevPos = static_cast< xub_StrLen >*/( _xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ) ); + + // find position of first character that has changed + sal_Int32 nOldLen = aOldText.getLength(); + sal_Int32 nNewLen = aNewText.getLength(); + const sal_Unicode *pOldTxt = aOldText.getStr(); + const sal_Unicode *pNewTxt = aNewText.getStr(); + sal_Int32 nChgPos = 0; + while ( nChgPos < nOldLen && nChgPos < nNewLen && + pOldTxt[nChgPos] == pNewTxt[nChgPos] ) + ++nChgPos; + + xub_StrLen nChgLen = static_cast< xub_StrLen >( nNewLen - nChgPos ); + String aChgText( aNewText.copy( nChgPos ), nChgLen ); + + // select text from first pos to be changed to current pos + EditSelection aSel( EditPaM( aPaM.GetNode(), (USHORT) nChgPos ), aPaM ); + + if (aChgText.Len()) + return InsertText( aSel, aChgText ); // implicitly handles undo + else + return aPaM; + } + else + { + // should the character be ignored (i.e. not get inserted) ? + if (!_xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) + return aPaM; // nothing to be done -> no need for undo + } + } + + // at this point now we will insert the character 'normally' some lines below... + } + + if ( IsUndoEnabled() && !IsInUndo() ) + { + EditUndoInsertChars* pNewUndo = new EditUndoInsertChars( this, CreateEPaM( aPaM ), c ); + BOOL bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? TRUE : FALSE; + InsertUndo( pNewUndo, bTryMerge ); + } + + aEditDoc.InsertText( (const EditPaM&)aPaM, c ); + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertText" ); + pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); + aPaM.GetIndex()++; // macht EditDoc-Methode nicht mehr + } + + TextModified(); + + if ( bUndoAction ) + UndoActionEnd( EDITUNDO_INSERT ); + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertText( EditSelection aCurSel, const XubString& rStr ) +{ + UndoActionStart( EDITUNDO_INSERT ); + + EditPaM aPaM; + if ( aCurSel.HasRange() ) + aPaM = ImpDeleteSelection( aCurSel ); + else + aPaM = aCurSel.Max(); + + EditPaM aCurPaM( aPaM ); // fuers Invalidieren + + XubString aText( rStr ); + aText.ConvertLineEnd( LINEEND_LF ); + SfxVoidItem aTabItem( EE_FEATURE_TAB ); + + // Konvertiert nach LineSep = \n + // Token mit LINE_SEP abfragen, + // da der MAC-Compiler aus \n etwas anderes macht! + + USHORT nStart = 0; + while ( nStart < aText.Len() ) + { + USHORT nEnd = aText.Search( LINE_SEP, nStart ); + if ( nEnd == STRING_NOTFOUND ) + nEnd = aText.Len(); // nicht dereferenzieren! + + // Start == End => Leerzeile + if ( nEnd > nStart ) + { + XubString aLine( aText, nStart, nEnd-nStart ); + xub_StrLen nChars = aPaM.GetNode()->Len() + aLine.Len(); + if ( nChars > MAXCHARSINPARA ) + { + USHORT nMaxNewChars = MAXCHARSINPARA-aPaM.GetNode()->Len(); + nEnd -= ( aLine.Len() - nMaxNewChars ); // Dann landen die Zeichen im naechsten Absatz. + aLine.Erase( nMaxNewChars ); // Del Rest... + } +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM ), aLine ) ); +#endif + // Tabs ? + if ( aLine.Search( '\t' ) == STRING_NOTFOUND ) + aPaM = aEditDoc.InsertText( aPaM, aLine ); + else + { + USHORT nStart2 = 0; + while ( nStart2 < aLine.Len() ) + { + USHORT nEnd2 = aLine.Search( '\t', nStart2 ); + if ( nEnd2 == STRING_NOTFOUND ) + nEnd2 = aLine.Len(); // nicht dereferenzieren! + + if ( nEnd2 > nStart2 ) + aPaM = aEditDoc.InsertText( aPaM, XubString( aLine, nStart2, nEnd2-nStart2 ) ); + if ( nEnd2 < aLine.Len() ) + { + // aPaM = ImpInsertFeature( EditSelection( aPaM, aPaM ), ); + aPaM = aEditDoc.InsertFeature( aPaM, aTabItem ); + } + nStart2 = nEnd2+1; + } + } + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertText" ); + pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.Len() ); + } + if ( nEnd < aText.Len() ) + aPaM = ImpInsertParaBreak( aPaM ); + + nStart = nEnd+1; + } + + UndoActionEnd( EDITUNDO_INSERT ); + + TextModified(); + return aPaM; +} + +EditPaM ImpEditEngine::ImpFastInsertText( EditPaM aPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "FastInsertText: Zeilentrenner nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "FastInsertText: Zeilentrenner nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "FastInsertText: Features nicht erlaubt!" ); + + if ( ( aPaM.GetNode()->Len() + rStr.Len() ) < MAXCHARSINPARA ) + { +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM ), rStr ) ); +#endif + + aPaM = aEditDoc.InsertText( aPaM, rStr ); + TextModified(); + } + else + { + aPaM = ImpInsertText( aPaM, rStr ); + } + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertFeature( EditSelection aCurSel, const SfxPoolItem& rItem ) +{ + EditPaM aPaM; + if ( aCurSel.HasRange() ) + aPaM = ImpDeleteSelection( aCurSel ); + else + aPaM = aCurSel.Max(); + + if ( aPaM.GetIndex() >= 0xfffe ) + return aPaM; + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertFeature( this, CreateEPaM( aPaM ), rItem ) ); +#endif + aPaM = aEditDoc.InsertFeature( aPaM, rItem ); + + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertFeature" ); + pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 ); + + TextModified(); + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertParaBreak( const EditSelection& rCurSel, BOOL bKeepEndingAttribs ) +{ + EditPaM aPaM; + if ( rCurSel.HasRange() ) + aPaM = ImpDeleteSelection( rCurSel ); + else + aPaM = rCurSel.Max(); + + return ImpInsertParaBreak( aPaM, bKeepEndingAttribs ); +} + +EditPaM ImpEditEngine::ImpInsertParaBreak( const EditPaM& rPaM, BOOL bKeepEndingAttribs ) +{ + if ( aEditDoc.Count() >= 0xFFFE ) + { + DBG_ERROR( "Can't process more than 64K paragraphs!" ); + return rPaM; + } + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoSplitPara( this, aEditDoc.GetPos( rPaM.GetNode() ), rPaM.GetIndex() ) ); +#endif + + EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) ); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + { + xub_StrLen nEnd = rPaM.GetNode()->Len(); + aPaM.GetNode()->CreateWrongList(); + WrongList* pLWrongs = rPaM.GetNode()->GetWrongList(); + WrongList* pRWrongs = aPaM.GetNode()->GetWrongList(); + // Falschgeschriebene Woerter ruebernehmen: + USHORT nLWrongs = pLWrongs->Count(); + for ( USHORT nW = 0; nW < nLWrongs; nW++ ) + { + WrongRange& rWrong = pLWrongs->GetObject( nW ); + // Nur wenn wirklich dahinter, ein ueberlappendes wird beim Spell korrigiert + if ( rWrong.nStart > nEnd ) + { + pRWrongs->InsertWrong( rWrong, pRWrongs->Count() ); + WrongRange& rRWrong = pRWrongs->GetObject( pRWrongs->Count() - 1 ); + rRWrong.nStart = rRWrong.nStart - nEnd; + rRWrong.nEnd = rRWrong.nEnd - nEnd; + } + else if ( ( rWrong.nStart < nEnd ) && ( rWrong.nEnd > nEnd ) ) + rWrong.nEnd = nEnd; + } + USHORT nInv = nEnd ? nEnd-1 : nEnd; + if ( nEnd ) + pLWrongs->MarkInvalid( nInv, nEnd ); + else + pLWrongs->SetValid(); + pRWrongs->SetValid(); // sonst 0 - 0xFFFF + pRWrongs->MarkInvalid( 0, 1 ); // Nur das erste Wort testen + } +#endif // !SVX_LIGHT + + + ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" ); + pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); + + // Optimieren: Nicht unnoetig viele GetPos auf die Listen ansetzen! + // Hier z.B. bei Undo, aber auch in allen anderen Methoden. + USHORT nPos = GetParaPortions().GetPos( pPortion ); + ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() ); + GetParaPortions().Insert( pNewPortion, nPos + 1 ); + ParaAttribsChanged( pNewPortion->GetNode() ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPos+1 ); + + CursorMoved( rPaM.GetNode() ); // falls leeres Attribut entstanden. + TextModified(); + return aPaM; +} + +EditPaM ImpEditEngine::ImpFastInsertParagraph( USHORT nPara ) +{ +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + { + if ( nPara ) + { + DBG_ASSERT( aEditDoc.SaveGetObject( nPara-1 ), "FastInsertParagraph: Prev existiert nicht" ); + InsertUndo( new EditUndoSplitPara( this, nPara-1, aEditDoc.GetObject( nPara-1 )->Len() ) ); + } + else + InsertUndo( new EditUndoSplitPara( this, 0, 0 ) ); + } +#endif + + ContentNode* pNode = new ContentNode( aEditDoc.GetItemPool() ); + // Falls FlatMode, wird spaeter kein Font eingestellt: + pNode->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + pNode->CreateWrongList(); +#endif // !SVX_LIGHT + + aEditDoc.Insert( pNode, nPara ); + + ParaPortion* pNewPortion = new ParaPortion( pNode ); + GetParaPortions().Insert( pNewPortion, nPara ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPara ); + + return EditPaM( pNode, 0 ); +} + +EditPaM ImpEditEngine::InsertParaBreak( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertParaBreak( aCurSel ) ); + if ( aStatus.DoAutoIndenting() ) + { + USHORT nPara = aEditDoc.GetPos( aPaM.GetNode() ); + DBG_ASSERT( nPara > 0, "AutoIndenting: Fehler!" ); + XubString aPrevParaText( GetEditDoc().GetParaAsString( nPara-1 ) ); + USHORT n = 0; + while ( ( n < aPrevParaText.Len() ) && + ( ( aPrevParaText.GetChar(n) == ' ' ) || ( aPrevParaText.GetChar(n) == '\t' ) ) ) + { + if ( aPrevParaText.GetChar(n) == '\t' ) + aPaM = ImpInsertFeature( aPaM, SfxVoidItem( EE_FEATURE_TAB ) ); + else + aPaM = ImpInsertText( aPaM, aPrevParaText.GetChar(n) ); + n++; + } + + } + return aPaM; +} + +EditPaM ImpEditEngine::InsertTab( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_TAB ) ) ); + return aPaM; +} + +EditPaM ImpEditEngine::InsertField( EditSelection aCurSel, const SvxFieldItem& rFld ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, rFld ) ); + return aPaM; +} + +BOOL ImpEditEngine::UpdateFields() +{ + BOOL bChanges = FALSE; + USHORT nParas = GetEditDoc().Count(); + for ( USHORT nPara = 0; nPara < nParas; nPara++ ) + { + BOOL bChangesInPara = FALSE; + ContentNode* pNode = GetEditDoc().GetObject( nPara ); + DBG_ASSERT( pNode, "NULL-Pointer im Doc" ); + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); +// USHORT nAttrs = rAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + EditCharAttribField* pField = (EditCharAttribField*)pAttr; + EditCharAttribField* pCurrent = new EditCharAttribField( *pField ); + pField->Reset(); + + if ( aStatus.MarkFields() ) + pField->GetFldColor() = new Color( GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor ); + + XubString aFldValue = GetEditEnginePtr()->CalcFieldValue( + (const SvxFieldItem&)*pField->GetItem(), + nPara, pField->GetStart(), + pField->GetTxtColor(), pField->GetFldColor() ); + pField->GetFieldValue() = aFldValue; + if ( *pField != *pCurrent ) + { + bChanges = TRUE; + bChangesInPara = TRUE; + } + delete pCurrent; + } + } + if ( bChangesInPara ) + { + // ggf. etwas genauer invalidieren. + ParaPortion* pPortion = GetParaPortions().GetObject( nPara ); + DBG_ASSERT( pPortion, "NULL-Pointer im Doc" ); + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); + } + } + return bChanges; +} + +EditPaM ImpEditEngine::InsertLineBreak( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_LINEBR ) ) ); + return aPaM; +} + +// ---------------------------------------------------------------------- +// Hilfsfunktionen +// ---------------------------------------------------------------------- +Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, USHORT nFlags ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: PaMtoEditCursor" ); + + Rectangle aEditCursor; + long nY = 0; + for ( USHORT nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject(nPortion); + ContentNode* pNode = pPortion->GetNode(); + DBG_ASSERT( pNode, "Ungueltiger Node in Portion!" ); + if ( pNode != aPaM.GetNode() ) + { + nY += pPortion->GetHeight(); + } + else + { + aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags ); + aEditCursor.Top() += nY; + aEditCursor.Bottom() += nY; + return aEditCursor; + } + } + DBG_ERROR( "Portion nicht gefunden!" ); + return aEditCursor; +} + +EditPaM ImpEditEngine::GetPaM( Point aDocPos, BOOL bSmart ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: GetPaM" ); + + long nY = 0; + long nTmpHeight; + EditPaM aPaM; + USHORT nPortion; + for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject(nPortion); + nTmpHeight = pPortion->GetHeight(); // sollte auch bei !bVisible richtig sein! + nY += nTmpHeight; + if ( nY > aDocPos.Y() ) + { + nY -= nTmpHeight; + aDocPos.Y() -= nY; + // unsichtbare Portions ueberspringen: + while ( pPortion && !pPortion->IsVisible() ) + { + nPortion++; + pPortion = GetParaPortions().SaveGetObject( nPortion ); + } + DBG_ASSERT( pPortion, "Keinen sichtbaren Absatz gefunden: GetPaM" ); + aPaM = GetPaM( pPortion, aDocPos, bSmart ); + return aPaM; + + } + } + // Dann den letzten sichtbaren Suchen: + nPortion = GetParaPortions().Count()-1; + while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() ) + nPortion--; + + DBG_ASSERT( GetParaPortions()[nPortion]->IsVisible(), "Keinen sichtbaren Absatz gefunden: GetPaM" ); + aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() ); + aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() ); + return aPaM; +} + +sal_uInt32 ImpEditEngine::GetTextHeight() const +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: GetTextHeight" ); + DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Nicht formatiert" ); + return nCurTextHeight; +} + +sal_uInt32 ImpEditEngine::CalcTextWidth( BOOL bIgnoreExtraSpace ) +{ + // Wenn noch nicht formatiert und nicht gerade dabei. + // Wird in der Formatierung bei AutoPageSize gerufen. + if ( !IsFormatted() && !IsFormatting() ) + FormatDoc(); + + EditLine* pLine; + + long nMaxWidth = 0; + long nCurWidth = 0; + + // -------------------------------------------------- + // Ueber alle Absaetze... + // -------------------------------------------------- + USHORT nParas = GetParaPortions().Count(); +// USHORT nBiggestPara = 0; +// USHORT nBiggestLine = 0; + for ( USHORT nPara = 0; nPara < nParas; nPara++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject( nPara ); + if ( pPortion->IsVisible() ) + { + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() ); + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() ); + + // -------------------------------------------------- + // Ueber die Zeilen des Absatzes... + // -------------------------------------------------- + ULONG nLines = pPortion->GetLines().Count(); + for ( USHORT nLine = 0; nLine < nLines; nLine++ ) + { + pLine = pPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "NULL-Pointer im Zeileniterator in CalcWidth" ); + // nCurWidth = pLine->GetStartPosX(); + // Bei Center oder Right haengt die breite von der + // Papierbreite ab, hier nicht erwuenscht. + // Am besten generell nicht auf StartPosX verlassen, + // es muss auch die rechte Einrueckung beruecksichtigt werden! + nCurWidth = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth ); + if ( nLine == 0 ) + { + long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() ); + nCurWidth -= nFI; + if ( pPortion->GetBulletX() > nCurWidth ) + { + nCurWidth += nFI; // LI? + if ( pPortion->GetBulletX() > nCurWidth ) + nCurWidth = pPortion->GetBulletX(); + } + } + nCurWidth += GetXValue( rLRItem.GetRight() ); + nCurWidth += CalcLineWidth( pPortion, pLine, bIgnoreExtraSpace ); + if ( nCurWidth > nMaxWidth ) + { + nMaxWidth = nCurWidth; + } + } + } + } + if ( nMaxWidth < 0 ) + nMaxWidth = 0; + + nMaxWidth++; // Ein breiter, da in CreateLines bei >= umgebrochen wird. + return (sal_uInt32)nMaxWidth; +} + +sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, BOOL bIgnoreExtraSpace ) +{ + USHORT nPara = GetEditDoc().GetPos( pPortion->GetNode() ); + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + + ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF ); + + SvxAdjust eJustification = GetJustification( nPara ); + + // Berechnung der Breite ohne die Indents... + sal_uInt32 nWidth = 0; + USHORT nPos = pLine->GetStart(); + for ( USHORT nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) + { + TextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nTP ); + switch ( pTextPortion->GetKind() ) + { + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + case PORTIONKIND_TAB: + { + nWidth += pTextPortion->GetSize().Width(); + } + break; + case PORTIONKIND_TEXT: + { + if ( ( eJustification != SVX_ADJUST_BLOCK ) || ( !bIgnoreExtraSpace ) ) + { + nWidth += pTextPortion->GetSize().Width(); + } + else + { + SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() ); + SeekCursor( pPortion->GetNode(), nPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(), *pPortion->GetNode(), nPos, pTextPortion->GetLen(), NULL ).Width(); + } + } + break; + } + nPos = nPos + pTextPortion->GetLen(); + } + + GetRefDevice()->Pop(); + + return nWidth; +} + +sal_uInt32 ImpEditEngine::CalcTextHeight() +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: CalcTextHeight" ); + sal_uInt32 nY = 0; + for ( USHORT nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + nY += GetParaPortions()[nPortion]->GetHeight(); + return nY; +} + +USHORT ImpEditEngine::GetLineCount( USHORT nParagraph ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineCount" ); + if ( pPPortion ) + return pPPortion->GetLines().Count(); + + return 0xFFFF; +} + +xub_StrLen ImpEditEngine::GetLineLen( USHORT nParagraph, USHORT nLine ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineLen: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineLen" ); + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineHeight" ); + return pLine->GetLen(); + } + + return 0xFFFF; +} + +void ImpEditEngine::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineBoundaries" ); + rStart = rEnd = 0xFFFF; // default values in case of error + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineBoundaries" ); + rStart = pLine->GetStart(); + rEnd = pLine->GetEnd(); + } +} + +USHORT ImpEditEngine::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + USHORT nLineNo = 0xFFFF; + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetLineNumberAtIndex: invalid paragraph index" ); + if (pNode) + { + // we explicitly allow for the index to point at the character right behind the text + const bool bValidIndex = /*0 <= nIndex &&*/ nIndex <= pNode->Len(); + DBG_ASSERT( bValidIndex, "GetLineNumberAtIndex: invalid index" ); + const USHORT nLineCount = GetLineCount( nPara ); + if (nIndex == pNode->Len()) + nLineNo = nLineCount > 0 ? nLineCount - 1 : 0; + else if (bValidIndex) // nIndex < pNode->Len() + { + USHORT nStart = USHRT_MAX, nEnd = USHRT_MAX; + for (USHORT i = 0; i < nLineCount && nLineNo == 0xFFFF; ++i) + { + GetLineBoundaries( nStart, nEnd, nPara, i ); + if (nStart <= nIndex && nIndex < nEnd) + nLineNo = i; + } + } + } + return nLineNo; +} + +USHORT ImpEditEngine::GetLineHeight( USHORT nParagraph, USHORT nLine ) +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineHeight" ); + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineHeight" ); + return pLine->GetHeight(); + } + + return 0xFFFF; +} + +sal_uInt32 ImpEditEngine::GetParaHeight( USHORT nParagraph ) +{ + sal_uInt32 nHeight = 0; + + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" ); + + if ( pPPortion ) + nHeight = pPPortion->GetHeight(); + + return nHeight; +} + +void ImpEditEngine::UpdateSelections() +{ + USHORT nInvNodes = aDeletedNodes.Count(); + + // Pruefen, ob eine der Selektionen auf einem geloeschten Node steht... + // Wenn der Node gueltig ist, muss noch der Index geprueft werden! + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews.GetObject(nView); + DBG_CHKOBJ( pView, EditView, 0 ); + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + BOOL bChanged = FALSE; + for ( USHORT n = 0; n < nInvNodes; n++ ) + { + DeletedNodeInfo* pInf = aDeletedNodes.GetObject( n ); + if ( ( ( ULONG )(aCurSel.Min().GetNode()) == pInf->GetInvalidAdress() ) || + ( ( ULONG )(aCurSel.Max().GetNode()) == pInf->GetInvalidAdress() ) ) + { + // ParaPortions verwenden, da jetzt auch versteckte + // Absaetze beruecksichtigt werden muessen! + USHORT nPara = pInf->GetPosition(); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pPPortion ) // letzter Absatz + { + nPara = GetParaPortions().Count()-1; + pPPortion = GetParaPortions().GetObject( nPara ); + } + DBG_ASSERT( pPPortion, "Leeres Document in UpdateSelections ?" ); + // Nicht aus einem verstecktem Absatz landen: + USHORT nCurPara = nPara; + USHORT nLastPara = GetParaPortions().Count()-1; + while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() ) + nPara++; + if ( nPara > nLastPara ) // dann eben rueckwaerts... + { + nPara = nCurPara; + while ( nPara && !GetParaPortions()[nPara]->IsVisible() ) + nPara--; + } + DBG_ASSERT( GetParaPortions()[nPara]->IsVisible(), "Keinen sichtbaren Absatz gefunden: UpdateSelections" ); + + ParaPortion* pParaPortion = GetParaPortions()[nPara]; + EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) ); + pView->pImpEditView->SetEditSelection( aTmpSelection ); + bChanged=TRUE; + break; // for-Schleife + } + } + if ( !bChanged ) + { + // Index prueffen, falls Node geschrumpft. + if ( aCurSel.Min().GetIndex() > aCurSel.Min().GetNode()->Len() ) + { + aCurSel.Min().GetIndex() = aCurSel.Min().GetNode()->Len(); + pView->pImpEditView->SetEditSelection( aCurSel ); + } + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + { + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + pView->pImpEditView->SetEditSelection( aCurSel ); + } + } + } + + // Loeschen... + for ( USHORT n = 0; n < nInvNodes; n++ ) + { + DeletedNodeInfo* pInf = aDeletedNodes.GetObject( n ); + delete pInf; + } + aDeletedNodes.Remove( 0, aDeletedNodes.Count() ); +} + +EditSelection ImpEditEngine::ConvertSelection( USHORT nStartPara, USHORT nStartPos, + USHORT nEndPara, USHORT nEndPos ) const +{ + EditSelection aNewSelection; + + // Start... + ContentNode* pNode = aEditDoc.SaveGetObject( nStartPara ); + USHORT nIndex = nStartPos; + if ( !pNode ) + { + pNode = aEditDoc[ aEditDoc.Count()-1 ]; + nIndex = pNode->Len(); + } + else if ( nIndex > pNode->Len() ) + nIndex = pNode->Len(); + + aNewSelection.Min().SetNode( pNode ); + aNewSelection.Min().SetIndex( nIndex ); + + // End... + pNode = aEditDoc.SaveGetObject( nEndPara ); + nIndex = nEndPos; + if ( !pNode ) + { + pNode = aEditDoc[ aEditDoc.Count()-1 ]; + nIndex = pNode->Len(); + } + else if ( nIndex > pNode->Len() ) + nIndex = pNode->Len(); + + aNewSelection.Max().SetNode( pNode ); + aNewSelection.Max().SetIndex( nIndex ); + + return aNewSelection; +} + +EditSelection ImpEditEngine::MatchGroup( const EditSelection& rSel ) +{ + EditSelection aMatchSel; + EditSelection aTmpSel( rSel ); + aTmpSel.Adjust( GetEditDoc() ); + if ( ( aTmpSel.Min().GetNode() != aTmpSel.Max().GetNode() ) || + ( ( aTmpSel.Max().GetIndex() - aTmpSel.Min().GetIndex() ) > 1 ) ) + { + return aMatchSel; + } + + USHORT nPos = aTmpSel.Min().GetIndex(); + ContentNode* pNode = aTmpSel.Min().GetNode(); + if ( nPos >= pNode->Len() ) + return aMatchSel; + + USHORT nMatchChar = aGroupChars.Search( pNode->GetChar( nPos ) ); + if ( nMatchChar != STRING_NOTFOUND ) + { + USHORT nNode = aEditDoc.GetPos( pNode ); + if ( ( nMatchChar % 2 ) == 0 ) + { + // Vorwaerts suchen... + xub_Unicode nSC = aGroupChars.GetChar( nMatchChar ); + DBG_ASSERT( aGroupChars.Len() > (nMatchChar+1), "Ungueltige Gruppe von MatchChars!" ); + xub_Unicode nEC = aGroupChars.GetChar( nMatchChar+1 ); + + USHORT nCur = aTmpSel.Min().GetIndex()+1; + USHORT nLevel = 1; + while ( pNode && nLevel ) + { + XubString& rStr = *pNode; + while ( nCur < rStr.Len() ) + { + if ( rStr.GetChar( nCur ) == nSC ) + nLevel++; + else if ( rStr.GetChar( nCur ) == nEC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + nCur++; + } + + if ( nLevel ) + { + nNode++; + pNode = nNode < aEditDoc.Count() ? aEditDoc.GetObject( nNode ) : 0; + nCur = 0; + } + } + if ( nLevel == 0 ) // gefunden + { + aMatchSel.Min() = aTmpSel.Min(); + aMatchSel.Max() = EditPaM( pNode, nCur+1 ); + } + } + else + { + // Rueckwaerts suchen... + xub_Unicode nEC = aGroupChars.GetChar( nMatchChar ); + xub_Unicode nSC = aGroupChars.GetChar( nMatchChar-1 ); + + USHORT nCur = aTmpSel.Min().GetIndex()-1; + USHORT nLevel = 1; + while ( pNode && nLevel ) + { + if ( pNode->Len() ) + { + XubString& rStr = *pNode; + while ( nCur ) + { + if ( rStr.GetChar( nCur ) == nSC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + else if ( rStr.GetChar( nCur ) == nEC ) + nLevel++; + + nCur--; + } + } + + if ( nLevel ) + { + pNode = nNode ? aEditDoc.GetObject( --nNode ) : 0; + if ( pNode ) + nCur = pNode->Len()-1; // egal ob negativ, weil if Len() + } + } + + if ( nLevel == 0 ) // gefunden + { + aMatchSel.Min() = aTmpSel.Min(); + aMatchSel.Min().GetIndex()++; // hinter das Zeichen + aMatchSel.Max() = EditPaM( pNode, nCur ); + } + } + } + return aMatchSel; +} + +void ImpEditEngine::StopSelectionMode() +{ + if ( ( IsInSelectionMode() || aSelEngine.IsInSelection() ) && pActiveView ) + { + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + EditSelection aSel( pActiveView->pImpEditView->GetEditSelection() ); + aSel.Min() = aSel.Max(); + pActiveView->pImpEditView->SetEditSelection( aSel ); + pActiveView->ShowCursor(); + aSelEngine.Reset(); + bInSelection = FALSE; + } +} + +void ImpEditEngine::SetActiveView( EditView* pView ) +{ + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Eigentlich waere jetzt ein bHasVisSel und HideSelection notwendig !!! + + if ( pView == pActiveView ) + return; + + if ( pActiveView && pActiveView->HasSelection() ) + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + + pActiveView = pView; + + if ( pActiveView && pActiveView->HasSelection() ) + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + + // NN: Quick fix for #78668#: + // When editing of a cell in Calc is ended, the edit engine is not deleted, + // only the edit views are removed. If mpIMEInfos is still set in that case, + // mpIMEInfos->aPos points to an invalid selection. + // -> reset mpIMEInfos now + // (probably something like this is necessary whenever the content is modified + // from the outside) + + if ( !pView && mpIMEInfos ) + { + delete mpIMEInfos; + mpIMEInfos = NULL; + } +} + +uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable( const EditSelection& rSelection ) const +{ +#ifndef SVX_LIGHT + EditSelection aSelection( rSelection ); + aSelection.Adjust( GetEditDoc() ); + + EditDataObject* pDataObj = new EditDataObject; + uno::Reference< datatransfer::XTransferable > xDataObj; + xDataObj = pDataObj; + + XubString aText( GetSelected( aSelection ) ); + aText.ConvertLineEnd(); // Systemspezifisch + pDataObj->GetString() = aText; + + SvxFontItem::EnableStoreUnicodeNames( TRUE ); + WriteBin( pDataObj->GetStream(), aSelection, TRUE ); + pDataObj->GetStream().Seek( 0 ); + SvxFontItem::EnableStoreUnicodeNames( FALSE ); + + ((ImpEditEngine*)this)->WriteRTF( pDataObj->GetRTFStream(), aSelection ); + pDataObj->GetRTFStream().Seek( 0 ); + + if ( ( aSelection.Min().GetNode() == aSelection.Max().GetNode() ) + && ( aSelection.Max().GetIndex() == (aSelection.Min().GetIndex()+1) ) ) + { + const EditCharAttrib* pAttr = aSelection.Min().GetNode()->GetCharAttribs(). + FindFeature( aSelection.Min().GetIndex() ); + if ( pAttr && + ( pAttr->GetStart() == aSelection.Min().GetIndex() ) && + ( pAttr->Which() == EE_FEATURE_FIELD ) ) + { + const SvxFieldItem* pField = (const SvxFieldItem*)pAttr->GetItem(); + const SvxFieldData* pFld = pField->GetField(); + if ( pFld && pFld->ISA( SvxURLField ) ) + { + // Office-Bookmark + String aURL( ((const SvxURLField*)pFld)->GetURL() ); + String aTxt( ((const SvxURLField*)pFld)->GetRepresentation() ); + pDataObj->GetURL() = aURL; + } + } + } + + return xDataObj; +#else + return uno::Reference< datatransfer::XTransferable >(); +#endif +} + +EditSelection ImpEditEngine::InsertText( uno::Reference< datatransfer::XTransferable >& rxDataObj, const String& rBaseURL, const EditPaM& rPaM, BOOL bUseSpecial ) +{ + EditSelection aNewSelection( rPaM ); + + if ( rxDataObj.is() ) + { + datatransfer::DataFlavor aFlavor; + BOOL bDone = FALSE; + + if ( bUseSpecial ) + { + // BIN + SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_EDITENGINE, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + uno::Sequence< sal_Int8 > aSeq; + aData >>= aSeq; + { + SvMemoryStream aBinStream( aSeq.getArray(), aSeq.getLength(), STREAM_READ ); + aNewSelection = Read( aBinStream, rBaseURL, EE_FORMAT_BIN, rPaM ); + } + bDone = TRUE; + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + } + + if ( !bDone ) + { + // Bookmark + /* + String aURL = ...; + String aTxt = ...; + // Feld nur einfuegen, wenn Factory vorhanden. + if ( ITEMDATA() && ITEMDATA()->GetClassManager().Get( SVX_URLFIELD ) ) + { + SvxFieldItem aField( SvxURLField( aURL, aTxt, SVXURLFORMAT_URL ), EE_FEATURE_FIELD ); + aNewSelection = InsertField( aPaM, aField ); + UpdateFields(); + } + else + aNewSelection = ImpInsertText( aPaM, aURL ); + } + */ + } + if ( !bDone ) + { + // RTF + SotExchange::GetFormatDataFlavor( SOT_FORMAT_RTF, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + uno::Sequence< sal_Int8 > aSeq; + aData >>= aSeq; + { + SvMemoryStream aRTFStream( aSeq.getArray(), aSeq.getLength(), STREAM_READ ); + aNewSelection = Read( aRTFStream, rBaseURL, EE_FORMAT_RTF, rPaM ); + } + bDone = TRUE; + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + } + } + if ( !bDone ) + { + // XML ? + // Currently, there is nothing like "The" XML format, StarOffice doesn't offer plain XML in Clipboard... + } + } + if ( !bDone ) + { + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + ::rtl::OUString aText; + aData >>= aText; + aNewSelection = ImpInsertText( rPaM, aText ); + bDone = TRUE; + } + catch( ... ) + { + ; // #i9286# can happen, even if isDataFlavorSupported returns true... + } + } + } + } + + return aNewSelection; +} + +Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion ) +{ + Range aRange( 0, 0 ); + + if ( pPortion->IsVisible() ) + { + const SvxULSpaceItem& rULSpace = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + // erst von vorne... + USHORT nFirstInvalid = 0xFFFF; + USHORT nLine; + for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pL = pPortion->GetLines().GetObject( nLine ); + if ( pL->IsInvalid() ) + { + nFirstInvalid = nLine; + break; + } + if ( nLine && !aStatus.IsOutliner() ) // nicht die erste Zeile + aRange.Min() += nSBL; + aRange.Min() += pL->GetHeight(); + } + DBG_ASSERT( nFirstInvalid != 0xFFFF, "Keine ungueltige Zeile gefunden in GetInvalidYOffset(1)" ); + + + // Abgleichen und weiter... + aRange.Max() = aRange.Min(); + aRange.Max() += pPortion->GetFirstLineOffset(); + if ( nFirstInvalid != 0 ) // Nur wenn nicht die erste Zeile ungueltig + aRange.Min() = aRange.Max(); + + USHORT nLastInvalid = pPortion->GetLines().Count()-1; + for ( nLine = nFirstInvalid; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pL = pPortion->GetLines().GetObject( nLine ); + if ( pL->IsValid() ) + { + nLastInvalid = nLine; + break; + } + + if ( nLine && !aStatus.IsOutliner() ) + aRange.Max() += nSBL; + aRange.Max() += pL->GetHeight(); + } + + // MT 07/00 SBL kann jetzt kleiner 100% sein => ggf. die Zeile davor neu ausgeben. + if( ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) && rLSItem.GetPropLineSpace() && + ( rLSItem.GetPropLineSpace() < 100 ) ) + { + EditLine* pL = pPortion->GetLines().GetObject( nFirstInvalid ); + long n = pL->GetTxtHeight() * ( 100 - rLSItem.GetPropLineSpace() ); + n /= 100; + aRange.Min() -= n; + aRange.Max() += n; + } + + if ( ( nLastInvalid == pPortion->GetLines().Count()-1 ) && ( !aStatus.IsOutliner() ) ) + aRange.Max() += GetYValue( rULSpace.GetLower() ); + } + return aRange; +} + +EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, BOOL bSmart ) +{ + DBG_ASSERT( pPortion->IsVisible(), "Wozu GetPaM() bei einem unsichtbaren Absatz?" ); + DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" ); + + USHORT nCurIndex = 0; + EditPaM aPaM; + aPaM.SetNode( pPortion->GetNode() ); + + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + long nY = pPortion->GetFirstLineOffset(); + + DBG_ASSERT( pPortion->GetLines().Count(), "Leere ParaPortion in GetPaM!" ); + + EditLine* pLine = 0; + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); + nY += pTmpLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY += nSBL; + if ( nY > aDocPos.Y() ) // das war 'se + { + pLine = pTmpLine; + break; // richtige Y-Position intressiert nicht + } + + nCurIndex = nCurIndex + pTmpLine->GetLen(); + } + + if ( !pLine ) // darf nur im Bereich von SA passieren! + { + #ifdef DBG_UTIL + const SvxULSpaceItem& rULSpace =(const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + DBG_ASSERT( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in keiner Zeile, GetPaM ?" ); + #endif + aPaM.SetIndex( pPortion->GetNode()->Len() ); + return aPaM; + } + + // Wenn Zeile gefunden, nur noch X-Position => Index + nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart ); + aPaM.SetIndex( nCurIndex ); + + if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && + ( pLine != pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1) ) ) + { + aPaM = CursorLeft( aPaM, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + } + + return aPaM; +} + +USHORT ImpEditEngine::GetChar( ParaPortion* pParaPortion, EditLine* pLine, long nXPos, BOOL bSmart ) +{ + DBG_ASSERT( pLine, "Keine Zeile erhalten: GetChar" ); + + USHORT nChar = 0xFFFF; + USHORT nCurIndex = pLine->GetStart(); + + + // Search best matching portion with GetPortionXOffset() + for ( USHORT i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) + { + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i ); + long nXLeft = GetPortionXOffset( pParaPortion, pLine, i ); + long nXRight = nXLeft + pPortion->GetSize().Width(); + if ( ( nXLeft <= nXPos ) && ( nXRight >= nXPos ) ) + { + nChar = nCurIndex; + + // Search within Portion... + + // Don't search within special portions... + if ( pPortion->GetKind() != PORTIONKIND_TEXT ) + { + // ...but check on which side + if ( bSmart ) + { + long nLeftDiff = nXPos-nXLeft; + long nRightDiff = nXRight-nXPos; + if ( nRightDiff < nLeftDiff ) + nChar++; + } + } + else + { + USHORT nMax = pPortion->GetLen(); + USHORT nOffset = 0xFFFF; + USHORT nTmpCurIndex = nChar - pLine->GetStart(); + + long nXInPortion = nXPos - nXLeft; + if ( pPortion->IsRightToLeft() ) + nXInPortion = nXRight - nXPos; + + // Search in Array... + for ( USHORT x = 0; x < nMax; x++ ) + { + long nTmpPosMax = pLine->GetCharPosArray().GetObject( nTmpCurIndex+x ); + if ( nTmpPosMax > nXInPortion ) + { + // pruefen, ob dieser oder der davor... + long nTmpPosMin = x ? pLine->GetCharPosArray().GetObject( nTmpCurIndex+x-1 ) : 0; + long nDiffLeft = nXInPortion - nTmpPosMin; + long nDiffRight = nTmpPosMax - nXInPortion; + DBG_ASSERT( nDiffLeft >= 0, "DiffLeft negativ" ); + DBG_ASSERT( nDiffRight >= 0, "DiffRight negativ" ); + nOffset = ( bSmart && ( nDiffRight < nDiffLeft ) ) ? x+1 : x; + // I18N: If there are character position with the length of 0, + // they belong to the same character, we can not use this position as an index. + // Skip all 0-positions, cheaper than using XBreakIterator: + if ( nOffset < nMax ) + { + const long nX = pLine->GetCharPosArray().GetObject(nOffset); + while ( ( (nOffset+1) < nMax ) && ( pLine->GetCharPosArray().GetObject(nOffset+1) == nX ) ) + nOffset++; + } + break; + } + } + + // Bei Verwendung des CharPosArray duerfte es keine Ungenauigkeiten geben! + // Vielleicht bei Kerning ? + // 0xFFF passiert z.B. bei Outline-Font, wenn ganz hinten. + if ( nOffset == 0xFFFF ) + nOffset = nMax; + + DBG_ASSERT( nOffset <= nMax, "nOffset > nMax" ); + + nChar = nChar + nOffset; + + // Check if index is within a cell: + if ( nChar && ( nChar < pParaPortion->GetNode()->Len() ) ) + { + EditPaM aPaM( pParaPortion->GetNode(), nChar+1 ); + USHORT nScriptType = GetScriptType( aPaM ); + if ( nScriptType == i18n::ScriptType::COMPLEX ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int32 nCount = 1; + lang::Locale aLocale = GetLocale( aPaM ); + USHORT nRight = (USHORT)_xBI->nextCharacters( *pParaPortion->GetNode(), nChar, aLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); + USHORT nLeft = (USHORT)_xBI->previousCharacters( *pParaPortion->GetNode(), nRight, aLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); + if ( ( nLeft != nChar ) && ( nRight != nChar ) ) + { + nChar = ( Abs( nRight - nChar ) < Abs( nLeft - nChar ) ) ? nRight : nLeft; + } + } + } + } + } + + nCurIndex = nCurIndex + pPortion->GetLen(); + } + + if ( nChar == 0xFFFF ) + { + nChar = ( nXPos <= pLine->GetStartPosX() ) ? pLine->GetStart() : pLine->GetEnd(); + } + + return nChar; +} + +Range ImpEditEngine::GetLineXPosStartEnd( ParaPortion* pParaPortion, EditLine* pLine ) +{ + Range aLineXPosStartEnd; + + USHORT nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); + if ( !IsRightToLeft( nPara ) ) + { + aLineXPosStartEnd.Min() = pLine->GetStartPosX(); + aLineXPosStartEnd.Max() = pLine->GetStartPosX() + pLine->GetTextWidth(); + } + else + { + aLineXPosStartEnd.Min() = GetPaperSize().Width() - ( pLine->GetStartPosX() + pLine->GetTextWidth() ); + aLineXPosStartEnd.Max() = GetPaperSize().Width() - pLine->GetStartPosX(); + } + + + return aLineXPosStartEnd; +} + +long ImpEditEngine::GetPortionXOffset( ParaPortion* pParaPortion, EditLine* pLine, USHORT nTextPortion ) +{ + long nX = pLine->GetStartPosX(); + + for ( USHORT i = pLine->GetStartPortion(); i < nTextPortion; i++ ) + { + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i ); + switch ( pPortion->GetKind() ) + { + case PORTIONKIND_FIELD: + case PORTIONKIND_TEXT: + case PORTIONKIND_HYPHENATOR: + case PORTIONKIND_TAB: +// case PORTIONKIND_EXTRASPACE: + { + nX += pPortion->GetSize().Width(); + } + break; + } + } + + USHORT nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); + BOOL bR2LPara = IsRightToLeft( nPara ); + + TextPortion* pDestPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + if ( pDestPortion->GetKind() != PORTIONKIND_TAB ) + { + if ( !bR2LPara && pDestPortion->GetRightToLeft() ) + { + // Portions behind must be added, visual before this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetSize().Width(); + else + break; + nTmpPortion++; + } + // Portions before must be removed, visual behind this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetSize().Width(); + else + break; + } + } + else if ( bR2LPara && !pDestPortion->IsRightToLeft() ) + { + // Portions behind must be ermoved, visual behind this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetSize().Width(); + else + break; + nTmpPortion++; + } + // Portions before must be added, visual before this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetSize().Width(); + else + break; + } + } + } + if ( bR2LPara ) + { + // Switch X postions... + DBG_ASSERT( GetTextRanger() || GetPaperSize().Width(), "GetPortionXOffset - paper size?!" ); + DBG_ASSERT( GetTextRanger() || (nX <= GetPaperSize().Width()), "GetPortionXOffset - position out of paper size!" ); + nX = GetPaperSize().Width() - nX; + nX -= pDestPortion->GetSize().Width(); + } + + return nX; +} + +long ImpEditEngine::GetXPos( ParaPortion* pParaPortion, EditLine* pLine, USHORT nIndex, BOOL bPreferPortionStart ) +{ + DBG_ASSERT( pLine, "Keine Zeile erhalten: GetXPos" ); + DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "GetXPos muss richtig gerufen werden!" ); + + BOOL bDoPreferPortionStart = bPreferPortionStart; + // Assure that the portion belongs to this line: + if ( nIndex == pLine->GetStart() ) + bDoPreferPortionStart = TRUE; + else if ( nIndex == pLine->GetEnd() ) + bDoPreferPortionStart = FALSE; + + USHORT nTextPortionStart = 0; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); + + DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " ); + + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + + long nX = GetPortionXOffset( pParaPortion, pLine, nTextPortion ); + + // calc text width, portion size may include CJK/CTL spacing... + // But the array migh not be init yet, if using text ranger this method is called within CreateLines()... + long nPortionTextWidth = pPortion->GetSize().Width(); + if ( ( pPortion->GetKind() == PORTIONKIND_TEXT ) && pPortion->GetLen() && !GetTextRanger() ) + nPortionTextWidth = pLine->GetCharPosArray().GetObject( nTextPortionStart + pPortion->GetLen() - 1 - pLine->GetStart() ); + + if ( nTextPortionStart != nIndex ) + { + // Search within portion... + if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) + { + // End of Portion + if ( pPortion->GetKind() == PORTIONKIND_TAB ) + { + if ( (nTextPortion+1) < pParaPortion->GetTextPortions().Count() ) + { + TextPortion* pNextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion+1 ); + if ( pNextPortion->GetKind() != PORTIONKIND_TAB ) + { + // DBG_ASSERT( !bPreferPortionStart, "GetXPos - How can we this tab portion here???" ); + // #109879# We loop if nIndex == pLine->GetEnd, because bPreferPortionStart will be reset + if ( !bPreferPortionStart ) + nX = GetXPos( pParaPortion, pLine, nIndex, TRUE ); + else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) + nX += nPortionTextWidth; + } + } + else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) + { + nX += nPortionTextWidth; + } + } + else if ( !pPortion->IsRightToLeft() ) + { + nX += nPortionTextWidth; + } + } + else if ( pPortion->GetKind() == PORTIONKIND_TEXT ) + { + DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new GetXPos()" ); + DBG_ASSERT( pLine && pLine->GetCharPosArray().Count(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" ); + + if( pLine->GetCharPosArray().Count() ) + { + USHORT nPos = nIndex - 1 - pLine->GetStart(); + if( nPos >= pLine->GetCharPosArray().Count() ) + { + nPos = pLine->GetCharPosArray().Count()-1; + DBG_ERROR("svx::ImpEditEngine::GetXPos(), index out of range!"); + } + + long nPosInPortion = pLine->GetCharPosArray().GetObject( nPos ); + + if ( !pPortion->IsRightToLeft() ) + { + nX += nPosInPortion; + } + else + { + nX += nPortionTextWidth - nPosInPortion; + } + + if ( pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed ) + { + nX += pPortion->GetExtraInfos()->nPortionOffsetX; + if ( pPortion->GetExtraInfos()->nAsianCompressionTypes & CHAR_PUNCTUATIONRIGHT ) + { + BYTE nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex ) ); + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + USHORT n = nIndex - nTextPortionStart; + const sal_Int32* pDXArray = pLine->GetCharPosArray().GetData()+( nTextPortionStart-pLine->GetStart() ); + sal_Int32 nCharWidth = ( ( (n+1) < pPortion->GetLen() ) ? pDXArray[n] : pPortion->GetSize().Width() ) + - ( n ? pDXArray[n-1] : 0 ); + if ( (n+1) < pPortion->GetLen() ) + { + // smaller, when char behind is CHAR_PUNCTUATIONRIGHT also + nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex+1 ) ); + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + sal_Int32 nNextCharWidth = ( ( (n+2) < pPortion->GetLen() ) ? pDXArray[n+1] : pPortion->GetSize().Width() ) + - pDXArray[n]; + sal_Int32 nCompressed = nNextCharWidth/2; + nCompressed *= pPortion->GetExtraInfos()->nMaxCompression100thPercent; + nCompressed /= 10000; + nCharWidth += nCompressed; + } + } + else + { + nCharWidth *= 2; // last char pos to portion end is only compressed size + } + nX += nCharWidth/2; // 50% compression + } + } + } + } + } + } + else // if ( nIndex == pLine->GetStart() ) + { + if ( pPortion->IsRightToLeft() ) + { + nX += nPortionTextWidth; + } + } + + return nX; +} + +void ImpEditEngine::CalcHeight( ParaPortion* pPortion ) +{ + pPortion->nHeight = 0; + pPortion->nFirstLineOffset = 0; + + if ( pPortion->IsVisible() ) + { + DBG_ASSERT( pPortion->GetLines().Count(), "Absatz ohne Zeilen in ParaPortion::CalcHeight" ); + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + pPortion->nHeight += pPortion->GetLines().GetObject( nLine )->GetHeight(); + + if ( !aStatus.IsOutliner() ) + { + const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + if ( nSBL ) + { + if ( pPortion->GetLines().Count() > 1 ) + pPortion->nHeight += ( pPortion->GetLines().Count() - 1 ) * nSBL; + if ( aStatus.ULSpaceSummation() ) + pPortion->nHeight += nSBL; + } + + USHORT nPortion = GetParaPortions().GetPos( pPortion ); + if ( nPortion || aStatus.ULSpaceFirstParagraph() ) + { + USHORT nUpper = GetYValue( rULItem.GetUpper() ); + pPortion->nHeight += nUpper; + pPortion->nFirstLineOffset = nUpper; + } + + if ( ( nPortion != (GetParaPortions().Count()-1) ) ) + { + pPortion->nHeight += GetYValue( rULItem.GetLower() ); // nicht in letzter + } + + + if ( nPortion && !aStatus.ULSpaceSummation() ) + { + ParaPortion* pPrev = GetParaPortions().SaveGetObject( nPortion-1 ); + const SvxULSpaceItem& rPrevULItem = (const SvxULSpaceItem&)pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rPrevLSItem = (const SvxLineSpacingItem&)pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + + // Verhalten WinWord6/Writer3: + // Bei einem proportionalen Zeilenabstand wird auch der Absatzabstand + // manipuliert. + // Nur Writer3: Nicht aufaddieren, sondern Mindestabstand. + + // Pruefen, ob Abstand durch LineSpacing > Upper: + USHORT nExtraSpace = GetYValue( lcl_CalcExtraSpace( pPortion, rLSItem ) ); + if ( nExtraSpace > pPortion->nFirstLineOffset ) + { + // Absatz wird 'groesser': + pPortion->nHeight += ( nExtraSpace - pPortion->nFirstLineOffset ); + pPortion->nFirstLineOffset = nExtraSpace; + } + + // nFirstLineOffset jetzt f(pNode) => jetzt f(pNode, pPrev) ermitteln: + USHORT nPrevLower = GetYValue( rPrevULItem.GetLower() ); + + // Dieser PrevLower steckt noch in der Hoehe der PrevPortion... + if ( nPrevLower > pPortion->nFirstLineOffset ) + { + // Absatz wird 'kleiner': + pPortion->nHeight -= pPortion->nFirstLineOffset; + pPortion->nFirstLineOffset = 0; + } + else if ( nPrevLower ) + { + // Absatz wird 'etwas kleiner': + pPortion->nHeight -= nPrevLower; + pPortion->nFirstLineOffset = + pPortion->nFirstLineOffset - nPrevLower; + } + + // Finde ich zwar nicht so gut, aber Writer3-Feature: + // Pruefen, ob Abstand durch LineSpacing > Lower: + // Dieser Wert steckt nicht in der Hoehe der PrevPortion. + if ( !pPrev->IsInvalid() ) + { + nExtraSpace = GetYValue( lcl_CalcExtraSpace( pPrev, rPrevLSItem ) ); + if ( nExtraSpace > nPrevLower ) + { + USHORT nMoreLower = nExtraSpace - nPrevLower; + // Absatz wird 'groesser', 'waechst' nach unten: + if ( nMoreLower > pPortion->nFirstLineOffset ) + { + pPortion->nHeight += ( nMoreLower - pPortion->nFirstLineOffset ); + pPortion->nFirstLineOffset = nMoreLower; + } + } + } + } + } + } +} + +Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, USHORT nIndex, USHORT nFlags ) +{ + DBG_ASSERT( pPortion->IsVisible(), "Wozu GetEditCursor() bei einem unsichtbaren Absatz?" ); + DBG_ASSERT( IsFormatted() || GetTextRanger(), "GetEditCursor: Nicht formatiert" ); + + /* + GETCRSR_ENDOFLINE: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile, + am Ende der Zeile bleiben, nicht am Anfang der naechsten. + Zweck: - END => wirklich hinter das letzte Zeichen + - Selektion.... + */ + + long nY = pPortion->GetFirstLineOffset(); + + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + USHORT nCurIndex = 0; + DBG_ASSERT( pPortion->GetLines().Count(), "Leere ParaPortion in GetEditCursor!" ); + EditLine* pLine = 0; + BOOL bEOL = ( nFlags & GETCRSR_ENDOFLINE ) ? TRUE : FALSE; + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); + if ( ( pTmpLine->GetStart() == nIndex ) || ( pTmpLine->IsIn( nIndex, bEOL ) ) ) + { + pLine = pTmpLine; + break; + } + + nCurIndex = nCurIndex + pTmpLine->GetLen(); + nY += pTmpLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY += nSBL; + } + if ( !pLine ) + { + // Cursor am Ende des Absatzes. + DBG_ASSERT( nIndex == nCurIndex, "Index voll daneben in GetEditCursor!" ); + + pLine = pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1 ); + nY -= pLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY -= nSBL; + nCurIndex = nCurIndex - pLine->GetLen(); + } + + Rectangle aEditCursor; + + aEditCursor.Top() = nY; + nY += pLine->GetHeight(); + aEditCursor.Bottom() = nY-1; + + // innerhalb der Zeile suchen... + long nX; + + if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GETCRSR_STARTOFLINE ) ) + { + Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); + nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max(); + } + else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GETCRSR_ENDOFLINE ) ) + { + Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); + nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min(); + } + else + { + nX = GetXPos( pPortion, pLine, nIndex, ( nFlags & GETCRSR_PREFERPORTIONSTART ) ? TRUE : FALSE ); + } + + aEditCursor.Left() = aEditCursor.Right() = nX; + + if ( nFlags & GETCRSR_TXTONLY ) + aEditCursor.Top() = aEditCursor.Bottom() - pLine->GetTxtHeight() + 1; + else + aEditCursor.Top() = aEditCursor.Bottom() - Min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1; + + return aEditCursor; +} + +void ImpEditEngine::SetValidPaperSize( const Size& rNewSz ) +{ + aPaperSize = rNewSz; + + long nMinWidth = aStatus.AutoPageWidth() ? aMinAutoPaperSize.Width() : 0; + long nMaxWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : 0x7FFFFFFF; + long nMinHeight = aStatus.AutoPageHeight() ? aMinAutoPaperSize.Height() : 0; + long nMaxHeight = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : 0x7FFFFFFF; + + // Minimale/Maximale Breite: + if ( aPaperSize.Width() < nMinWidth ) + aPaperSize.Width() = nMinWidth; + else if ( aPaperSize.Width() > nMaxWidth ) + aPaperSize.Width() = nMaxWidth; + + // Minimale/Maximale Hoehe: + if ( aPaperSize.Height() < nMinHeight ) + aPaperSize.Height() = nMinHeight; + else if ( aPaperSize.Height() > nMaxHeight ) + aPaperSize.Height() = nMaxHeight; +} + +void ImpEditEngine::IndentBlock( EditView* pEditView, BOOL bRight ) +{ + ESelection aESel( CreateESel( pEditView->pImpEditView->GetEditSelection() ) ); + aESel.Adjust(); + + // Nur wenn mehrere selektierte Absaetze... + if ( aESel.nEndPara > aESel.nStartPara ) + { + ESelection aNewSel = aESel; + aNewSel.nStartPos = 0; + aNewSel.nEndPos = 0xFFFF; + + if ( aESel.nEndPos == 0 ) + { + aESel.nEndPara--; // dann diesen Absatz nicht... + aNewSel.nEndPos = 0; + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( + pEditView->pImpEditView->GetEditSelection().Max() ); + UndoActionStart( bRight ? EDITUNDO_INDENTBLOCK : EDITUNDO_UNINDENTBLOCK ); + + for ( USHORT nPara = aESel.nStartPara; nPara <= aESel.nEndPara; nPara++ ) + { + ContentNode* pNode = GetEditDoc().GetObject( nPara ); + if ( bRight ) + { + // Tabs hinzufuegen + EditPaM aPaM( pNode, 0 ); + InsertTab( aPaM ); + } + else + { + // Tabs entfernen + EditCharAttrib* pFeature = pNode->GetCharAttribs().FindFeature( 0 ); + if ( pFeature && ( pFeature->GetStart() == 0 ) && + ( pFeature->GetItem()->Which() == EE_FEATURE_TAB ) ) + { + EditPaM aStartPaM( pNode, 0 ); + EditPaM aEndPaM( pNode, 1 ); + ImpDeleteSelection( EditSelection( aStartPaM, aEndPaM ) ); + } + } + } + + UndoActionEnd( bRight ? EDITUNDO_INDENTBLOCK : EDITUNDO_UNINDENTBLOCK ); + UpdateSelections(); + FormatAndUpdate( pEditView ); + + ContentNode* pLastNode = GetEditDoc().GetObject( aNewSel.nEndPara ); + if ( pLastNode->Len() < aNewSel.nEndPos ) + aNewSel.nEndPos = pLastNode->Len(); + pEditView->pImpEditView->SetEditSelection( CreateSel( aNewSel ) ); + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->ShowCursor( FALSE, TRUE ); + } +} + +vos::ORef<SvxForbiddenCharactersTable> ImpEditEngine::GetForbiddenCharsTable( BOOL bGetInternal ) const +{ + vos::ORef<SvxForbiddenCharactersTable> xF = xForbiddenCharsTable; + if ( !xF.isValid() && bGetInternal ) + xF = EE_DLL()->GetGlobalData()->GetForbiddenCharsTable(); + return xF; +} + +void ImpEditEngine::SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) +{ + EE_DLL()->GetGlobalData()->SetForbiddenCharsTable( xForbiddenChars ); +} + +svtools::ColorConfig& ImpEditEngine::GetColorConfig() +{ + if ( !pColorConfig ) + pColorConfig = new svtools::ColorConfig; + + return *pColorConfig; +} + +BOOL ImpEditEngine::IsVisualCursorTravelingEnabled() +{ + BOOL bVisualCursorTravaling = FALSE; + + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + if ( pCTLOptions->IsCTLFontEnabled() && ( pCTLOptions->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) ) + { + bVisualCursorTravaling = TRUE; + } + + return bVisualCursorTravaling; + +} + +BOOL ImpEditEngine::DoVisualCursorTraveling( const ContentNode* ) +{ + // Don't check if it's necessary, because we also need it when leaving the paragraph + return IsVisualCursorTravelingEnabled(); +/* + BOOL bDoVisualCursorTraveling = FALSE; + + if ( IsVisualCursorTravelingEnabled() && pNode->Len() ) + { + // Only necessary when RTL text in LTR para or LTR text in RTL para + bDoVisualCursorTraveling = HasDifferentRTLLevels( pNode ); + } + + return bDoVisualCursorTraveling; +*/ +} + + +void ImpEditEngine::CallNotify( EENotify& rNotify ) +{ + if ( !nBlockNotifications ) + { + GetNotifyHdl().Call( &rNotify ); + } + else + { + EENotify* pNewNotify = new EENotify( rNotify ); + aNotifyCache.Insert( pNewNotify, aNotifyCache.Count() ); + } +} + +void ImpEditEngine::EnterBlockNotifications() +{ + if( !nBlockNotifications ) + { + // #109864# Send out START notification immediately, to allow + // external, non-queued events to be captured as well from + // client side + EENotify aNotify( EE_NOTIFY_BLOCKNOTIFICATION_START ); + aNotify.pEditEngine = GetEditEnginePtr(); + GetNotifyHdl().Call( &aNotify ); + } + + nBlockNotifications++; +} + +void ImpEditEngine::LeaveBlockNotifications() +{ + DBG_ASSERT( nBlockNotifications, "LeaveBlockNotifications - Why?" ); + + nBlockNotifications--; + if ( !nBlockNotifications ) + { + // Call blocked notify events... + while ( aNotifyCache.Count() ) + { + EENotify* pNotify = aNotifyCache[0]; + // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler... + aNotifyCache.Remove( 0 ); + GetNotifyHdl().Call( pNotify ); + delete pNotify; + } + + EENotify aNotify( EE_NOTIFY_BLOCKNOTIFICATION_END ); + aNotify.pEditEngine = GetEditEnginePtr(); + GetNotifyHdl().Call( &aNotify ); + } +} + +IMPL_LINK( ImpEditEngine, DocModified, void*, EMPTYARG ) +{ + aModifyHdl.Call( NULL /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner + return 0; +} diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx new file mode 100644 index 000000000000..dbc6767d1f91 --- /dev/null +++ b/editeng/source/editeng/impedit3.cxx @@ -0,0 +1,4677 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <vcl/metaact.hxx> +#include <vcl/gdimtf.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <vcl/wrkwin.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/flditem.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/txtrange.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/numitem.hxx> + +#include <svtools/colorcfg.hxx> +#include <svl/ctloptions.hxx> + +#include <editeng/forbiddencharacterstable.hxx> + +#include <unotools/localedatawrapper.hxx> + +#include <editeng/unolingu.hxx> + +#include <math.h> +#include <vcl/svapp.hxx> +#include <vcl/metric.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/text/CharacterCompressionType.hpp> +#include <vcl/pdfextoutdevdata.hxx> +#include <i18npool/mslangid.hxx> + +#include <comphelper/processfactory.hxx> + +using ::rtl::OUString; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + +SV_DECL_VARARR_SORT( SortedPositions, sal_uInt32, 16, 8 ) +SV_IMPL_VARARR_SORT( SortedPositions, sal_uInt32 ); + +#define CH_HYPH '-' + +#define RESDIFF 10 + +#define WRONG_SHOW_MIN 5 +#define WRONG_SHOW_SMALL 11 +#define WRONG_SHOW_MEDIUM 15 + +struct TabInfo +{ + BOOL bValid; + + SvxTabStop aTabStop; + xub_StrLen nCharPos; + USHORT nTabPortion; + long nStartPosX; + long nTabPos; + + TabInfo() { bValid = FALSE; } +}; + +Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin ) +{ + double nRealOrientation = nOrientation*F_PI1800; + double nCos = cos( nRealOrientation ); + double nSin = sin( nRealOrientation ); + + Point aRotatedPos; + Point aTranslatedPos( rPoint ); + + // Translation + aTranslatedPos -= rOrigin; + + // Rotation... + aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ); + aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() ); + aTranslatedPos = aRotatedPos; + + // Translation... + aTranslatedPos += rOrigin; + return aTranslatedPos; +} + +BYTE GetCharTypeForCompression( xub_Unicode cChar ) +{ + switch ( cChar ) + { + case 0x3008: case 0x300A: case 0x300C: case 0x300E: + case 0x3010: case 0x3014: case 0x3016: case 0x3018: + case 0x301A: case 0x301D: + { + return CHAR_PUNCTUATIONRIGHT; + } + case 0x3001: case 0x3002: case 0x3009: case 0x300B: + case 0x300D: case 0x300F: case 0x3011: case 0x3015: + case 0x3017: case 0x3019: case 0x301B: case 0x301E: + case 0x301F: + { + return CHAR_PUNCTUATIONLEFT; + } + default: + { + return ( ( 0x3040 <= cChar ) && ( 0x3100 > cChar ) ) ? CHAR_KANA : CHAR_NORMAL; + } + } +} + +void lcl_DrawRedLines( + OutputDevice* pOutDev, + long nFontHeight, + const Point& rPnt, + sal_uInt16 nIndex, + sal_uInt16 nMaxEnd, + const sal_Int32* pDXArray, + WrongList* pWrongs, + short nOrientation, + const Point& rOrigin, + BOOL bVertical, + BOOL bIsRightToLeft ) +{ +#ifndef SVX_LIGHT + // Aber nur, wenn Font nicht zu klein... + long nHght = pOutDev->LogicToPixel( Size( 0, nFontHeight ) ).Height(); + if( WRONG_SHOW_MIN < nHght ) + { + sal_uInt16 nStyle; + if( WRONG_SHOW_MEDIUM < nHght ) + nStyle = WAVE_NORMAL; + else if( WRONG_SHOW_SMALL < nHght ) + nStyle = WAVE_SMALL; + else + nStyle = WAVE_FLAT; + + sal_uInt16 nEnd, nStart = nIndex; + sal_Bool bWrong = pWrongs->NextWrong( nStart, nEnd ); + while ( bWrong ) + { + if ( nStart >= nMaxEnd ) + break; + + if ( nStart < nIndex ) // Wurde korrigiert + nStart = nIndex; + if ( nEnd > nMaxEnd ) + nEnd = nMaxEnd; + Point aPnt1( rPnt ); + if ( bVertical && ( nStyle != WAVE_FLAT ) ) + { + // VCL doesn't know that the text is vertical, and is manipulating + // the positions a little bit in y direction... + long nOnePixel = pOutDev->PixelToLogic( Size( 0, 1 ) ).Height(); + long nCorrect = ( nStyle == WAVE_NORMAL ) ? 2*nOnePixel : nOnePixel; + aPnt1.Y() -= nCorrect; + aPnt1.X() -= nCorrect; + } + if ( nStart > nIndex ) + { + if ( !bVertical ) + { + // since for RTL portions rPnt is on the visual right end of the portion + // (i.e. at the start of the first RTL char) we need to subtract the offset + // for RTL portions... + aPnt1.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nStart - nIndex - 1 ]; + } + else + aPnt1.Y() += pDXArray[ nStart - nIndex - 1 ]; + } + Point aPnt2( rPnt ); + DBG_ASSERT( nEnd > nIndex, "RedLine: aPnt2?" ); + if ( !bVertical ) + { + // since for RTL portions rPnt is on the visual right end of the portion + // (i.e. at the start of the first RTL char) we need to subtract the offset + // for RTL portions... + aPnt2.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nEnd - nIndex - 1 ]; + } + else + aPnt2.Y() += pDXArray[ nEnd - nIndex - 1 ]; + if ( nOrientation ) + { + aPnt1 = Rotate( aPnt1, nOrientation, rOrigin ); + aPnt2 = Rotate( aPnt2, nOrientation, rOrigin ); + } + + pOutDev->DrawWaveLine( aPnt1, aPnt2, nStyle ); + + nStart = nEnd+1; + if ( nEnd < nMaxEnd ) + bWrong = pWrongs->NextWrong( nStart, nEnd ); + else + bWrong = sal_False; + } + } +#endif // !SVX_LIGHT +} + +Point lcl_ImplCalcRotatedPos( Point rPos, Point rOrigin, double nSin, double nCos ) +{ + Point aRotatedPos; + // Translation... + Point aTranslatedPos( rPos); + aTranslatedPos -= rOrigin; + + aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ); + aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() ); + aTranslatedPos = aRotatedPos; + // Translation... + aTranslatedPos += rOrigin; + + return aTranslatedPos; +} + +sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh ) // For Kashidas from sw/source/core/text/porlay.txt +{ + // Lam + Alef + return ( 0x644 == cCh && 0x627 == cNextCh ) || + // Beh + Reh + ( 0x628 == cCh && 0x631 == cNextCh ); +} + +sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh ) // For Kashidas from sw/source/core/text/porlay.txt +{ + // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left + sal_Bool bRet = 0x627 != cPrevCh && 0x62F != cPrevCh && 0x630 != cPrevCh && + 0x631 != cPrevCh && 0x632 != cPrevCh && 0x648 != cPrevCh; + + // check for ligatures cPrevChar + cChar + if ( bRet ) + bRet = ! lcl_IsLigature( cPrevCh, cCh ); + + return bRet; +} + + +// ---------------------------------------------------------------------- +// class ImpEditEngine +// ---------------------------------------------------------------------- +void ImpEditEngine::UpdateViews( EditView* pCurView ) +{ + if ( !GetUpdateMode() || IsFormatting() || aInvalidRec.IsEmpty() ) + return; + + DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" ); + + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->HideCursor(); + + Rectangle aClipRec( aInvalidRec ); + Rectangle aVisArea( pView->GetVisArea() ); + aClipRec.Intersection( aVisArea ); + + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + aClipRec = pView->pImpEditView->GetWindowPos( aClipRec ); + + if ( ( pView == pCurView ) ) + Paint( pView->pImpEditView, aClipRec, sal_True ); + else + pView->GetWindow()->Invalidate( aClipRec ); + } + } + + if ( pCurView ) + { + sal_Bool bGotoCursor = pCurView->pImpEditView->DoAutoScroll(); + pCurView->ShowCursor( bGotoCursor ); + } + + aInvalidRec = Rectangle(); + CallStatusHdl(); +} + +IMPL_LINK( ImpEditEngine, OnlineSpellHdl, Timer *, EMPTYARG ) +{ + if ( !Application::AnyInput( INPUT_KEYBOARD ) && GetUpdateMode() && IsFormatted() ) + DoOnlineSpelling(); + else + aOnlineSpellTimer.Start(); + + return 0; +} + +IMPL_LINK_INLINE_START( ImpEditEngine, IdleFormatHdl, Timer *, EMPTYARG ) +{ + aIdleFormatter.ResetRestarts(); + + // #i97146# check if that view is still available + // else probably the idle format timer fired while we're already + // downing + EditView* pView = aIdleFormatter.GetView(); + for( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + if( aEditViews[nView] == pView ) + { + FormatAndUpdate( pView ); + break; + } + } + return 0; +} +IMPL_LINK_INLINE_END( ImpEditEngine, IdleFormatHdl, Timer *, EMPTYARG ) + +void ImpEditEngine::CheckIdleFormatter() +{ + aIdleFormatter.ForceTimeout(); + // Falls kein Idle, aber trotzdem nicht formatiert: + if ( !IsFormatted() ) + FormatDoc(); +} + +void ImpEditEngine::FormatFullDoc() +{ + for ( sal_uInt16 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + GetParaPortions()[nPortion]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion]->GetNode()->Len() ); + FormatDoc(); +} + +void ImpEditEngine::FormatDoc() +{ + if ( !GetUpdateMode() || IsFormatting() ) + return; + + EnterBlockNotifications(); + + bIsFormatting = sal_True; + + // Dann kann ich auch den Spell-Timer starten... + if ( GetStatus().DoOnlineSpelling() ) + StartOnlineSpellTimer(); + + long nY = 0; + sal_Bool bGrow = sal_False; + + Font aOldFont( GetRefDevice()->GetFont() ); + + // Hier schon, damit nicht jedesmal in CreateLines... + sal_Bool bMapChanged = ImpCheckRefMapMode(); + + aInvalidRec = Rectangle(); // leermachen + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + if ( pParaPortion->MustRepaint() || ( pParaPortion->IsInvalid() && pParaPortion->IsVisible() ) ) + { + if ( pParaPortion->IsInvalid() ) + { + sal_Bool bChangedByDerivedClass = GetEditEnginePtr()->FormattingParagraph( nPara ); + if ( bChangedByDerivedClass ) + { + pParaPortion->GetTextPortions().Reset(); + pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() ); + } + } + // bei MustRepaint() sollte keine Formatierung noetig sein! + // 23.1.95: Evtl. ist sie durch eine andere Aktion aber doch + // ungueltig geworden! +// if ( pParaPortion->MustRepaint() || CreateLines( nPara ) ) + if ( ( pParaPortion->MustRepaint() && !pParaPortion->IsInvalid() ) + || CreateLines( nPara, nY ) ) + { + if ( !bGrow && GetTextRanger() ) + { + // Bei einer Aenderung der Hoehe muss alles weiter unten + // neu formatiert werden... + for ( sal_uInt16 n = nPara+1; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPP = GetParaPortions().GetObject( n ); + pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() ); + pPP->GetLines().Reset(); + } + } + bGrow = sal_True; + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphHeightChanged( nPara ); + pParaPortion->SetMustRepaint( sal_False ); + } + + // InvalidRec nur einmal setzen... + if ( aInvalidRec.IsEmpty() ) + { + // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()... + long nWidth = Max( (long)1, ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) ); + Range aInvRange( GetInvalidYOffsets( pParaPortion ) ); + aInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ), + Size( nWidth, aInvRange.Len() ) ); + } + else + { + aInvalidRec.Bottom() = nY + pParaPortion->GetHeight(); + } + } + else if ( bGrow ) + { + aInvalidRec.Bottom() = nY + pParaPortion->GetHeight(); + } + nY += pParaPortion->GetHeight(); + } + + // Man kann auch durch UpdateMode An=>AUS=>AN in die Formatierung gelangen... + // Optimierung erst nach Vobis-Auslieferung aktivieren... +// if ( !aInvalidRec.IsEmpty() ) + { + sal_uInt32 nNewHeight = CalcTextHeight(); + long nDiff = nNewHeight - nCurTextHeight; + if ( nDiff ) + aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED : EE_STAT_TEXTWIDTHCHANGED; + if ( nNewHeight < nCurTextHeight ) + { + aInvalidRec.Bottom() = (long)Max( nNewHeight, nCurTextHeight ); + if ( aInvalidRec.IsEmpty() ) + { + aInvalidRec.Top() = 0; + // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt. + aInvalidRec.Left() = 0; + aInvalidRec.Right() = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height(); + } + } + + nCurTextHeight = nNewHeight; + + if ( aStatus.AutoPageSize() ) + CheckAutoPageSize(); + else if ( nDiff ) + { + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + ImpEditView* pImpView = pView->pImpEditView; + if ( pImpView->DoAutoHeight() ) + { + Size aSz( pImpView->GetOutputArea().GetWidth(), nCurTextHeight ); + if ( aSz.Height() > aMaxAutoPaperSize.Height() ) + aSz.Height() = aMaxAutoPaperSize.Height(); + else if ( aSz.Height() < aMinAutoPaperSize.Height() ) + aSz.Height() = aMinAutoPaperSize.Height(); + pImpView->ResetOutputArea( Rectangle( + pImpView->GetOutputArea().TopLeft(), aSz ) ); + } + } + } + } + + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( aOldFont ); + bIsFormatting = sal_False; + bFormatted = sal_True; + + if ( bMapChanged ) + GetRefDevice()->Pop(); + + CallStatusHdl(); // Falls Modified... + + LeaveBlockNotifications(); +} + +sal_Bool ImpEditEngine::ImpCheckRefMapMode() +{ + sal_Bool bChange = sal_False; + + if ( aStatus.DoFormat100() ) + { + MapMode aMapMode( GetRefDevice()->GetMapMode() ); + if ( aMapMode.GetScaleX().GetNumerator() != aMapMode.GetScaleX().GetDenominator() ) + bChange = sal_True; + else if ( aMapMode.GetScaleY().GetNumerator() != aMapMode.GetScaleY().GetDenominator() ) + bChange = sal_True; + + if ( bChange ) + { + Fraction Scale1( 1, 1 ); + aMapMode.SetScaleX( Scale1 ); + aMapMode.SetScaleY( Scale1 ); + GetRefDevice()->Push(); + GetRefDevice()->SetMapMode( aMapMode ); + } + } + + return bChange; +} + +void ImpEditEngine::CheckAutoPageSize() +{ + Size aPrevPaperSize( GetPaperSize() ); + if ( GetStatus().AutoPageWidth() ) + aPaperSize.Width() = (long) !IsVertical() ? CalcTextWidth( TRUE ) : GetTextHeight(); + if ( GetStatus().AutoPageHeight() ) + aPaperSize.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( TRUE ); + + SetValidPaperSize( aPaperSize ); //Min, Max beruecksichtigen + + if ( aPaperSize != aPrevPaperSize ) + { + if ( ( !IsVertical() && ( aPaperSize.Width() != aPrevPaperSize.Width() ) ) + || ( IsVertical() && ( aPaperSize.Height() != aPrevPaperSize.Height() ) ) ) + { + // Falls davor zentriert/rechts oder Tabs... + aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED : EE_STAT_TEXTHEIGHTCHANGED; + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + // Es brauchen nur Absaetze neu formatiert werden, + // die nicht linksbuendig sind. + // Die Hoehe kann sich hier nicht mehr aendern. + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + ContentNode* pNode = pParaPortion->GetNode(); + SvxAdjust eJustification = GetJustification( nPara ); + if ( eJustification != SVX_ADJUST_LEFT ) + { + pParaPortion->MarkSelectionInvalid( 0, pNode->Len() ); + CreateLines( nPara, 0 ); // 0: Bei AutoPageSize kein TextRange! + } + } + } + + Size aInvSize = aPaperSize; + if ( aPaperSize.Width() < aPrevPaperSize.Width() ) + aInvSize.Width() = aPrevPaperSize.Width(); + if ( aPaperSize.Height() < aPrevPaperSize.Height() ) + aInvSize.Height() = aPrevPaperSize.Height(); + + Size aSz( aInvSize ); + if ( IsVertical() ) + { + aSz.Width() = aInvSize.Height(); + aSz.Height() = aInvSize.Width(); + } + aInvalidRec = Rectangle( Point(), aSz ); + + + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + pView->pImpEditView->RecalcOutputArea(); + } + } +} + +static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight ) +{ + return ( nFontHeight * 12 ) / 10; // + 20% +} + +sal_Bool ImpEditEngine::CreateLines( USHORT nPara, sal_uInt32 nStartPosY ) +{ + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + + // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False + DBG_ASSERT( pParaPortion->GetNode(), "Portion ohne Node in CreateLines" ); + DBG_ASSERT( pParaPortion->IsVisible(), "Unsichtbare Absaetze nicht formatieren!" ); + DBG_ASSERT( pParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" ); + + BOOL bProcessingEmptyLine = ( pParaPortion->GetNode()->Len() == 0 ); + BOOL bEmptyNodeWithPolygon = ( pParaPortion->GetNode()->Len() == 0 ) && GetTextRanger(); + + // --------------------------------------------------------------- + // Schnelle Sonderbehandlung fuer leere Absaetze... + // --------------------------------------------------------------- + if ( ( pParaPortion->GetNode()->Len() == 0 ) && !GetTextRanger() ) + { + // schnelle Sonderbehandlung... + if ( pParaPortion->GetTextPortions().Count() ) + pParaPortion->GetTextPortions().Reset(); + if ( pParaPortion->GetLines().Count() ) + pParaPortion->GetLines().Reset(); + CreateAndInsertEmptyLine( pParaPortion, nStartPosY ); + return FinishCreateLines( pParaPortion ); + } + + // --------------------------------------------------------------- + // Initialisierung...... + // --------------------------------------------------------------- + + // Immer fuer 100% formatieren: + sal_Bool bMapChanged = ImpCheckRefMapMode(); + + if ( pParaPortion->GetLines().Count() == 0 ) + { + EditLine* pL = new EditLine; + pParaPortion->GetLines().Insert( pL, 0 ); + } + + // --------------------------------------------------------------- + // Absatzattribute holen...... + // --------------------------------------------------------------- + ContentNode* const pNode = pParaPortion->GetNode(); + + BOOL bRightToLeftPara = IsRightToLeft( nPara ); + + SvxAdjust eJustification = GetJustification( nPara ); + sal_Bool bHyphenatePara = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HYPHENATE )).GetValue(); + sal_Int32 nSpaceBefore = 0; + sal_Int32 nMinLabelWidth = 0; + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pNode, &nSpaceBefore, &nMinLabelWidth ); + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pNode ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&) pNode->GetContentAttribs().GetItem( EE_PARA_SBL ); + const BOOL bScriptSpace = ((const SvxScriptSpaceItem&) pNode->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING )).GetValue(); + +// const sal_uInt16 nInvalidEnd = ( pParaPortion->GetInvalidDiff() > 0 ) +// ? pParaPortion->GetInvalidPosStart() + pParaPortion->GetInvalidDiff() +// : pNode->Len(); + const short nInvalidDiff = pParaPortion->GetInvalidDiff(); + const sal_uInt16 nInvalidStart = pParaPortion->GetInvalidPosStart(); + const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff ); + + sal_Bool bQuickFormat = sal_False; + if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) ) + { + if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) && + ( pNode->Search( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) ) + { + bQuickFormat = sal_True; + } + else if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) ) + { + // pruefen, ob loeschen ueber Portiongrenzen erfolgte... + sal_uInt16 nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!! + sal_uInt16 nEnd = nStart - nInvalidDiff; // neg. + bQuickFormat = sal_True; + sal_uInt16 nPos = 0; + sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count(); + for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ ) + { + // Es darf kein Start/Ende im geloeschten Bereich liegen. + TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ]; + nPos = nPos + pTP->GetLen(); + if ( ( nPos > nStart ) && ( nPos < nEnd ) ) + { + bQuickFormat = sal_False; + break; + } + } + } + } + + // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it... + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + + GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + + ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF ); + + sal_uInt16 nRealInvalidStart = nInvalidStart; + + if ( bEmptyNodeWithPolygon ) + { + TextPortion* pDummyPortion = new TextPortion( 0 ); + pParaPortion->GetTextPortions().Reset(); + pParaPortion->GetTextPortions().Insert( pDummyPortion, 0 ); + } + else if ( bQuickFormat ) + { + // schnellere Methode: + RecalcTextPortion( pParaPortion, nInvalidStart, nInvalidDiff ); + } + else // nRealInvalidStart kann vor InvalidStart liegen, weil Portions geloescht.... + { + CreateTextPortions( pParaPortion, nRealInvalidStart ); + } + + + // --------------------------------------------------------------- + // Zeile mit InvalidPos suchen, eine Zeile davor beginnen... + // Zeilen flaggen => nicht removen ! + // --------------------------------------------------------------- + + sal_uInt16 nLine = pParaPortion->GetLines().Count()-1; + for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) + { + EditLine* pLine = pParaPortion->GetLines().GetObject( nL ); + if ( pLine->GetEnd() > nRealInvalidStart ) // nicht nInvalidStart! + { + nLine = nL; + break; + } + pLine->SetValid(); + } + // Eine Zeile davor beginnen... + // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern. + if ( nLine && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) ) + nLine--; + + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + + static Rectangle aZeroArea = Rectangle( Point(), Point() ); + Rectangle aBulletArea( aZeroArea ); + if ( !nLine ) + { + aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) ); + if ( aBulletArea.Right() > 0 ) + pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) ); + else + pParaPortion->SetBulletX( 0 ); // Falls Bullet falsch eingestellt. + } + + // --------------------------------------------------------------- + // Ab hier alle Zeilen durchformatieren... + // --------------------------------------------------------------- + sal_uInt16 nDelFromLine = 0xFFFF; + sal_Bool bLineBreak = sal_False; + + sal_uInt16 nIndex = pLine->GetStart(); + EditLine aSaveLine( *pLine ); + SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() ); + + sal_Bool bCalcCharPositions = sal_True; + sal_Int32* pBuf = new sal_Int32[ pNode->Len() ]; + + sal_Bool bSameLineAgain = sal_False; // Fuer TextRanger, wenn sich die Hoehe aendert. + TabInfo aCurrentTab; + + BOOL bForceOneRun = bEmptyNodeWithPolygon; + BOOL bCompressedChars = FALSE; + + while ( ( nIndex < pNode->Len() ) || bForceOneRun ) + { + bForceOneRun = FALSE; + + sal_Bool bEOL = sal_False; + sal_Bool bEOC = sal_False; + sal_uInt16 nPortionStart = 0; + sal_uInt16 nPortionEnd = 0; + + long nStartX = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth ); + if ( nIndex == 0 ) + { + long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() ); + nStartX += nFI; + + if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) ) + { +// TL_NFLR nStartX += nFI; // Vielleicht reicht der LI? +// TL_NFLR if ( pParaPortion->GetBulletX() > nStartX ) + nStartX = pParaPortion->GetBulletX(); + } + } + + long nMaxLineWidth; + if ( !IsVertical() ) + nMaxLineWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : aPaperSize.Width(); + else + nMaxLineWidth = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : aPaperSize.Height(); + + nMaxLineWidth -= GetXValue( rLRItem.GetRight() ); + nMaxLineWidth -= nStartX; + + // Wenn PaperSize == long_max, kann ich keinen neg. Erstzeileneinzug + // abziehen (Overflow) + if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) ) + nMaxLineWidth = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) - GetXValue( rLRItem.GetRight() ); + + // Wenn jetzt noch kleiner 0, kann es nur der rechte Rand sein. + if ( nMaxLineWidth <= 0 ) + nMaxLineWidth = 1; + + // Problem: Da eine Zeile _vor_ der ungueltigen Position mit der + // Formatierung begonnen wird, werden hier leider auch die Positionen + // neu bestimmt... + // Loesungsansatz: + // Die Zeile davor kann nur groesser werden, nicht kleiner + // => ... + if ( bCalcCharPositions ) + pLine->GetCharPosArray().Remove( 0, pLine->GetCharPosArray().Count() ); + + sal_uInt16 nTmpPos = nIndex; + sal_uInt16 nTmpPortion = pLine->GetStartPortion(); + long nTmpWidth = 0; + long nXWidth = nMaxLineWidth; + if ( nXWidth <= nTmpWidth ) // while muss 1x durchlaufen werden + nXWidth = nTmpWidth+1; + + SvLongsPtr pTextRanges = 0; + long nTextExtraYOffset = 0; + long nTextXOffset = 0; + long nTextLineHeight = 0; + if ( GetTextRanger() ) + { + GetTextRanger()->SetVertical( IsVertical() ); + + long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top(); + if ( !bSameLineAgain ) + { + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( IsFixedCellHeight() ) + nTextLineHeight = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + else + nTextLineHeight = aTmpFont.GetPhysTxtSize( GetRefDevice(), String() ).Height(); + // Metriken koennen groesser sein + FormatterFontMetric aTempFormatterMetrics; + RecalcFormatterFontMetrics( aTempFormatterMetrics, aTmpFont ); + sal_uInt16 nLineHeight = aTempFormatterMetrics.GetHeight(); + if ( nLineHeight > nTextLineHeight ) + nTextLineHeight = nLineHeight; + } + else + nTextLineHeight = pLine->GetHeight(); + + nXWidth = 0; + while ( !nXWidth ) + { + long nYOff = nTextY + nTextExtraYOffset; + long nYDiff = nTextLineHeight; + if ( IsVertical() ) + { + long nMaxPolygonX = GetTextRanger()->GetBoundRect().Right(); + nYOff = nMaxPolygonX-nYOff; + nYDiff = -nTextLineHeight; + } + pTextRanges = GetTextRanger()->GetTextRanges( Range( nYOff, nYOff + nYDiff ) ); + DBG_ASSERT( pTextRanges, "GetTextRanges?!" ); + long nMaxRangeWidth = 0; + // Den breitesten Bereich verwenden... + // Der breiteste Bereich koennte etwas verwirren, also + // generell den ersten. Am besten mal richtig mit Luecken. +// for ( sal_uInt16 n = 0; n < pTextRanges->Count(); ) + if ( pTextRanges->Count() ) + { + sal_uInt16 n = 0; + long nA = pTextRanges->GetObject( n++ ); + long nB = pTextRanges->GetObject( n++ ); + DBG_ASSERT( nA <= nB, "TextRange verdreht?" ); + long nW = nB - nA; + if ( nW > nMaxRangeWidth ) + { + nMaxRangeWidth = nW; + nTextXOffset = nA; + } + } + nXWidth = nMaxRangeWidth; + if ( nXWidth ) + nMaxLineWidth = nXWidth - nStartX - GetXValue( rLRItem.GetRight() ); + else + { + // Weiter unten im Polygon versuchen. + // Unterhalb des Polygons die Paperbreite verwenden. + nTextExtraYOffset += Max( (long)(nTextLineHeight / 10), (long)1 ); + if ( ( nTextY + nTextExtraYOffset ) > GetTextRanger()->GetBoundRect().Bottom() ) + { + nXWidth = !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height(); + if ( !nXWidth ) // AutoPaperSize + nXWidth = 0x7FFFFFFF; + } + } + } + } + + // Portion suchen, die nicht mehr in Zeile passt.... + TextPortion* pPortion = 0; + sal_Bool bBrokenLine = sal_False; + bLineBreak = sal_False; + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( pLine->GetStart() ); + while ( ( nTmpWidth < nXWidth ) && !bEOL && ( nTmpPortion < pParaPortion->GetTextPortions().Count() ) ) + { + nPortionStart = nTmpPos; + pPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + // Portion wegschmeissen, ggf. die davor korrigieren, wenn + // die Hyph-Portion ein Zeichen geschluckt hat... + pParaPortion->GetTextPortions().Remove( nTmpPortion ); + if ( nTmpPortion && pPortion->GetLen() ) + { + nTmpPortion--; + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" ); + nTmpWidth -= pPrev->GetSize().Width(); + nTmpPos = nTmpPos - pPrev->GetLen(); + pPrev->SetLen( pPrev->GetLen() + pPortion->GetLen() ); + pPrev->GetSize().Width() = (-1); + } + delete pPortion; + DBG_ASSERT( nTmpPortion < pParaPortion->GetTextPortions().Count(), "Keine Portion mehr da!" ); + pPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + } + DBG_ASSERT( pPortion->GetKind() != PORTIONKIND_HYPHENATOR, "CreateLines: Hyphenator-Portion!" ); + DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Leere Portion in CreateLines ?!" ); + if ( pNextFeature && ( pNextFeature->GetStart() == nTmpPos ) ) + { + sal_uInt16 nWhich = pNextFeature->GetItem()->Which(); + switch ( nWhich ) + { + case EE_FEATURE_TAB: + { + long nOldTmpWidth = nTmpWidth; + + // Tab-Pos suchen... + long nCurPos = nTmpWidth+nStartX; +// nCurPos -= rLRItem.GetTxtLeft(); // Tabs relativ zu LI + // Skalierung rausrechnen + if ( aStatus.DoStretch() && ( nStretchX != 100 ) ) + nCurPos = nCurPos*100/nStretchX; + + short nAllSpaceBeforeText = static_cast< short >(rLRItem.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth); + aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/, aEditDoc.GetDefTab() ); + aCurrentTab.nTabPos = GetXValue( (long) ( aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/ ) ); + aCurrentTab.bValid = FALSE; + + // Switch direction in R2L para... + if ( bRightToLeftPara ) + { + if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) + aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT; + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_LEFT ) + aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT; + } + + if ( ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) || + ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) || + ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) ) + { + // Bei LEFT/DEFAULT wird dieses Tab nicht mehr betrachtet. + aCurrentTab.bValid = TRUE; + aCurrentTab.nStartPosX = nTmpWidth; + aCurrentTab.nCharPos = nTmpPos; + aCurrentTab.nTabPortion = nTmpPortion; + } + + pPortion->GetKind() = PORTIONKIND_TAB; + pPortion->SetExtraValue( aCurrentTab.aTabStop.GetFill() ); + pPortion->GetSize().Width() = aCurrentTab.nTabPos - (nTmpWidth+nStartX); + + // #90520# Height needed... + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + pPortion->GetSize().Height() = aTmpFont.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL ).Height(); + + DBG_ASSERT( pPortion->GetSize().Width() >= 0, "Tab falsch berechnet!" ); + + nTmpWidth = aCurrentTab.nTabPos-nStartX; + + // Wenn dies das erste Token in der Zeile ist, + // und nTmpWidth > aPaperSize.Width, habe ich eine + // Endlos-Schleife! + if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) + { + // Aber was jetzt ? + // Tab passend machen + pPortion->GetSize().Width() = nXWidth-nOldTmpWidth; + nTmpWidth = nXWidth-1; + bEOL = sal_True; + bBrokenLine = sal_True; + } + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + bCompressedChars = FALSE; + } + break; + case EE_FEATURE_LINEBR: + { + DBG_ASSERT( pPortion, "?!" ); + pPortion->GetSize().Width() = 0; + bEOL = sal_True; + bLineBreak = sal_True; + pPortion->GetKind() = PORTIONKIND_LINEBREAK; + bCompressedChars = FALSE; + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + } + break; + case EE_FEATURE_FIELD: + { +// long nCurWidth = nTmpWidth; + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + sal_Unicode cChar = 0; // later: NBS? + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + String aFieldValue = cChar ? String(cChar) : ((EditCharAttribField*)pNextFeature)->GetFieldValue(); + if ( bCalcCharPositions || !pPortion->HasValidSize() ) + { + pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), aFieldValue, 0, aFieldValue.Len(), 0 ); + // Damit kein Scrollen bei ueberlangen Feldern + if ( pPortion->GetSize().Width() > nXWidth ) + pPortion->GetSize().Width() = nXWidth; + } + nTmpWidth += pPortion->GetSize().Width(); + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + pPortion->GetKind() = cChar ? PORTIONKIND_TEXT : PORTIONKIND_FIELD; + // Wenn dies das erste Token in der Zeile ist, + // und nTmpWidth > aPaperSize.Width, habe ich eine + // Endlos-Schleife! + if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) + { + nTmpWidth = nXWidth-1; + bEOL = sal_True; + bBrokenLine = sal_True; + } + // Compression in Fields???? + // I think this could be a little bit difficult and is not very usefull + bCompressedChars = FALSE; + } + break; + default: DBG_ERROR( "Was fuer ein Feature ?" ); + } + pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); + } + else + { + DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion - Extra Space?!" ); + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( bCalcCharPositions || !pPortion->HasValidSize() ) + { + pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), *pParaPortion->GetNode(), nTmpPos, pPortion->GetLen(), pBuf ); + + // #i9050# Do Kerning also behind portions... + if ( ( aTmpFont.GetFixKerning() > 0 ) && ( ( nTmpPos + pPortion->GetLen() ) < pNode->Len() ) ) + pPortion->GetSize().Width() += aTmpFont.GetFixKerning(); + if ( IsFixedCellHeight() ) + pPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + } + if ( bCalcCharPositions ) + { + sal_uInt16 nLen = pPortion->GetLen(); + // Es wird am Anfang generell das Array geplaettet + // => Immer einfach schnelles insert. + sal_uInt16 nPos = nTmpPos - pLine->GetStart(); + pLine->GetCharPosArray().Insert( pBuf, nLen, nPos ); + } + + // And now check for Compression: + if ( pPortion->GetLen() && GetAsianCompressionMode() ) + bCompressedChars |= ImplCalcAsianCompression( pNode, pPortion, nTmpPos, (sal_Int32*)pLine->GetCharPosArray().GetData() + (nTmpPos-pLine->GetStart()), 10000, FALSE ); + + nTmpWidth += pPortion->GetSize().Width(); + + pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) ); + + USHORT _nPortionEnd = nTmpPos + pPortion->GetLen(); + if( bScriptSpace && ( _nPortionEnd < pNode->Len() ) && ( nTmpWidth < nXWidth ) && IsScriptChange( EditPaM( pNode, _nPortionEnd ) ) ) + { + BOOL bAllow = FALSE; + USHORT nScriptTypeLeft = GetScriptType( EditPaM( pNode, _nPortionEnd ) ); + USHORT nScriptTypeRight = GetScriptType( EditPaM( pNode, _nPortionEnd+1 ) ); + if ( ( nScriptTypeLeft == i18n::ScriptType::ASIAN ) || ( nScriptTypeRight == i18n::ScriptType::ASIAN ) ) + bAllow = TRUE; + + // No spacing within L2R/R2L nesting + if ( bAllow ) + { + long nExtraSpace = pPortion->GetSize().Height()/5; + nExtraSpace = GetXValue( nExtraSpace ); + pPortion->GetSize().Width() += nExtraSpace; + nTmpWidth += nExtraSpace; + } + } + } + + if ( aCurrentTab.bValid && ( nTmpPortion != aCurrentTab.nTabPortion ) ) + { + long nWidthAfterTab = 0; + for ( USHORT n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++ ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( n ); + nWidthAfterTab += pTP->GetSize().Width(); + } + long nW = nWidthAfterTab; // Length before tab position + if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) + { +// nW = nWidthAfterTab; + } + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) + { + nW = nWidthAfterTab/2; + } + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) + { +// nW = nWidthAfterTab; + String aText = GetSelected( EditSelection( EditPaM( pParaPortion->GetNode(), nTmpPos ), + EditPaM( pParaPortion->GetNode(), nTmpPos + pPortion->GetLen() ) ) ); + USHORT nDecPos = aText.Search( aCurrentTab.aTabStop.GetDecimal() ); + if ( nDecPos != STRING_NOTFOUND ) + { + nW -= pParaPortion->GetTextPortions().GetObject( nTmpPortion )->GetSize().Width(); + nW += aTmpFont.QuickGetTextSize( GetRefDevice(), *pParaPortion->GetNode(), nTmpPos, nDecPos, NULL ).Width(); + aCurrentTab.bValid = FALSE; + } + } + else + { + DBG_ERROR( "CreateLines: Tab not handled!" ); + } + long nMaxW = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nStartX; + if ( nW >= nMaxW ) + { + nW = nMaxW; + aCurrentTab.bValid = FALSE; + } + TextPortion* pTabPortion = pParaPortion->GetTextPortions().GetObject( aCurrentTab.nTabPortion ); + pTabPortion->GetSize().Width() = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX; + nTmpWidth = aCurrentTab.nStartPosX + pTabPortion->GetSize().Width() + nWidthAfterTab; + } + + nTmpPos = nTmpPos + pPortion->GetLen(); + nPortionEnd = nTmpPos; + nTmpPortion++; + if ( aStatus.OneCharPerLine() ) + bEOL = sal_True; + } + + DBG_ASSERT( pPortion, "no portion!?" ); + + aCurrentTab.bValid = FALSE; + + // das war evtl. eine Portion zu weit: + sal_Bool bFixedEnd = sal_False; + if ( aStatus.OneCharPerLine() ) + { + // Zustand vor Portion: ( bis auf nTmpWidth ) + nPortionEnd = nTmpPos; + nTmpPos -= pPortion ? pPortion->GetLen() : 0; + nPortionStart = nTmpPos; + nTmpPortion--; + + bEOL = sal_True; + bEOC = sal_False; + + // Und jetzt genau ein Zeichen: + nTmpPos++; + nTmpPortion++; + nPortionEnd = nTmpPortion; + // Eine Nicht-Feature-Portion muss gebrochen werden + if ( pPortion->GetLen() > 1 ) + { + DBG_ASSERT( pPortion && (pPortion->GetKind() == PORTIONKIND_TEXT), "Len>1, aber keine TextPortion?" ); + nTmpWidth -= pPortion ? pPortion->GetSize().Width() : 0; + sal_uInt16 nP = SplitTextPortion( pParaPortion, nTmpPos, pLine ); + TextPortion* p = pParaPortion->GetTextPortions().GetObject( nP ); + DBG_ASSERT( p, "Portion ?!" ); + nTmpWidth += p->GetSize().Width(); + } + } + else if ( nTmpWidth >= nXWidth ) + { + nPortionEnd = nTmpPos; + nTmpPos -= pPortion ? pPortion->GetLen() : 0; + nPortionStart = nTmpPos; + nTmpPortion--; + bEOL = sal_False; + bEOC = sal_False; + if( pPortion ) switch ( pPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + { + nTmpWidth -= pPortion->GetSize().Width(); + } + break; + case PORTIONKIND_FIELD: + case PORTIONKIND_TAB: + { + nTmpWidth -= pPortion->GetSize().Width(); + bEOL = sal_True; + bFixedEnd = sal_True; + } + break; + default: + { + // Ein Feature wird nicht umgebrochen: + DBG_ASSERT( ( pPortion->GetKind() == PORTIONKIND_LINEBREAK ), "Was fuer ein Feature ?" ); + bEOL = sal_True; + bFixedEnd = sal_True; + } + } + } + else + { + bEOL = sal_True; + bEOC = sal_True; + pLine->SetEnd( nPortionEnd ); + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine TextPortions?" ); + pLine->SetEndPortion( (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1 ); + } + + if ( aStatus.OneCharPerLine() ) + { + pLine->SetEnd( nPortionEnd ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( bFixedEnd ) + { + pLine->SetEnd( nPortionStart ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( bLineBreak || bBrokenLine ) + { + pLine->SetEnd( nPortionStart+1 ); + pLine->SetEndPortion( nTmpPortion-1 ); + bEOC = sal_False; // wurde oben gesetzt, vielleich mal die if's umstellen? + } + else if ( !bEOL ) + { + DBG_ASSERT( pPortion && ((nPortionEnd-nPortionStart) == pPortion->GetLen()), "Doch eine andere Portion?!" ); + long nRemainingWidth = nMaxLineWidth - nTmpWidth; + sal_Bool bCanHyphenate = ( aTmpFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ); + if ( bCompressedChars && pPortion && ( pPortion->GetLen() > 1 ) && pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed ) + { + // I need the manipulated DXArray for determining the break postion... + ImplCalcAsianCompression( pNode, pPortion, nPortionStart, const_cast<sal_Int32*>(( pLine->GetCharPosArray().GetData() + (nPortionStart-pLine->GetStart()) )), 10000, TRUE ); + } + if( pPortion ) + ImpBreakLine( pParaPortion, pLine, pPortion, nPortionStart, + nRemainingWidth, bCanHyphenate && bHyphenatePara ); + } + + // ------------------------------------------------------------------ + // Zeile fertig => justieren + // ------------------------------------------------------------------ + + // CalcTextSize sollte besser durch ein kontinuierliches + // Registrieren ersetzt werden ! + Size aTextSize = pLine->CalcTextSize( *pParaPortion ); + + if ( aTextSize.Height() == 0 ) + { + SeekCursor( pNode, pLine->GetStart()+1, aTmpFont ); + aTmpFont.SetPhysFont( pRefDev ); + ImplInitDigitMode( pRefDev, 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( IsFixedCellHeight() ) + aTextSize.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + else + aTextSize.Height() = aTmpFont.GetPhysTxtSize( pRefDev, String() ).Height(); + pLine->SetHeight( (sal_uInt16)aTextSize.Height() ); + } + + // Die Fontmetriken koennen nicht kontinuierlich berechnet werden, + // wenn der Font sowieso eingestellt ist, weil ggf. ein grosser Font + // erst nach dem Umbrechen ploetzlich in der naechsten Zeile landet + // => Font-Metriken zu gross. + FormatterFontMetric aFormatterMetrics; + sal_uInt16 nTPos = pLine->GetStart(); + for ( sal_uInt16 nP = pLine->GetStartPortion(); nP <= pLine->GetEndPortion(); nP++ ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( nP ); + // #95819# problem with hard font height attribute, when everthing but the line break has this attribute + if ( pTP->GetKind() != PORTIONKIND_LINEBREAK ) + { + SeekCursor( pNode, nTPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont ); + } + nTPos = nTPos + pTP->GetLen(); + } + sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight(); + if ( nLineHeight > pLine->GetHeight() ) + pLine->SetHeight( nLineHeight ); + pLine->SetMaxAscent( aFormatterMetrics.nMaxAscent ); + + bSameLineAgain = sal_False; + if ( GetTextRanger() && ( pLine->GetHeight() > nTextLineHeight ) ) + { + // Nochmal mit der anderen Groesse aufsetzen! + bSameLineAgain = sal_True; + } + + + if ( !bSameLineAgain && !aStatus.IsOutliner() ) + { + if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + sal_uInt16 nMinHeight = GetYValue( rLSItem.GetLineHeight() ); + sal_uInt16 nTxtHeight = pLine->GetHeight(); + if ( nTxtHeight < nMinHeight ) + { + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = nMinHeight - nTxtHeight; + pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff) ); + pLine->SetHeight( nMinHeight, nTxtHeight ); + } + } + else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + if ( nPara || IsFixedCellHeight() || pLine->GetStartPortion() ) // Nicht die aller erste Zeile + { + // #100508# There are documents with PropLineSpace 0, why? + // (cmc: re above question :-) such documents can be seen by importing a .ppt + if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + sal_uInt16 nTxtHeight = pLine->GetHeight(); + sal_Int32 nH = nTxtHeight; + nH *= rLSItem.GetPropLineSpace(); + nH /= 100; + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = pLine->GetHeight() - nH; + if ( nDiff > pLine->GetMaxAscent() ) + nDiff = pLine->GetMaxAscent(); + pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() - nDiff) ); + pLine->SetHeight( (sal_uInt16)nH, nTxtHeight ); + } + } + } + } + + + // #80582# - Bullet should not influence line height +// if ( !nLine ) +// { +// long nBulletHeight = aBulletArea.GetHeight(); +// if ( nBulletHeight > (long)pLine->GetHeight() ) +// { +// long nDiff = nBulletHeight - (long)pLine->GetHeight(); +// // nDiff auf oben und unten verteilen. +// pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff/2) ); +// pLine->SetHeight( (sal_uInt16)nBulletHeight ); +// } +// } + + if ( ( !IsVertical() && aStatus.AutoPageWidth() ) || + ( IsVertical() && aStatus.AutoPageHeight() ) ) + { + // Wenn die Zeile in die aktuelle Papierbreite passt, muss + // diese Breite fuer die Ausrichting verwendet werden. + // Wenn sie nicht passt oder sie die Papierbreite aendert, + // wird bei Justification != LEFT sowieso noch mal formatiert. + long nMaxLineWidthFix = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) + - GetXValue( rLRItem.GetRight() ) - nStartX; + if ( aTextSize.Width() < nMaxLineWidthFix ) + nMaxLineWidth = nMaxLineWidthFix; + } + + if ( bCompressedChars ) + { + long nRemainingWidth = nMaxLineWidth - aTextSize.Width(); + if ( nRemainingWidth > 0 ) + { + ImplExpandCompressedPortions( pLine, pParaPortion, nRemainingWidth ); + aTextSize = pLine->CalcTextSize( *pParaPortion ); + } + } + + if ( pLine->IsHangingPunctuation() ) + { + // Width from HangingPunctuation was set to 0 in ImpBreakLine, + // check for rel width now, maybe create compression... + long n = nMaxLineWidth - aTextSize.Width(); + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( pLine->GetEndPortion() ); + sal_uInt16 nPosInArray = pLine->GetEnd()-1-pLine->GetStart(); + long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n; + pLine->GetCharPosArray()[ nPosInArray ] = nNewValue; + pTP->GetSize().Width() += n; + } + + pLine->SetTextWidth( aTextSize.Width() ); + switch ( eJustification ) + { + case SVX_ADJUST_CENTER: + { + long n = ( nMaxLineWidth - aTextSize.Width() ) / 2; + n += nStartX; // Einrueckung bleibt erhalten. + if ( n > 0 ) + pLine->SetStartPosX( (sal_uInt16)n ); + else + pLine->SetStartPosX( 0 ); + + } + break; + case SVX_ADJUST_RIGHT: + { + // Bei automatisch umgebrochenen Zeilen, die ein Blank + // am Ende enthalten, darf das Blank nicht ausgegeben werden! + + long n = nMaxLineWidth - aTextSize.Width(); + n += nStartX; // Einrueckung bleibt erhalten. + if ( n > 0 ) + pLine->SetStartPosX( (sal_uInt16)n ); + else + pLine->SetStartPosX( 0 ); + } + break; + case SVX_ADJUST_BLOCK: + { + long nRemainingSpace = nMaxLineWidth - aTextSize.Width(); + pLine->SetStartPosX( (sal_uInt16)nStartX ); + if ( !bEOC && ( nRemainingSpace > 0 ) ) // nicht die letzte Zeile... + ImpAdjustBlocks( pParaPortion, pLine, nRemainingSpace ); + } + break; + default: + { + pLine->SetStartPosX( (sal_uInt16)nStartX ); // FI, LI + } + break; + } + + // ----------------------------------------------------------------- + // pruefen, ob die Zeile neu ausgegeben werden muss... + // ----------------------------------------------------------------- + pLine->SetInvalid(); + + // Wenn eine Portion umgebrochen wurde sind ggf. viel zu viele Positionen + // im CharPosArray: + if ( bCalcCharPositions ) + { + sal_uInt16 nLen = pLine->GetLen(); + sal_uInt16 nCount = pLine->GetCharPosArray().Count(); + if ( nCount > nLen ) + pLine->GetCharPosArray().Remove( nLen, nCount-nLen ); + } + + if ( GetTextRanger() ) + { + if ( nTextXOffset ) + pLine->SetStartPosX( (sal_uInt16) ( pLine->GetStartPosX() + nTextXOffset ) ); + if ( nTextExtraYOffset ) + { + pLine->SetHeight( (sal_uInt16) ( pLine->GetHeight() + nTextExtraYOffset ), 0, pLine->GetHeight() ); + pLine->SetMaxAscent( (sal_uInt16) ( pLine->GetMaxAscent() + nTextExtraYOffset ) ); + } + } + + // Fuer kleiner 0 noch ueberlegen! + if ( pParaPortion->IsSimpleInvalid() /* && ( nInvalidDiff > 0 ) */ ) + { + // Aenderung durch einfache Textaenderung... + // Formatierung nicht abbrechen, da Portions evtl. wieder + // gesplittet werden muessen! + // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren! + // Aber ggf. als Valid markieren, damit weniger Ausgabe... + if ( pLine->GetEnd() < nInvalidStart ) + { + if ( *pLine == aSaveLine ) + { + pLine->SetValid(); + } + } + else + { + sal_uInt16 nStart = pLine->GetStart(); + sal_uInt16 nEnd = pLine->GetEnd(); + + if ( nStart > nInvalidEnd ) + { + if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && + ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) + { + pLine->SetValid(); + if ( bCalcCharPositions && bQuickFormat ) + { + bCalcCharPositions = sal_False; + bLineBreak = sal_False; + pParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + else if ( bCalcCharPositions && bQuickFormat && ( nEnd > nInvalidEnd) ) + { + // Wenn die ungueltige Zeile so endet, dass die naechste an + // der 'gleichen' Textstelle wie vorher beginnt, also nicht + // anders umgebrochen wird, brauche ich dort auch nicht die + // textbreiten neu bestimmen: + if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) + { + bCalcCharPositions = sal_False; + bLineBreak = sal_False; + pParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + } + + if ( !bSameLineAgain ) + { + nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende + // weil nEnd hinter das letzte Zeichen zeigt! + + sal_uInt16 nEndPortion = pLine->GetEndPortion(); + + // Naechste Zeile oder ggf. neue Zeile.... + pLine = 0; + if ( nLine < pParaPortion->GetLines().Count()-1 ) + pLine = pParaPortion->GetLines().GetObject( ++nLine ); + if ( pLine && ( nIndex >= pNode->Len() ) ) + { + nDelFromLine = nLine; + break; + } + if ( !pLine ) + { + if ( nIndex < pNode->Len() ) + { + pLine = new EditLine; + pParaPortion->GetLines().Insert( pLine, ++nLine ); + } + else if ( nIndex && bLineBreak && GetTextRanger() ) + { + // normaly CreateAndInsertEmptyLine would be called, but I want to use + // CreateLines, so I need Polygon code only here... + TextPortion* pDummyPortion = new TextPortion( 0 ); + pParaPortion->GetTextPortions().Insert( pDummyPortion, pParaPortion->GetTextPortions().Count() ); + pLine = new EditLine; + pParaPortion->GetLines().Insert( pLine, ++nLine ); + bForceOneRun = TRUE; + bProcessingEmptyLine = TRUE; + } + } + if ( pLine ) + { + aSaveLine = *pLine; + pLine->SetStart( nIndex ); + pLine->SetEnd( nIndex ); + pLine->SetStartPortion( nEndPortion+1 ); + pLine->SetEndPortion( nEndPortion+1 ); + } + } + } // while ( Index < Len ) + + if ( nDelFromLine != 0xFFFF ) + pParaPortion->GetLines().DeleteFromLine( nDelFromLine ); + + DBG_ASSERT( pParaPortion->GetLines().Count(), "Keine Zeile nach CreateLines!" ); + + if ( bLineBreak == sal_True ) + CreateAndInsertEmptyLine( pParaPortion, nStartPosY ); + + delete[] pBuf; + + sal_Bool bHeightChanged = FinishCreateLines( pParaPortion ); + + if ( bMapChanged ) + GetRefDevice()->Pop(); + + GetRefDevice()->Pop(); + + return bHeightChanged; +} + +void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 ) +{ + DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" ); + + EditLine* pTmpLine = new EditLine; + pTmpLine->SetStart( pParaPortion->GetNode()->Len() ); + pTmpLine->SetEnd( pParaPortion->GetNode()->Len() ); + pParaPortion->GetLines().Insert( pTmpLine, pParaPortion->GetLines().Count() ); + + sal_Bool bLineBreak = pParaPortion->GetNode()->Len() ? sal_True : sal_False; + sal_Int32 nSpaceBefore = 0; + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pParaPortion->GetNode(), &nSpaceBefore ); + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pParaPortion->GetNode() ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pParaPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + short nStartX = GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBefore)); + + Rectangle aBulletArea = Rectangle( Point(), Point() ); + if ( bLineBreak == sal_True ) + { + nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth ); + } + else + { + aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) ); + if ( aBulletArea.Right() > 0 ) + pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) ); + else + pParaPortion->SetBulletX( 0 ); // Falls Bullet falsch eingestellt. + if ( pParaPortion->GetBulletX() > nStartX ) + { + nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth ); + if ( pParaPortion->GetBulletX() > nStartX ) + nStartX = pParaPortion->GetBulletX(); + } + } + + SvxFont aTmpFont; + SeekCursor( pParaPortion->GetNode(), bLineBreak ? pParaPortion->GetNode()->Len() : 0, aTmpFont ); + aTmpFont.SetPhysFont( pRefDev ); + + TextPortion* pDummyPortion = new TextPortion( 0 ); + pDummyPortion->GetSize() = aTmpFont.GetPhysTxtSize( pRefDev, String() ); + if ( IsFixedCellHeight() ) + pDummyPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + pParaPortion->GetTextPortions().Insert( pDummyPortion, pParaPortion->GetTextPortions().Count() ); + FormatterFontMetric aFormatterMetrics; + RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont ); + pTmpLine->SetMaxAscent( aFormatterMetrics.nMaxAscent ); + pTmpLine->SetHeight( (sal_uInt16) pDummyPortion->GetSize().Height() ); + sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight(); + if ( nLineHeight > pTmpLine->GetHeight() ) + pTmpLine->SetHeight( nLineHeight ); + + if ( !aStatus.IsOutliner() ) + { + USHORT nPara = GetParaPortions().GetPos( pParaPortion ); + SvxAdjust eJustification = GetJustification( nPara ); + long nMaxLineWidth = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height(); + nMaxLineWidth -= GetXValue( rLRItem.GetRight() ); + long nTextXOffset = 0; + if ( nMaxLineWidth < 0 ) + nMaxLineWidth = 1; + if ( eJustification == SVX_ADJUST_CENTER ) + nStartX = sal::static_int_cast< short >(nMaxLineWidth / 2); + else if ( eJustification == SVX_ADJUST_RIGHT ) + nStartX = sal::static_int_cast< short >(nMaxLineWidth); + + nStartX = sal::static_int_cast< short >(nStartX + nTextXOffset); + } + + pTmpLine->SetStartPosX( nStartX ); + + if ( !aStatus.IsOutliner() ) + { + if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + sal_uInt16 nMinHeight = rLSItem.GetLineHeight(); + sal_uInt16 nTxtHeight = pTmpLine->GetHeight(); + if ( nTxtHeight < nMinHeight ) + { + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = nMinHeight - nTxtHeight; + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff) ); + pTmpLine->SetHeight( nMinHeight, nTxtHeight ); + } + } + else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + USHORT nPara = GetParaPortions().GetPos( pParaPortion ); + if ( nPara || IsFixedCellHeight() || pTmpLine->GetStartPortion() ) // Nicht die aller erste Zeile + { + // #100508# There are documents with PropLineSpace 0, why? + // (cmc: re above question :-) such documents can be seen by importing a .ppt + if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + sal_uInt16 nTxtHeight = pTmpLine->GetHeight(); + sal_Int32 nH = nTxtHeight; + nH *= rLSItem.GetPropLineSpace(); + nH /= 100; + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = pTmpLine->GetHeight() - nH; + if ( nDiff > pTmpLine->GetMaxAscent() ) + nDiff = pTmpLine->GetMaxAscent(); + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() - nDiff) ); + pTmpLine->SetHeight( (sal_uInt16)nH, nTxtHeight ); + } + } + } + } + + if ( !bLineBreak ) + { + long nMinHeight = aBulletArea.GetHeight(); + if ( nMinHeight > (long)pTmpLine->GetHeight() ) + { + long nDiff = nMinHeight - (long)pTmpLine->GetHeight(); + // nDiff auf oben und unten verteilen. + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff/2) ); + pTmpLine->SetHeight( (sal_uInt16)nMinHeight ); + } + } + else + { + // -2: Die neue ist bereits eingefuegt. +#ifdef DBG_UTIL + EditLine* pLastLine = pParaPortion->GetLines().GetObject( pParaPortion->GetLines().Count()-2 ); + DBG_ASSERT( pLastLine, "Weicher Umbruch, keine Zeile ?!" ); + DBG_ASSERT( pLastLine->GetEnd() == pParaPortion->GetNode()->Len(), "Doch anders?" ); +#endif +// pTmpLine->SetStart( pLastLine->GetEnd() ); +// pTmpLine->SetEnd( pLastLine->GetEnd() ); + sal_uInt16 nPos = (sal_uInt16) pParaPortion->GetTextPortions().Count() - 1 ; + pTmpLine->SetStartPortion( nPos ); + pTmpLine->SetEndPortion( nPos ); + } +} + +sal_Bool ImpEditEngine::FinishCreateLines( ParaPortion* pParaPortion ) +{ +// CalcCharPositions( pParaPortion ); + pParaPortion->SetValid(); + long nOldHeight = pParaPortion->GetHeight(); +// sal_uInt16 nPos = GetParaPortions().GetPos( pParaPortion ); +// DBG_ASSERT( nPos != USHRT_MAX, "FinishCreateLines: Portion nicht in Liste!" ); +// ParaPortion* pPrev = nPos ? GetParaPortions().GetObject( nPos-1 ) : 0; + CalcHeight( pParaPortion ); + + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "FinishCreateLines: Keine Text-Portion?" ); + sal_Bool bRet = ( pParaPortion->GetHeight() != nOldHeight ); + return bRet; +} + +void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate ) +{ + ContentNode* const pNode = pParaPortion->GetNode(); + + sal_uInt16 nBreakInLine = nPortionStart - pLine->GetStart(); + sal_uInt16 nMax = nBreakInLine + pPortion->GetLen(); + while ( ( nBreakInLine < nMax ) && ( pLine->GetCharPosArray()[nBreakInLine] < nRemainingWidth ) ) + nBreakInLine++; + + sal_uInt16 nMaxBreakPos = nBreakInLine + pLine->GetStart(); + sal_uInt16 nBreakPos = 0xFFFF; + + sal_Bool bCompressBlank = sal_False; + sal_Bool bHyphenated = sal_False; + sal_Bool bHangingPunctuation = sal_False; + sal_Unicode cAlternateReplChar = 0; + sal_Unicode cAlternateExtraChar = 0; + + if ( ( nMaxBreakPos < ( nMax + pLine->GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) ) + { + // Break behind the blank, blank will be compressed... + nBreakPos = nMaxBreakPos + 1; + bCompressBlank = sal_True; + } + else + { + sal_uInt16 nMinBreakPos = pLine->GetStart(); + USHORT nAttrs = pNode->GetCharAttribs().GetAttribs().Count(); + for ( USHORT nAttr = nAttrs; nAttr; ) + { + EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[--nAttr]; + if ( pAttr->IsFeature() && ( pAttr->GetEnd() > nMinBreakPos ) && ( pAttr->GetEnd() <= nMaxBreakPos ) ) + { + nMinBreakPos = pAttr->GetEnd(); + break; + } + } + + lang::Locale aLocale = GetLocale( EditPaM( pNode, nMaxBreakPos ) ); + + Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + OUString aText( *pNode ); + Reference< XHyphenator > xHyph; + if ( bCanHyphenate ) + xHyph = GetHyphenator(); + i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, Sequence< PropertyValue >(), 1 ); + i18n::LineBreakUserOptions aUserOptions; + + const i18n::ForbiddenCharacters* pForbidden = GetForbiddenCharsTable()->GetForbiddenCharacters( SvxLocaleToLanguage( aLocale ), TRUE ); + aUserOptions.forbiddenBeginCharacters = pForbidden->beginLine; + aUserOptions.forbiddenEndCharacters = pForbidden->endLine; + aUserOptions.applyForbiddenRules = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES )).GetValue(); + aUserOptions.allowPunctuationOutsideMargin = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION )).GetValue(); + aUserOptions.allowHyphenateEnglish = FALSE; + + i18n::LineBreakResults aLBR = _xBI->getLineBreak( *pNode, nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions ); + nBreakPos = (USHORT)aLBR.breakIndex; + + // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos + if ( nBreakPos < nMinBreakPos ) + { + nBreakPos = nMinBreakPos; + } + else if ( ( nBreakPos > nMaxBreakPos ) && !aUserOptions.allowPunctuationOutsideMargin ) + { + DBG_ERROR( "I18N: XBreakIterator::getLineBreak returns position > Max" ); + nBreakPos = nMaxBreakPos; + } + + // #101795# nBreakPos can never be outside the portion, even not with hangig punctuation + if ( nBreakPos > nMaxBreakPos ) + nBreakPos = nMaxBreakPos; + + // BUG in I18N - the japanese dot is in the next line! + // !!! Testen!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ( (nBreakPos + ( aUserOptions.allowPunctuationOutsideMargin ? 0 : 1 ) ) <= nMaxBreakPos ) + { + sal_Unicode cFirstInNextLine = ( (nBreakPos+1) < pNode->Len() ) ? pNode->GetChar( nBreakPos ) : 0; + if ( cFirstInNextLine == 12290 ) + nBreakPos++; + } + + bHangingPunctuation = ( nBreakPos > nMaxBreakPos ) ? sal_True : sal_False; + pLine->SetHangingPunctuation( bHangingPunctuation ); + + #ifndef SVX_LIGHT + // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch + // die Silbentrennung jagen... + // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt, + // nBreakPos ist der Wort-Anfang + // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort + // auf mehr als Zwei Zeilen gebrochen wird... + if ( !bHangingPunctuation && bCanHyphenate && GetHyphenator().is() ) + { + i18n::Boundary aBoundary = _xBI->getWordBoundary( *pNode, nBreakPos, GetLocale( EditPaM( pNode, nBreakPos ) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True ); +// sal_uInt16 nWordStart = nBreakPos; +// sal_uInt16 nBreakPos_OLD = nBreakPos; + sal_uInt16 nWordStart = nBreakPos; + sal_uInt16 nWordEnd = (USHORT) aBoundary.endPos; + DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" ); + + USHORT nWordLen = nWordEnd - nWordStart; + if ( ( nWordEnd >= nMaxBreakPos ) && ( nWordLen > 3 ) ) + { + // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD + // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" ); + String aWord( *pNode, nWordStart, nWordLen ); + sal_uInt16 nMinTrail = nWordEnd-nMaxBreakPos+1; //+1: Vor dem angeknacksten Buchstaben + Reference< XHyphenatedWord > xHyphWord; + if (xHyphenator.is()) + xHyphWord = xHyphenator->hyphenate( aWord, aLocale, aWord.Len() - nMinTrail, Sequence< PropertyValue >() ); + if (xHyphWord.is()) + { + sal_Bool bAlternate = xHyphWord->isAlternativeSpelling(); + sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos(); + + if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (pLine->GetStart() + 2 ) ) ) + { + if ( !bAlternate ) + { + bHyphenated = sal_True; + nBreakPos = nWordStart + _nWordLen; + } + else + { + String aAlt( xHyphWord->getHyphenatedWord() ); + + // Wir gehen von zwei Faellen aus, die nun + // vorliegen koennen: + // 1) packen wird zu pak-ken + // 2) Schiffahrt wird zu Schiff-fahrt + // In Fall 1 muss ein Zeichen ersetzt werden, + // in Fall 2 wird ein Zeichen hinzugefuegt. + // Die Identifikation wird erschwert durch Worte wie + // "Schiffahrtsbrennesseln", da der Hyphenator alle + // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln" + // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom + // Index des AlternativWord auf aWord schliessen. + + // Das ganze geraffel wird durch eine Funktion am + // Hyphenator vereinfacht werden, sobald AMA sie einbaut... + sal_uInt16 nAltStart = _nWordLen - 1; + sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len()); + sal_uInt16 nTxtEnd = nTxtStart; + sal_uInt16 nAltEnd = nAltStart; + + // Die Bereiche zwischen den nStart und nEnd ist + // die Differenz zwischen Alternativ- und OriginalString. + while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() && + aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) ) + { + ++nTxtEnd; + ++nAltEnd; + } + + // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt: + if( nAltEnd > nTxtEnd && nAltStart == nAltEnd && + aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) ) + { + ++nAltEnd; + ++nTxtStart; + ++nTxtEnd; + } + + DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" ); + + if ( nTxtEnd > nTxtStart ) + cAlternateReplChar = aAlt.GetChar( nAltStart ); + else + cAlternateExtraChar = aAlt.GetChar( nAltStart ); + + bHyphenated = sal_True; + nBreakPos = nWordStart + nTxtStart; + if ( cAlternateReplChar ) + nBreakPos++; + } + } + } + } + } + + #endif // !SVX_LIGHT + + if ( nBreakPos <= pLine->GetStart() ) + { + // keine Trenner in Zeile => abhacken ! + nBreakPos = nMaxBreakPos; + // MT: I18N nextCharacters !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ( nBreakPos <= pLine->GetStart() ) + nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife! + } + } + + // die angeknackste Portion ist die End-Portion + pLine->SetEnd( nBreakPos ); + + sal_uInt16 nEndPortion = SplitTextPortion( pParaPortion, nBreakPos, pLine ); + + if ( !bCompressBlank && !bHangingPunctuation ) + { + // #96187# When justification is not SVX_ADJUST_LEFT, it's important to compress + // the trailing space even if there is enough room for the space... + // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too... + DBG_ASSERT( nBreakPos > pLine->GetStart(), "ImpBreakLines - BreakPos not expected!" ); + if ( pNode->GetChar( nBreakPos-1 ) == ' ' ) + bCompressBlank = sal_True; + } + + if ( bCompressBlank || bHangingPunctuation ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( nEndPortion ); + DBG_ASSERT( pTP->GetKind() == PORTIONKIND_TEXT, "BlankRubber: Keine TextPortion!" ); + DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); + sal_uInt16 nPosInArray = nBreakPos - 1 - pLine->GetStart(); + pTP->GetSize().Width() = ( nPosInArray && ( pTP->GetLen() > 1 ) ) ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0; + pLine->GetCharPosArray()[ nPosInArray ] = pTP->GetSize().Width(); + } + else if ( bHyphenated ) + { + // Eine Portion fuer den Trenner einbauen... + TextPortion* pHyphPortion = new TextPortion( 0 ); + pHyphPortion->GetKind() = PORTIONKIND_HYPHENATOR; + String aHyphText( CH_HYPH ); + if ( cAlternateReplChar ) + { + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nEndPortion ); + DBG_ASSERT( pPrev && pPrev->GetLen(), "Hyphenate: Prev portion?!" ); + pPrev->SetLen( pPrev->GetLen() - 1 ); + pHyphPortion->SetLen( 1 ); + pHyphPortion->SetExtraValue( cAlternateReplChar ); + // Breite der Portion davor korrigieren: + pPrev->GetSize().Width() = + pLine->GetCharPosArray()[ nBreakPos-1 - pLine->GetStart() - 1 ]; + } + else if ( cAlternateExtraChar ) + { + pHyphPortion->SetExtraValue( cAlternateExtraChar ); + aHyphText.Insert( cAlternateExtraChar, 0 ); + } + + // Breite der Hyph-Portion ermitteln: + SvxFont aFont; + SeekCursor( pParaPortion->GetNode(), nBreakPos, aFont ); + aFont.SetPhysFont( GetRefDevice() ); + pHyphPortion->GetSize().Height() = GetRefDevice()->GetTextHeight(); + pHyphPortion->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText ); + + pParaPortion->GetTextPortions().Insert( pHyphPortion, ++nEndPortion ); + } + pLine->SetEndPortion( nEndPortion ); +} + +void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace ) +{ + DBG_ASSERT( nRemainingSpace > 0, "AdjustBlocks: Etwas zuwenig..." ); + DBG_ASSERT( pLine, "AdjustBlocks: Zeile ?!" ); + if ( ( nRemainingSpace < 0 ) || pLine->IsEmpty() ) + return ; + + const USHORT nFirstChar = pLine->GetStart(); + const USHORT nLastChar = pLine->GetEnd() -1; // Last zeigt dahinter + ContentNode* pNode = pParaPortion->GetNode(); + + DBG_ASSERT( nLastChar < pNode->Len(), "AdjustBlocks: Out of range!" ); + + // Search blanks or Kashidas... + SvUShorts aPositions; + USHORT nChar; + for ( nChar = nFirstChar; nChar <= nLastChar; nChar++ ) + { + if ( pNode->GetChar(nChar) == ' ' ) + { + // Don't use blank if language is arabic + LanguageType eLang = GetLanguage( EditPaM( pNode, nChar ) ); + if ( MsLangId::getPrimaryLanguage( eLang) != LANGUAGE_ARABIC_PRIMARY_ONLY ) + aPositions.Insert( nChar, aPositions.Count() ); + } + } + + // Kashidas ? + ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions ); + + + if ( !aPositions.Count() ) + return; + + // Wenn das letzte Zeichen ein Blank ist, will ich es nicht haben! + // Die Breite muss auf die Blocker davor verteilt werden... + // Aber nicht, wenn es das einzige ist + if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.Count() > 1 ) && ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) ) + { + aPositions.Remove( aPositions.Count()-1, 1 ); + USHORT nPortionStart, nPortion; + nPortion = pParaPortion->GetTextPortions().FindPortion( nLastChar+1, nPortionStart ); + TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ]; + long nRealWidth = pLine->GetCharPosArray()[nLastChar-nFirstChar]; + long nBlankWidth = nRealWidth; + if ( nLastChar > nPortionStart ) + nBlankWidth -= pLine->GetCharPosArray()[nLastChar-nFirstChar-1]; + // Evtl. ist das Blank schon in ImpBreakLine abgezogen worden: + if ( nRealWidth == pLastPortion->GetSize().Width() ) + { + // Beim letzten Zeichen muss die Portion hinter dem Blank aufhoeren + // => Korrektur vereinfachen: + DBG_ASSERT( ( nPortionStart + pLastPortion->GetLen() ) == ( nLastChar+1 ), "Blank doch nicht am Portion-Ende?!" ); + pLastPortion->GetSize().Width() -= nBlankWidth; + nRemainingSpace += nBlankWidth; + } + pLine->GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth; + } + + USHORT nGaps = aPositions.Count(); + const long nMore4Everyone = nRemainingSpace / nGaps; + long nSomeExtraSpace = nRemainingSpace - nMore4Everyone*nGaps; + + DBG_ASSERT( nSomeExtraSpace < (long)nGaps, "AdjustBlocks: ExtraSpace zu gross" ); + DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " ); + + // Die Positionen im Array und die Portion-Breiten korrigieren: + // Letztes Zeichen wird schon nicht mehr beachtet... + for ( USHORT n = 0; n < aPositions.Count(); n++ ) + { + nChar = aPositions[n]; + if ( nChar < nLastChar ) + { + USHORT nPortionStart, nPortion; + nPortion = pParaPortion->GetTextPortions().FindPortion( nChar, nPortionStart ); + TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ]; + + // Die Breite der Portion: + pLastPortion->GetSize().Width() += nMore4Everyone; + if ( nSomeExtraSpace ) + pLastPortion->GetSize().Width()++; + + // Correct positions in array + // Even for kashidas just change positions, VCL will then draw the kashida automaticly + USHORT nPortionEnd = nPortionStart + pLastPortion->GetLen(); + for ( USHORT _n = nChar; _n < nPortionEnd; _n++ ) + { + pLine->GetCharPosArray()[_n-nFirstChar] += nMore4Everyone; + if ( nSomeExtraSpace ) + pLine->GetCharPosArray()[_n-nFirstChar]++; + } + + if ( nSomeExtraSpace ) + nSomeExtraSpace--; + } + } + + // Now the text width contains the extra width... + pLine->SetTextWidth( pLine->GetTextWidth() + nRemainingSpace ); +} + +void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, USHORT nStart, USHORT nEnd, SvUShorts& rArray ) +{ + // the search has to be performed on a per word base + + EditSelection aWordSel( EditPaM( pNode, nStart ) ); + aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + if ( aWordSel.Min().GetIndex() < nStart ) + aWordSel.Min().GetIndex() = nStart; + + while ( ( aWordSel.Min().GetNode() == pNode ) && ( aWordSel.Min().GetIndex() < nEnd ) ) + { + USHORT nSavPos = aWordSel.Max().GetIndex(); + if ( aWordSel.Max().GetIndex() > nEnd ) + aWordSel.Max().GetIndex() = nEnd; + + String aWord = GetSelected( aWordSel ); + + // restore selection for proper iteration at the end of the function + aWordSel.Max().GetIndex() = nSavPos; + + xub_StrLen nIdx = 0; + xub_StrLen nKashidaPos = STRING_LEN; + xub_Unicode cCh; + xub_Unicode cPrevCh = 0; + + while ( nIdx < aWord.Len() ) + { + cCh = aWord.GetChar( nIdx ); + + // 1. Priority: + // after user inserted kashida + if ( 0x640 == cCh ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx; + break; + } + + // 2. Priority: + // after a Seen or Sad + if ( nIdx + 1 < aWord.Len() && + ( 0x633 == cCh || 0x635 == cCh ) ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx; + break; + } + + // 3. Priority: + // before final form of Teh Marbuta, Hah, Dal + // 4. Priority: + // before final form of Alef, Lam or Kaf + if ( nIdx && nIdx + 1 == aWord.Len() && + ( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh || + 0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + break; + } + } + + // 5. Priority: + // before media Bah + if ( nIdx && nIdx + 1 < aWord.Len() && 0x628 == cCh ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if next character is Reh, Yeh or Alef Maksura + xub_Unicode cNextCh = aWord.GetChar( nIdx + 1 ); + + if ( 0x631 == cNextCh || 0x64A == cNextCh || + 0x649 == cNextCh ) + { + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + } + } + + // 6. Priority: + // other connecting possibilities + if ( nIdx && nIdx + 1 == aWord.Len() && + 0x60C <= cCh && 0x6FE >= cCh ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + // only choose this position if we did not find + // a better one: + if ( STRING_LEN == nKashidaPos ) + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + break; + } + } + + // Do not consider Fathatan, Dammatan, Kasratan, Fatha, + // Damma, Kasra, Shadda and Sukun when checking if + // a character can be connected to previous character. + if ( cCh < 0x64B || cCh > 0x652 ) + cPrevCh = cCh; + + ++nIdx; + } // end of current word + + if ( STRING_LEN != nKashidaPos ) + rArray.Insert( nKashidaPos, rArray.Count() ); + + aWordSel = WordRight( aWordSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } +} + +sal_uInt16 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_uInt16 nPos, EditLine* pCurLine ) +{ + DBG_ASSERT( pPortion, "SplitTextPortion: Welche ?" ); + + // Die Portion bei nPos wird geplittet, wenn bei nPos nicht + // sowieso ein Wechsel ist + if ( nPos == 0 ) + return 0; + + sal_uInt16 nSplitPortion; + sal_uInt16 nTmpPos = 0; + TextPortion* pTextPortion = 0; + sal_uInt16 nPortions = pPortion->GetTextPortions().Count(); + for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) + { + TextPortion* pTP = pPortion->GetTextPortions().GetObject(nSplitPortion); + nTmpPos = nTmpPos + pTP->GetLen(); + if ( nTmpPos >= nPos ) + { + if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden + { + // Skip Portions with ExtraSpace +// while ( ( (nSplitPortion+1) < nPortions ) && (pPortion->GetTextPortions().GetObject(nSplitPortion+1)->GetKind() == PORTIONKIND_EXTRASPACE ) ) +// nSplitPortion++; + + return nSplitPortion; + } + pTextPortion = pTP; + break; + } + } + + DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" ); + DBG_ASSERT( pTextPortion->GetKind() == PORTIONKIND_TEXT, "SplitTextPortion: Keine TextPortion!" ); + + sal_uInt16 nOverlapp = nTmpPos - nPos; + pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp; + TextPortion* pNewPortion = new TextPortion( nOverlapp ); + pPortion->GetTextPortions().Insert( pNewPortion, nSplitPortion+1 ); + // Groessen setzen: + if ( pCurLine ) + { + // Kein neues GetTextSize, sondern Werte aus Array verwenden: + DBG_ASSERT( nPos > pCurLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); + pTextPortion->GetSize().Width() = pCurLine->GetCharPosArray()[ nPos-pCurLine->GetStart()-1 ]; + + if ( pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed ) + { + // We need the original size from the portion + USHORT nTxtPortionStart = pPortion->GetTextPortions().GetStartPos( nSplitPortion ); + SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() ); + SeekCursor( pPortion->GetNode(), nTxtPortionStart+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + GetRefDevice()->Push( PUSH_TEXTLANGUAGE ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), *pPortion->GetNode(), nTxtPortionStart, pTextPortion->GetLen(), NULL ); + GetRefDevice()->Pop(); + pTextPortion->GetExtraInfos()->nOrgWidth = aSz.Width(); + } + } + else + pTextPortion->GetSize().Width() = (-1); + + return nSplitPortion; +} + +void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStart /* , sal_Bool bCreateBlockPortions */ ) +{ + sal_uInt16 nStartPos = rStart; + ContentNode* pNode = pParaPortion->GetNode(); + DBG_ASSERT( pNode->Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" ); + + SortedPositions aPositions; + aPositions.Insert( (sal_uInt32) 0 ); + + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + // Start und Ende in das Array eintragen... + // Die InsertMethode laesst keine doppelten Werte zu.... + aPositions.Insert( pAttrib->GetStart() ); + aPositions.Insert( pAttrib->GetEnd() ); + nAttr++; + pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + aPositions.Insert( pNode->Len() ); + + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion ) ); + + const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT nT = 0; nT < rTypes.Count(); nT++ ) + aPositions.Insert( rTypes[nT].nStartPos ); + + const WritingDirectionInfos& rWritingDirections = pParaPortion->aWritingDirectionInfos; + for ( USHORT nD = 0; nD < rWritingDirections.Count(); nD++ ) + aPositions.Insert( rWritingDirections[nD].nStartPos ); + + if ( mpIMEInfos && mpIMEInfos->nLen && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) ) + { + sal_uInt16 nLastAttr = 0xFFFF; + for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ ) + { + if ( mpIMEInfos->pAttribs[n] != nLastAttr ) + { + aPositions.Insert( mpIMEInfos->aPos.GetIndex() + n ); + nLastAttr = mpIMEInfos->pAttribs[n]; + } + } + aPositions.Insert( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ); + } + + // Ab ... loeschen: + // Leider muss die Anzahl der TextPortions mit aPositions.Count() + // nicht uebereinstimmen, da evtl. Zeilenumbrueche... + sal_uInt16 nPortionStart = 0; + sal_uInt16 nInvPortion = 0; + sal_uInt16 nP; + for ( nP = 0; nP < pParaPortion->GetTextPortions().Count(); nP++ ) + { + TextPortion* pTmpPortion = pParaPortion->GetTextPortions().GetObject(nP); + nPortionStart = nPortionStart + pTmpPortion->GetLen(); + if ( nPortionStart >= nStartPos ) + { + nPortionStart = nPortionStart - pTmpPortion->GetLen(); + rStart = nPortionStart; + nInvPortion = nP; + break; + } + } + DBG_ASSERT( nP < pParaPortion->GetTextPortions().Count() || !pParaPortion->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" ); + if ( nInvPortion && ( nPortionStart+pParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen() > nStartPos ) ) + { + // lieber eine davor... + // Aber nur wenn es mitten in der Portion war, sonst ist es evtl. + // die einzige in der Zeile davor ! + nInvPortion--; + nPortionStart = nPortionStart - pParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen(); + } + pParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); + + // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein: + aPositions.Insert( nPortionStart ); + + sal_uInt16 nInvPos; +#ifdef DBG_UTIL + sal_Bool bFound = +#endif + aPositions.Seek_Entry( nPortionStart, &nInvPos ); + + DBG_ASSERT( bFound && ( nInvPos < (aPositions.Count()-1) ), "InvPos ?!" ); + for ( sal_uInt16 i = nInvPos+1; i < aPositions.Count(); i++ ) + { + TextPortion* pNew = new TextPortion( (sal_uInt16)aPositions[i] - (sal_uInt16)aPositions[i-1] ); + pParaPortion->GetTextPortions().Insert( pNew, pParaPortion->GetTextPortions().Count()); + } + + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine Portions?!" ); +#ifdef EDITDEBUG + DBG_ASSERT( pParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); +#endif +} + +void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars ) +{ + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine Portions!" ); + DBG_ASSERT( nNewChars, "RecalcTextPortion mit Diff == 0" ); + + ContentNode* const pNode = pParaPortion->GetNode(); + if ( nNewChars > 0 ) + { + // Wenn an nStartPos ein Attribut beginnt/endet, faengt eine neue Portion + // an, ansonsten wird die Portion an nStartPos erweitert. + + if ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) || IsScriptChange( EditPaM( pNode, nStartPos ) ) ) + { + sal_uInt16 nNewPortionPos = 0; + if ( nStartPos ) + nNewPortionPos = SplitTextPortion( pParaPortion, nStartPos ) + 1; + + // Eine leere Portion kann hier stehen, wenn der Absatz leer war, + // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist. + if ( ( nNewPortionPos < pParaPortion->GetTextPortions().Count() ) && + !pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) + { + DBG_ASSERT( pParaPortion->GetTextPortions()[nNewPortionPos]->GetKind() == PORTIONKIND_TEXT, "Leere Portion war keine TextPortion!" ); + USHORT & r = + pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen(); + r = r + nNewChars; + } + else + { + TextPortion* pNewPortion = new TextPortion( nNewChars ); + pParaPortion->GetTextPortions().Insert( pNewPortion, nNewPortionPos ); + } + } + else + { + sal_uInt16 nPortionStart; + const sal_uInt16 nTP = pParaPortion->GetTextPortions(). + FindPortion( nStartPos, nPortionStart ); + TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ]; + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + pTP->GetSize().Width() = (-1); + } + } + else + { + // Portion schrumpfen oder ggf. entfernen. + // Vor Aufruf dieser Methode muss sichergestellt sein, dass + // keine Portions in dem geloeschten Bereich lagen! + + // Es darf keine reinragende oder im Bereich startende Portion geben, + // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein + sal_uInt16 nPortion = 0; + sal_uInt16 nPos = 0; + sal_uInt16 nEnd = nStartPos-nNewChars; + sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count(); + TextPortion* pTP = 0; + for ( nPortion = 0; nPortion < nPortions; nPortion++ ) + { + pTP = pParaPortion->GetTextPortions()[ nPortion ]; + if ( ( nPos+pTP->GetLen() ) > nStartPos ) + { + DBG_ASSERT( nPos <= nStartPos, "Start falsch!" ); + DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" ); + break; + } + nPos = nPos + pTP->GetLen(); + } + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) + { + // Portion entfernen; + BYTE nType = pTP->GetKind(); + pParaPortion->GetTextPortions().Remove( nPortion ); + delete pTP; + if ( nType == PORTIONKIND_LINEBREAK ) + { + TextPortion* pNext = pParaPortion->GetTextPortions()[ nPortion ]; + if ( pNext && !pNext->GetLen() ) + { + // Dummy-Portion entfernen + pParaPortion->GetTextPortions().Remove( nPortion ); + delete pNext; + } + } + } + else + { + DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + } + + // ganz am Schluss darf keine HYPHENATOR-Portion stehen bleiben... + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" ); + sal_uInt16 nLastPortion = pParaPortion->GetTextPortions().Count() - 1; + pTP = pParaPortion->GetTextPortions().GetObject( nLastPortion ); + if ( pTP->GetKind() == PORTIONKIND_HYPHENATOR ) + { + // Portion wegschmeissen, ggf. die davor korrigieren, wenn + // die Hyph-Portion ein Zeichen geschluckt hat... + pParaPortion->GetTextPortions().Remove( nLastPortion ); + if ( nLastPortion && pTP->GetLen() ) + { + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nLastPortion - 1 ); + DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" ); + pPrev->SetLen( pPrev->GetLen() + pTP->GetLen() ); + pPrev->GetSize().Width() = (-1); + } + delete pTP; + } + } +#ifdef EDITDEBUG + DBG_ASSERT( pParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); +#endif +} + +void ImpEditEngine::SetTextRanger( TextRanger* pRanger ) +{ + if ( pTextRanger != pRanger ) + { + delete pTextRanger; + pTextRanger = pRanger; + + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() ); + pParaPortion->GetLines().Reset(); + } + + FormatFullDoc(); + UpdateViews( GetActiveView() ); + if ( GetUpdateMode() && GetActiveView() ) + pActiveView->ShowCursor( sal_False, sal_False ); + } +} + +void ImpEditEngine::SetVertical( BOOL bVertical ) +{ + if ( IsVertical() != bVertical ) + { + GetEditDoc().SetVertical( bVertical ); + sal_Bool bUseCharAttribs = ( aStatus.GetControlWord() & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False; + GetEditDoc().CreateDefFont( bUseCharAttribs ); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } + } +} + +void ImpEditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight ) +{ + if ( IsFixedCellHeight() != bUseFixedCellHeight ) + { + GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight ); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } + } +} + +void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut, sal_uInt16 nIgnoreWhich ) +{ + // Es war mal geplant, SeekCursor( nStartPos, nEndPos, ... ), damit nur + // ab der StartPosition neu gesucht wird. + // Problem: Es mussten zwei Listen beruecksichtigt/gefuehrt werden: + // OrderedByStart,OrderedByEnd. + + if ( nPos > pNode->Len() ) + nPos = pNode->Len(); + + rFont = pNode->GetCharAttribs().GetDefFont(); + + short nScriptType = GetScriptType( EditPaM( pNode, nPos ) ); + if ( ( nScriptType == i18n::ScriptType::ASIAN ) || ( nScriptType == i18n::ScriptType::COMPLEX ) ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ); + rFont.SetName( rFontItem.GetFamilyName() ); + rFont.SetFamily( rFontItem.GetFamily() ); + rFont.SetPitch( rFontItem.GetPitch() ); + rFont.SetCharSet( rFontItem.GetCharSet() ); + Size aSz( rFont.GetSize() ); + aSz.Height() = ((const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ) ).GetHeight(); + rFont.SetSize( aSz ); + rFont.SetWeight( ((const SvxWeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ))).GetWeight() ); + rFont.SetItalic( ((const SvxPostureItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ))).GetPosture() ); + rFont.SetLanguage( ((const SvxLanguageItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ))).GetLanguage() ); + } + + sal_uInt16 nRelWidth = ((const SvxCharScaleWidthItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH)).GetValue(); + + if ( pOut ) + { + const SvxUnderlineItem& rTextLineColor = (const SvxUnderlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE ); + if ( rTextLineColor.GetColor() != COL_TRANSPARENT ) + pOut->SetTextLineColor( rTextLineColor.GetColor() ); + else + pOut->SetTextLineColor(); + } + + if ( pOut ) + { + const SvxOverlineItem& rOverlineColor = (const SvxOverlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_OVERLINE ); + if ( rOverlineColor.GetColor() != COL_TRANSPARENT ) + pOut->SetOverlineColor( rOverlineColor.GetColor() ); + else + pOut->SetOverlineColor(); + } + + const SvxLanguageItem* pCJKLanguageItem = NULL; + + if ( aStatus.UseCharAttribs() ) + { + const CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( rAttribs, nAttr ); + while ( pAttrib && ( pAttrib->GetStart() <= nPos ) ) + { + // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen! + // Leere Attribute werden beruecksichtigt( verwendet), da diese + // gerade eingestellt wurden. + // 12.4.95: Doch keine Leeren Attribute verwenden: + // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font + // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam. + if ( ( pAttrib->Which() != nIgnoreWhich ) && + ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) ) + || ( !pNode->Len() ) ) ) + { + DBG_ASSERT( ( pAttrib->Which() >= EE_CHAR_START ) && ( pAttrib->Which() <= EE_FEATURE_END ), "Unglueltiges Attribut in Seek() " ); + if ( IsScriptItemValid( pAttrib->Which(), nScriptType ) ) + { + pAttrib->SetFont( rFont, pOut ); + // #i1550# hard color attrib should win over text color from field + if ( pAttrib->Which() == EE_FEATURE_FIELD ) + { + EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttrib( EE_CHAR_COLOR, nPos ); + if ( pColorAttr ) + pColorAttr->SetFont( rFont, pOut ); + } + } + if ( pAttrib->Which() == EE_CHAR_FONTWIDTH ) + nRelWidth = ((const SvxCharScaleWidthItem*)pAttrib->GetItem())->GetValue(); + if ( pAttrib->Which() == EE_CHAR_LANGUAGE_CJK ) + pCJKLanguageItem = (const SvxLanguageItem*) pAttrib->GetItem(); + } + pAttrib = GetAttrib( rAttribs, ++nAttr ); + } + } + + if ( !pCJKLanguageItem ) + pCJKLanguageItem = (const SvxLanguageItem*) &pNode->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK ); + + rFont.SetCJKContextLanguage( pCJKLanguageItem->GetLanguage() ); + + if ( rFont.GetKerning() && IsKernAsianPunctuation() && ( nScriptType == i18n::ScriptType::ASIAN ) ) + rFont.SetKerning( rFont.GetKerning() | KERNING_ASIAN ); + + if ( aStatus.DoNotUseColors() ) + { + // Hack fuer DL,weil JOE staendig die Pooldefaults verbiegt! + // const SvxColorItem& rColorItem = (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR ); + rFont.SetColor( /* rColorItem.GetValue() */ COL_BLACK ); + } + + if ( aStatus.DoStretch() || ( nRelWidth != 100 ) ) + { + // Fuer das aktuelle Ausgabegeraet, weil es sonst bei einem + // Drucker als RefDev auf dem Bildschirm #?!@' aussieht! + OutputDevice* pDev = pOut ? pOut : GetRefDevice(); + rFont.SetPhysFont( pDev ); + FontMetric aMetric( pDev->GetFontMetric() ); + // Fuer die Hoehe nicht die Metriken nehmen, da das bei + // Hoch-/Tiefgestellt schief geht. + Size aRealSz( aMetric.GetSize().Width(), rFont.GetSize().Height() ); + if ( aStatus.DoStretch() ) + { + if ( nStretchY != 100 ) + { + aRealSz.Height() *= nStretchY; + aRealSz.Height() /= 100; + } + if ( nStretchX != 100 ) + { + aRealSz.Width() *= nStretchX; + aRealSz.Width() /= 100; + + // Auch das Kerning: (long wegen Zwischenergebnis) + long nKerning = rFont.GetFixKerning(); +/* + Die Ueberlegung war: Wenn neg. Kerning, aber StretchX = 200 + => Nicht das Kerning verdoppelt, also die Buchstaben weiter + zusammenziehen + --------------------------- + Kern StretchX =>Kern + --------------------------- + >0 <100 < (Proportional) + <0 <100 < (Proportional) + >0 >100 > (Proportional) + <0 >100 < (Der Betrag, also Antiprop) +*/ + if ( ( nKerning < 0 ) && ( nStretchX > 100 ) ) + { + // Antiproportional + nKerning *= 100; + nKerning /= nStretchX; + } + else if ( nKerning ) + { + // Proportional + nKerning *= nStretchX; + nKerning /= 100; + } + rFont.SetFixKerning( (short)nKerning ); + } + } + if ( nRelWidth != 100 ) + { + aRealSz.Width() *= nRelWidth; + aRealSz.Width() /= 100; + } + rFont.SetSize( aRealSz ); + // Font wird nicht restauriert... + } + + if ( ( ( rFont.GetColor() == COL_AUTO ) || ( IsForceAutoColor() ) ) && pOut ) + { + // #i75566# Do not use AutoColor when printing OR Pdf export + const bool bPrinting(OUTDEV_PRINTER == pOut->GetOutDevType()); + const bool bPDFExporting(0 != pOut->GetPDFWriter()); + + if ( IsAutoColorEnabled() && !bPrinting && !bPDFExporting) + { + // Never use WindowTextColor on the printer + rFont.SetColor( GetAutoColor() ); + } + else + { + if ( ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() ) + rFont.SetColor( COL_WHITE ); + else + rFont.SetColor( COL_BLACK ); + } + } + + if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) && + ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) ) + { + sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; + if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) + rFont.SetUnderline( UNDERLINE_SINGLE ); + else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_BOLD ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + else if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) + rFont.SetColor( Color( COL_RED ) ); + else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT ) + rFont.SetColor( Color( COL_LIGHTGRAY ) ); + if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); + rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); + rFont.SetTransparent( FALSE ); + } + else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) + { + rFont.SetUnderline( UNDERLINE_WAVE ); + if( pOut ) + pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) ); + } + } +} + +void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont ) +{ + // Fuer Zeilenhoehe bei Hoch/Tief erstmal ohne Propr! + sal_uInt16 nPropr = rFont.GetPropr(); + DBG_ASSERT( ( nPropr == 100 ) || rFont.GetEscapement(), "Propr ohne Escape?!" ); + if ( nPropr != 100 ) + { + rFont.SetPropr( 100 ); + rFont.SetPhysFont( pRefDev ); + } + sal_uInt16 nAscent, nDescent; + + FontMetric aMetric( pRefDev->GetFontMetric() ); + nAscent = (sal_uInt16)aMetric.GetAscent(); + if ( IsAddExtLeading() ) + nAscent = sal::static_int_cast< sal_uInt16 >( + nAscent + aMetric.GetExtLeading() ); + nDescent = (sal_uInt16)aMetric.GetDescent(); + + if ( IsFixedCellHeight() ) + { +/* creating correct proportional ascent and descent values lead to problems if different fonts are used + in the same portion, it results in a bigger linespacing. + sal_Int32 f = nAscent + nDescent; + if ( f ) + { + sal_Int32 nHeight = ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ); + nAscent = (sal_Int16)(( nHeight * nAscent ) / f ); + nDescent = (sal_Int16)(nHeight - nAscent); + } +*/ + nAscent = sal::static_int_cast< sal_uInt16 >( rFont.GetHeight() ); + nDescent= sal::static_int_cast< sal_uInt16 >( ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ) - nAscent ); + } + else + { + sal_uInt16 nIntLeading = ( aMetric.GetIntLeading() > 0 ) ? (sal_uInt16)aMetric.GetIntLeading() : 0; + // Fonts ohne Leading bereiten Probleme + if ( ( nIntLeading == 0 ) && ( pRefDev->GetOutDevType() == OUTDEV_PRINTER ) ) + { + // Da schaun wir mal, was fuer eine Leading ich auf dem + // Bildschirm erhalte + VirtualDevice* pVDev = GetVirtualDevice( pRefDev->GetMapMode(), pRefDev->GetDrawMode() ); + rFont.SetPhysFont( pVDev ); + aMetric = pVDev->GetFontMetric(); + + // Damit sich die Leading nicht wieder rausrechnet, + // wenn die ganze Zeile den Font hat, nTmpLeading. + + // 4/96: Kommt bei HP Laserjet 4V auch nicht hin + // => Werte komplett vom Bildschirm holen. + // sal_uInt16 nTmpLeading = (sal_uInt16)aMetric.GetLeading(); + // nAscent += nTmpLeading; + nAscent = (sal_uInt16)aMetric.GetAscent(); + nDescent = (sal_uInt16)aMetric.GetDescent(); + // nLeading = (sal_uInt16)aMetric.GetLeading(); + } + } + if ( nAscent > rCurMetrics.nMaxAscent ) + rCurMetrics.nMaxAscent = nAscent; + if ( nDescent > rCurMetrics.nMaxDescent ) + rCurMetrics.nMaxDescent= nDescent; + // Sonderbehandlung Hoch/Tief: + if ( rFont.GetEscapement() ) + { + // Jetzt unter Beruecksichtigung von Escape/Propr + // Ascent oder Descent ggf vergroessern + short nDiff = (short)(rFont.GetSize().Height()*rFont.GetEscapement()/100L); + if ( rFont.GetEscapement() > 0 ) + { + nAscent = (sal_uInt16) (((long)nAscent)*nPropr/100 + nDiff); + if ( nAscent > rCurMetrics.nMaxAscent ) + rCurMetrics.nMaxAscent = nAscent; + } + else // muss < 0 sein + { + nDescent = (sal_uInt16) (((long)nDescent)*nPropr/100 - nDiff); + if ( nDescent > rCurMetrics.nMaxDescent ) + rCurMetrics.nMaxDescent= nDescent; + } + } +} + +void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly, short nOrientation ) +{ + if ( !GetUpdateMode() && !bStripOnly ) + return; + + if ( !IsFormatted() ) + FormatDoc(); + + long nFirstVisXPos = - pOutDev->GetMapMode().GetOrigin().X(); + long nFirstVisYPos = - pOutDev->GetMapMode().GetOrigin().Y(); + + EditLine* pLine; + Point aTmpPos; + Point aRedLineTmpPos; + DBG_ASSERT( GetParaPortions().Count(), "Keine ParaPortion?!" ); + SvxFont aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() ); + Font aOldFont( pOutDev->GetFont() ); + vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOutDev->GetExtOutDevData() ); + + // Bei gedrehtem Text wird aStartPos als TopLeft angesehen, da andere + // Informationen fehlen, und sowieso das ganze Object ungescrollt + // dargestellt wird. + // Das Rechteck ist unendlich gross. + Point aOrigin( aStartPos ); + double nCos = 0.0, nSin = 0.0; + if ( nOrientation ) + { + double nRealOrientation = nOrientation*F_PI1800; + nCos = cos( nRealOrientation ); + nSin = sin( nRealOrientation ); + } + + // #110496# Added some more optional metafile comments. This + // change: factored out some duplicated code. + GDIMetaFile* pMtf = pOutDev->GetConnectMetaFile(); + const bool bMetafileValid( pMtf != NULL ); + + // Fuer OnlineSpelling: +// EditPaM aCursorPos; +// if( GetStatus().DoOnlineSpelling() && pActiveView ) +// aCurPos = pActiveView->pImpEditView->GetEditSelections().Max(); + + // -------------------------------------------------- + // Ueber alle Absaetze... + // -------------------------------------------------- + for ( sal_uInt16 n = 0; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject( n ); + DBG_ASSERT( pPortion, "NULL-Pointer in TokenList in Paint" ); + // falls beim Tippen Idle-Formatierung, asynchrones Paint. + // Unsichtbare Portions koennen ungueltig sein. + if ( pPortion->IsVisible() && pPortion->IsInvalid() ) + return; + + if ( pPDFExtOutDevData ) + pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); + + long nParaHeight = pPortion->GetHeight(); + sal_uInt16 nIndex = 0; + if ( pPortion->IsVisible() && ( + ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRec.Top() ) ) || + ( IsVertical() && ( ( aStartPos.X() - nParaHeight ) < aClipRec.Right() ) ) ) ) + + { + // -------------------------------------------------- + // Ueber die Zeilen des Absatzes... + // -------------------------------------------------- + sal_uInt16 nLines = pPortion->GetLines().Count(); + sal_uInt16 nLastLine = nLines-1; + + if ( !IsVertical() ) + aStartPos.Y() += pPortion->GetFirstLineOffset(); + else + aStartPos.X() -= pPortion->GetFirstLineOffset(); + + Point aParaStart( aStartPos ); + + const SvxLineSpacingItem& rLSItem = ((const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL )); + sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) + { + pLine = pPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "NULL-Pointer im Zeileniterator in UpdateViews" ); + aTmpPos = aStartPos; + if ( !IsVertical() ) + { + aTmpPos.X() += pLine->GetStartPosX(); + aTmpPos.Y() += pLine->GetMaxAscent(); + aStartPos.Y() += pLine->GetHeight(); + } + else + { + aTmpPos.Y() += pLine->GetStartPosX(); + aTmpPos.X() -= pLine->GetMaxAscent(); + aStartPos.X() -= pLine->GetHeight(); + } + + if ( ( !IsVertical() && ( aStartPos.Y() > aClipRec.Top() ) ) + || ( IsVertical() && aStartPos.X() < aClipRec.Right() ) ) + { + // Why not just also call when stripping portions? This will give the correct values + // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call + // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine + // does, too. No change for not-layouting (painting). + if(0 == nLine) // && !bStripOnly) + { + // VERT??? + GetEditEnginePtr()->PaintingFirstLine( n, aParaStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev ); + } + + // -------------------------------------------------- + // Ueber die Portions der Zeile... + // -------------------------------------------------- + nIndex = pLine->GetStart(); + for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ ) + { + DBG_ASSERT( pPortion->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" ); + TextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( y ); + DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" ); + + long nPortionXOffset = GetPortionXOffset( pPortion, pLine, y ); + if ( !IsVertical() ) + { + aTmpPos.X() = aStartPos.X() + nPortionXOffset; + if ( aTmpPos.X() > aClipRec.Right() ) + break; // Keine weitere Ausgabe in Zeile noetig + } + else + { + aTmpPos.Y() = aStartPos.Y() + nPortionXOffset; + if ( aTmpPos.Y() > aClipRec.Bottom() ) + break; // Keine weitere Ausgabe in Zeile noetig + } + + // R2L replaces with obove... + // New position after processing R2L text... +// R2L if ( nR2LWidth && !pTextPortion->GetRightToLeft() ) +// R2L { +// R2L if ( !IsVertical() ) +// R2L aTmpPos.X() += nR2LWidth; +// R2L else +// R2L aTmpPos.Y() += nR2LWidth; +// R2L +// R2L nR2LWidth = 0; +// R2L } + + switch ( pTextPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + { + SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev ); + + BOOL bDrawFrame = FALSE; + + if ( ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) && !aTmpFont.IsTransparent() && + ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() && + ( IsAutoColorEnabled() && ( pOutDev->GetOutDevType() != OUTDEV_PRINTER ) ) ) + { + aTmpFont.SetTransparent( TRUE ); + pOutDev->SetFillColor(); + pOutDev->SetLineColor( GetAutoColor() ); + bDrawFrame = TRUE; + } + +#ifdef EDITDEBUG + if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + aTmpFont.SetFillColor( COL_LIGHTGRAY ); + aTmpFont.SetTransparent( sal_False ); + } + if ( pTextPortion->GetRightToLeft() ) + { + aTmpFont.SetFillColor( COL_LIGHTGRAY ); + aTmpFont.SetTransparent( sal_False ); + } + else if ( GetScriptType( EditPaM( pPortion->GetNode(), nIndex+1 ) ) == i18n::ScriptType::COMPLEX ) + { + aTmpFont.SetFillColor( COL_LIGHTCYAN ); + aTmpFont.SetTransparent( sal_False ); + } +#endif + aTmpFont.SetPhysFont( pOutDev ); + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + pOutDev->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + ImplInitLayoutMode( pOutDev, n, nIndex ); + ImplInitDigitMode( pOutDev, 0, 0, 0, aTmpFont.GetLanguage() ); + + XubString aText; + USHORT nTextStart = 0; + USHORT nTextLen = 0; + const sal_Int32* pDXArray = 0; + sal_Int32* pTmpDXArray = 0; + + if ( pTextPortion->GetKind() == PORTIONKIND_TEXT ) + { + aText = *pPortion->GetNode(); + nTextStart = nIndex; + nTextLen = pTextPortion->GetLen(); + pDXArray = pLine->GetCharPosArray().GetData()+( nIndex-pLine->GetStart() ); + + // --> FME 2005-10-18 #i55716# Paint control characters + if ( aStatus.MarkFields() ) + { + xub_StrLen nTmpIdx; + const xub_StrLen nTmpEnd = nTextStart + pTextPortion->GetLen(); + + for ( nTmpIdx = nTextStart; nTmpIdx <= nTmpEnd ; ++nTmpIdx ) + { + const sal_Unicode cChar = ( nTmpIdx != aText.Len() && ( nTmpIdx != nTextStart || 0 == nTextStart ) ) ? + aText.GetChar( nTmpIdx ) : + 0; + + if ( 0x200B == cChar || 0x2060 == cChar ) + { + const String aBlank( ' ' ); + long nHalfBlankWidth = aTmpFont.QuickGetTextSize( pOutDev, aBlank, 0, 1, 0 ).Width() / 2; + + const long nAdvanceX = ( nTmpIdx == nTmpEnd ? + pTextPortion->GetSize().Width() : + pDXArray[ nTmpIdx - nTextStart ] ) - nHalfBlankWidth; + const long nAdvanceY = -pLine->GetMaxAscent(); + + Point aTopLeftRectPos( aTmpPos ); + if ( !IsVertical() ) + { + aTopLeftRectPos.X() += nAdvanceX; + aTopLeftRectPos.Y() += nAdvanceY; + } + else + { + aTopLeftRectPos.Y() += nAdvanceX; + aTopLeftRectPos.X() -= nAdvanceY; + } + + Point aBottomRightRectPos( aTopLeftRectPos ); + if ( !IsVertical() ) + { + aBottomRightRectPos.X() += 2 * nHalfBlankWidth; + aBottomRightRectPos.Y() += pLine->GetHeight(); + } + else + { + aBottomRightRectPos.X() -= pLine->GetHeight(); + aBottomRightRectPos.Y() += 2 * nHalfBlankWidth; + } + + pOutDev->Push( PUSH_FILLCOLOR ); + pOutDev->Push( PUSH_LINECOLOR ); + pOutDev->SetFillColor( COL_LIGHTGRAY ); + pOutDev->SetLineColor( COL_LIGHTGRAY ); + + const Rectangle aBackRect( aTopLeftRectPos, aBottomRightRectPos ); + pOutDev->DrawRect( aBackRect ); + + pOutDev->Pop(); + pOutDev->Pop(); + + if ( 0x200B == cChar ) + { + const String aSlash( '/' ); + const short nOldEscapement = aTmpFont.GetEscapement(); + const BYTE nOldPropr = aTmpFont.GetPropr(); + + aTmpFont.SetEscapement( -20 ); + aTmpFont.SetPropr( 25 ); + aTmpFont.SetPhysFont( pOutDev ); + + const Size aSlashSize = aTmpFont.QuickGetTextSize( pOutDev, aSlash, 0, 1, 0 ); + Point aSlashPos( aTmpPos ); + const long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2; + if ( !IsVertical() ) + { + aSlashPos.X() = aTopLeftRectPos.X() + nAddX; + } + else + { + aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX; + } + + aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1, 0 ); + + aTmpFont.SetEscapement( nOldEscapement ); + aTmpFont.SetPropr( nOldPropr ); + aTmpFont.SetPhysFont( pOutDev ); + } + } + } + } + // <-- + } + else if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + DBG_ASSERT( pAttr, "Feld nicht gefunden" ); + DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Feld vom falschen Typ!" ); + aText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + nTextStart = 0; + nTextLen = aText.Len(); + + pTmpDXArray = new sal_Int32[ aText.Len() ]; + pDXArray = pTmpDXArray; + Font _aOldFont( GetRefDevice()->GetFont() ); + aTmpFont.SetPhysFont( GetRefDevice() ); + aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray ); + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( _aOldFont ); + + // add a meta file comment if we record to a metafile + if( bMetafileValid ) + { + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if( pFieldData ) + pMtf->AddAction( pFieldData->createBeginComment() ); + } + } + + } + else if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + if ( pTextPortion->GetExtraValue() ) + aText = pTextPortion->GetExtraValue(); + aText += CH_HYPH; + nTextStart = 0; + nTextLen = aText.Len(); + + // #b6668980# crash when accessing 0 pointer in pDXArray + pTmpDXArray = new sal_Int32[ aText.Len() ]; + pDXArray = pTmpDXArray; + Font _aOldFont( GetRefDevice()->GetFont() ); + aTmpFont.SetPhysFont( GetRefDevice() ); + aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray ); + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( _aOldFont ); + } + + long nTxtWidth = pTextPortion->GetSize().Width(); + + Point aOutPos( aTmpPos ); + aRedLineTmpPos = aTmpPos; + // In RTL portions spell markup pos should be at the start of the + // first chara as well. That is on the right end of the portion + if (pTextPortion->IsRightToLeft()) + aRedLineTmpPos.X() += pTextPortion->GetSize().Width(); + +//L2R if ( pTextPortion->GetRightToLeft() ) +//L2R { +//L2R sal_uInt16 nNextPortion = y+1; +//L2R while ( nNextPortion <= pLine->GetEndPortion() ) +//L2R { +//L2R TextPortion* pNextTextPortion = pPortion->GetTextPortions().GetObject( nNextPortion ); +//L2R if ( pNextTextPortion->GetRightToLeft() ) +//L2R { +//L2R if ( !IsVertical() ) +//L2R aOutPos.X() += pNextTextPortion->GetSize().Width(); +//L2R else +//L2R aOutPos.Y() += pNextTextPortion->GetSize().Width(); +//L2R } +//L2R else +//L2R break; +//L2R nNextPortion++; +//L2R } +//L2R } + if ( bStripOnly ) + { + EEngineData::WrongSpellVector aWrongSpellVector; + + if(GetStatus().DoOnlineSpelling() && pTextPortion->GetLen()) + { + WrongList* pWrongs = pPortion->GetNode()->GetWrongList(); + + if(pWrongs && pWrongs->HasWrongs()) + { + sal_uInt16 nStart(nIndex); + sal_uInt16 nEnd(0); + sal_Bool bWrong(pWrongs->NextWrong(nStart, nEnd)); + const sal_uInt16 nMaxEnd(nIndex + pTextPortion->GetLen()); + + while(bWrong) + { + if(nStart >= nMaxEnd) + { + break; + } + + if(nStart < nIndex) + { + nStart = nIndex; + } + + if(nEnd > nMaxEnd) + { + nEnd = nMaxEnd; + } + + // add to vector + aWrongSpellVector.push_back(EEngineData::WrongSpellClass(nStart, nEnd)); + + // goto next index + nStart = nEnd + 1; + + if(nEnd < nMaxEnd) + { + bWrong = pWrongs->NextWrong(nStart, nEnd); + } + else + { + bWrong = sal_False; + } + } + } + } + + const SvxFieldData* pFieldData = 0; + + if(PORTIONKIND_FIELD == pTextPortion->GetKind()) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex); + SvxFieldItem* pFieldItem = PTR_CAST(SvxFieldItem, pAttr->GetItem()); + + if(pFieldItem) + { + pFieldData = pFieldItem->GetField(); + } + } + + // support for EOC, EOW, EOS TEXT comments. To support that, + // the locale is needed. With the locale and a XBreakIterator it is + // possible to re-create the text marking info on primitive level + const lang::Locale aLocale(GetLocale(EditPaM(pPortion->GetNode(), nIndex + 1))); + + // create EOL and EOP bools + const bool bEndOfLine(y == pLine->GetEndPortion()); + const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); + + // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in + // consequence, but also already set at pOutDev) + const Color aOverlineColor(pOutDev->GetOverlineColor()); + + // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in + // consequence, but also already set at pOutDev) + const Color aTextLineColor(pOutDev->GetTextLineColor()); + + // Unicode code points conversion according to ctl text numeral setting + ImplInitDigitMode( 0, &aText, nTextStart, nTextLen, aTmpFont.GetLanguage() ); + + // StripPortions() data callback + GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray, + aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(), + aWrongSpellVector.size() ? &aWrongSpellVector : 0, + pFieldData, + bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments + &aLocale, + aOverlineColor, + aTextLineColor); + } + else + { + short nEsc = aTmpFont.GetEscapement(); + if ( nOrientation ) + { + // Bei Hoch/Tief selbst Hand anlegen: + if ( aTmpFont.GetEscapement() ) + { + long nDiff = aTmpFont.GetSize().Height() * aTmpFont.GetEscapement() / 100L; + if ( !IsVertical() ) + aOutPos.Y() -= nDiff; + else + aOutPos.X() += nDiff; + aRedLineTmpPos = aOutPos; + aTmpFont.SetEscapement( 0 ); + } + + aOutPos = lcl_ImplCalcRotatedPos( aOutPos, aOrigin, nSin, nCos ); + aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation ); + aTmpFont.SetPhysFont( pOutDev ); + + } + // nur ausgeben, was im sichtbaren Bereich beginnt: + // Wichtig, weil Bug bei einigen Grafikkarten bei transparentem Font, Ausgabe bei neg. + if ( nOrientation || ( !IsVertical() && ( ( aTmpPos.X() + nTxtWidth ) >= nFirstVisXPos ) ) + || ( IsVertical() && ( ( aTmpPos.Y() + nTxtWidth ) >= nFirstVisYPos ) ) ) + { + if ( nEsc && ( ( aTmpFont.GetUnderline() != UNDERLINE_NONE ) ) ) + { + // Das Hoch/Tief ohne Underline malen, das Underline + // auf der BaseLine der Original-Fonthoehe ausgeben... + + // Aber nur, wenn davor auch Unterstrichen! + sal_Bool bSpecialUnderline = sal_False; + EditCharAttrib* pPrev = pPortion->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex ); + if ( pPrev ) + { + SvxFont aDummy; + // Unterstreichung davor? + if ( pPrev->GetStart() ) + { + SeekCursor( pPortion->GetNode(), pPrev->GetStart(), aDummy ); + if ( aDummy.GetUnderline() != UNDERLINE_NONE ) + bSpecialUnderline = sal_True; + } + if ( !bSpecialUnderline && ( pPrev->GetEnd() < pPortion->GetNode()->Len() ) ) + { + SeekCursor( pPortion->GetNode(), pPrev->GetEnd()+1, aDummy ); + if ( aDummy.GetUnderline() != UNDERLINE_NONE ) + bSpecialUnderline = sal_True; + } + } + if ( bSpecialUnderline ) + { + Size aSz = aTmpFont.GetPhysTxtSize( pOutDev, aText, nTextStart, nTextLen ); + BYTE nProp = aTmpFont.GetPropr(); + aTmpFont.SetEscapement( 0 ); + aTmpFont.SetPropr( 100 ); + aTmpFont.SetPhysFont( pOutDev ); + String aBlanks; + aBlanks.Fill( nTextLen, ' ' ); + Point aUnderlinePos( aOutPos ); + if ( nOrientation ) + aUnderlinePos = lcl_ImplCalcRotatedPos( aTmpPos, aOrigin, nSin, nCos ); + pOutDev->DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks, 0, nTextLen ); + + aTmpFont.SetUnderline( UNDERLINE_NONE ); + if ( !nOrientation ) + aTmpFont.SetEscapement( nEsc ); + aTmpFont.SetPropr( nProp ); + aTmpFont.SetPhysFont( pOutDev ); + } + } + Point aRealOutPos( aOutPos ); + if ( ( pTextPortion->GetKind() == PORTIONKIND_TEXT ) + && pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed + && pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation ) + { + aRealOutPos.X() += pTextPortion->GetExtraInfos()->nPortionOffsetX; + } + + // --> FME 2005-06-17 #i37132# RTL portions with + // compressed blank should not paint this blank: + if ( pTextPortion->IsRightToLeft() && nTextLen >= 2 && + pDXArray[ nTextLen - 1 ] == + pDXArray[ nTextLen - 2 ] && + ' ' == aText.GetChar( nTextStart + nTextLen - 1 ) ) + --nTextLen; + // <-- + + // output directly + aTmpFont.QuickDrawText( pOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray ); + + if ( bDrawFrame ) + { + Point aTopLeft( aTmpPos ); + aTopLeft.Y() -= pLine->GetMaxAscent(); + if ( nOrientation ) + aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos ); + Rectangle aRect( aTopLeft, pTextPortion->GetSize() ); + pOutDev->DrawRect( aRect ); + } + + + // PDF export: + if ( pPDFExtOutDevData ) + { + if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if ( pFieldData->ISA( SvxURLField ) ) + { + Point aTopLeft( aTmpPos ); + aTopLeft.Y() -= pLine->GetMaxAscent(); +// if ( nOrientation ) +// aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos ); + + Rectangle aRect( aTopLeft, pTextPortion->GetSize() ); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = pPDFExtOutDevData->CreateLink( aRect ); + aBookmark.aBookmark = ((SvxURLField*)pFieldData)->GetURL(); + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back( aBookmark ); + } + } + } + } + + // comment + + + + + } + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() && pPortion->GetNode()->GetWrongList()->HasWrongs() && pTextPortion->GetLen() ) + { + {//#105750# adjust LinePos for superscript or subscript text + short _nEsc = aTmpFont.GetEscapement(); + if( _nEsc ) + { + long nShift = ((_nEsc*long(aTmpFont.GetSize().Height()))/ 100L); + if( !IsVertical() ) + aRedLineTmpPos.Y() -= nShift; + else + aRedLineTmpPos.X() += nShift; + } + } + Color aOldColor( pOutDev->GetLineColor() ); + pOutDev->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL ).nColor ) ); + lcl_DrawRedLines( pOutDev, aTmpFont.GetSize().Height(), aRedLineTmpPos, nIndex, nIndex + pTextPortion->GetLen(), pDXArray, pPortion->GetNode()->GetWrongList(), nOrientation, aOrigin, IsVertical(), pTextPortion->IsRightToLeft() ); + pOutDev->SetLineColor( aOldColor ); + } +#endif // !SVX_LIGHT + } + + pOutDev->Pop(); + + if ( pTmpDXArray ) + delete[] pTmpDXArray; + +// R2L if ( !pTextPortion->GetRightToLeft() ) +// R2L { +// R2L if ( !IsVertical() ) +// R2L aTmpPos.X() += nTxtWidth; +// R2L else +// R2L aTmpPos.Y() += nTxtWidth; +// R2L } +// R2L else +// R2L { +// R2L nR2LWidth += nTxtWidth; +// R2L } + + if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + DBG_ASSERT( pAttr, "Feld nicht gefunden" ); + DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Feld vom falschen Typ!" ); + + // add a meta file comment if we record to a metafile + if( bMetafileValid ) + { + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if( pFieldData ) + pMtf->AddAction( pFieldData->createEndComment() ); + } + } + + } + + } + break; +// case PORTIONKIND_EXTRASPACE: + case PORTIONKIND_TAB: + { + if ( pTextPortion->GetExtraValue() && ( pTextPortion->GetExtraValue() != ' ' ) ) + { + SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev ); + aTmpFont.SetTransparent( sal_False ); + aTmpFont.SetEscapement( 0 ); + aTmpFont.SetPhysFont( pOutDev ); + long nCharWidth = aTmpFont.QuickGetTextSize( pOutDev, pTextPortion->GetExtraValue(), 0, 1, NULL ).Width(); + long nChars = 2; + if( nCharWidth ) + nChars = pTextPortion->GetSize().Width() / nCharWidth; + if ( nChars < 2 ) + nChars = 2; // wird durch DrawStretchText gestaucht. + else if ( nChars == 2 ) + nChars = 3; // sieht besser aus + + String aText; + aText.Fill( (USHORT)nChars, pTextPortion->GetExtraValue() ); + pOutDev->DrawStretchText( aTmpPos, pTextPortion->GetSize().Width(), aText ); + } + } + break; + } + nIndex = nIndex + pTextPortion->GetLen(); + } + } + + if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() ) + { + if ( !IsVertical() ) + aStartPos.Y() += nSBL; + else + aStartPos.X() -= nSBL; + } + + // keine sichtbaren Aktionen mehr? + if ( !IsVertical() && ( aStartPos.Y() >= aClipRec.Bottom() ) ) + break; + else if ( IsVertical() && ( aStartPos.X() <= aClipRec.Left() ) ) + break; + } + + if ( !aStatus.IsOutliner() ) + { + const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + long nUL = GetYValue( rULItem.GetLower() ); + if ( !IsVertical() ) + aStartPos.Y() += nUL; + else + aStartPos.X() -= nUL; + } + } + else + { + if ( !IsVertical() ) + aStartPos.Y() += nParaHeight; + else + aStartPos.X() -= nParaHeight; + } + + if ( pPDFExtOutDevData ) + pPDFExtOutDevData->EndStructureElement(); + + // keine sichtbaren Aktionen mehr? + if ( !IsVertical() && ( aStartPos.Y() > aClipRec.Bottom() ) ) + break; + if ( IsVertical() && ( aStartPos.X() < aClipRec.Left() ) ) + break; + } + if ( aStatus.DoRestoreFont() ) + pOutDev->SetFont( aOldFont ); +} + +void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRec, sal_Bool bUseVirtDev ) +{ + DBG_ASSERT( pView, "Keine View - Kein Paint!" ); + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + if ( !GetUpdateMode() || IsInUndo() ) + return; + + // Schnittmenge aus Paintbereich und OutputArea. + Rectangle aClipRec( pView->GetOutputArea() ); + aClipRec.Intersection( rRec ); + + Window* pOutWin = pView->GetWindow(); + + if ( bUseVirtDev ) + { + Rectangle aClipRecPixel( pOutWin->LogicToPixel( aClipRec ) ); + if ( !IsVertical() ) + { + // etwas mehr, falls abgerundet! + aClipRecPixel.Right() += 1; + aClipRecPixel.Bottom() += 1; + } + else + { + aClipRecPixel.Left() -= 1; + aClipRecPixel.Bottom() += 1; + } + + // Wenn aClipRecPixel > XXXX, dann invalidieren ?! + + VirtualDevice* pVDev = GetVirtualDevice( pOutWin->GetMapMode(), pOutWin->GetDrawMode() ); + pVDev->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() ); + + { + Color aBackgroundColor( pView->GetBackgroundColor() ); + // #i47161# Check if text is visible on background + SvxFont aTmpFont; + ContentNode* pNode = GetEditDoc().SaveGetObject( 0 ); + SeekCursor( pNode, 1, aTmpFont ); + Color aFontColor( aTmpFont.GetColor() ); + if( aFontColor == COL_AUTO ) + aFontColor = GetAutoColor(); + + // #i69346# check for reverse color of input method attribute + if( mpIMEInfos && (mpIMEInfos->aPos.GetNode() == pNode && + mpIMEInfos->pAttribs)) + { + sal_uInt16 nAttr = mpIMEInfos->pAttribs[ 0 ]; + if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + aFontColor = rStyleSettings.GetHighlightColor() ; + } + } + + UINT8 nColorDiff = aFontColor.GetColorError( aBackgroundColor ); + if( nColorDiff < 8 ) + aBackgroundColor = aFontColor.IsDark() ? COL_WHITE : COL_BLACK; + pVDev->SetBackground( aBackgroundColor ); + } + + sal_Bool bVDevValid = sal_True; + Size aOutSz( pVDev->GetOutputSizePixel() ); + if ( ( aOutSz.Width() < aClipRecPixel.GetWidth() ) || + ( aOutSz.Height() < aClipRecPixel.GetHeight() ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() ); + } + else + { + // Das VirtDev kann bei einem Resize sehr gross werden => + // irgendwann mal kleiner machen! + if ( ( aOutSz.Height() > ( aClipRecPixel.GetHeight() + RESDIFF ) ) || + ( aOutSz.Width() > ( aClipRecPixel.GetWidth() + RESDIFF ) ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() ); + } + else + { + pVDev->Erase(); + } + } + DBG_ASSERT( bVDevValid, "VDef konnte nicht vergroessert werden!" ); + if ( !bVDevValid ) + { + Paint( pView, rRec, sal_False /* ohne VDev */ ); + return; + } + + // PaintRect fuer VDev nicht mit alignter Groesse, + // da sonst die Zeile darunter auch ausgegeben werden muss: + Rectangle aTmpRec( Point( 0, 0 ), aClipRec.GetSize() ); + + aClipRec = pOutWin->PixelToLogic( aClipRecPixel ); + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos = aClipRec.TopLeft(); + aStartPos = pView->GetDocPos( aStartPos ); + aStartPos.X() *= (-1); + aStartPos.Y() *= (-1); + } + else + { + aStartPos = aClipRec.TopRight(); + Point aDocPos( pView->GetDocPos( aStartPos ) ); + aStartPos.X() = aClipRec.GetSize().Width() + aDocPos.Y(); + aStartPos.Y() = -aDocPos.X(); + } + + Paint( pVDev, aTmpRec, aStartPos ); + + sal_Bool bClipRegion = sal_False; + Region aOldRegion; + MapMode aOldMapMode; + if ( GetTextRanger() ) + { + // Some problems here with push/pop, why?! +// pOutWin->Push( PUSH_CLIPREGION|PUSH_MAPMODE ); + bClipRegion = pOutWin->IsClipRegion(); + aOldRegion = pOutWin->GetClipRegion(); + // Wie bekomme ich das Polygon an die richtige Stelle???? + // Das Polygon bezieht sich auf die View, nicht auf das Window + // => Origin umsetzen... + aOldMapMode = pOutWin->GetMapMode(); + Point aOrigin = aOldMapMode.GetOrigin(); + Point aViewPos = pView->GetOutputArea().TopLeft(); + aOrigin.Move( aViewPos.X(), aViewPos.Y() ); + aClipRec.Move( -aViewPos.X(), -aViewPos.Y() ); + MapMode aNewMapMode( aOldMapMode ); + aNewMapMode.SetOrigin( aOrigin ); + pOutWin->SetMapMode( aNewMapMode ); + pOutWin->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) ); + } + + pOutWin->DrawOutDev( aClipRec.TopLeft(), aClipRec.GetSize(), + Point(0,0), aClipRec.GetSize(), *pVDev ); + + if ( GetTextRanger() ) + { +// pOutWin->Pop(); + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + pOutWin->SetMapMode( aOldMapMode ); + } + + + pView->DrawSelection(); + } + else + { + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos = pView->GetOutputArea().TopLeft(); + aStartPos.X() -= pView->GetVisDocLeft(); + aStartPos.Y() -= pView->GetVisDocTop(); + } + else + { + aStartPos = pView->GetOutputArea().TopRight(); + aStartPos.X() += pView->GetVisDocTop(); + aStartPos.Y() -= pView->GetVisDocLeft(); + } + + // Wenn Doc-Breite < OutputArea,Width, nicht umgebrochene Felder, + // stehen die Felder sonst �ber, wenn > Zeile. + // ( Oben nicht, da dort bereits Doc-Breite von Formatierung mit drin ) + if ( !IsVertical() && ( pView->GetOutputArea().GetWidth() > GetPaperSize().Width() ) ) + { + long nMaxX = pView->GetOutputArea().Left() + GetPaperSize().Width(); + if ( aClipRec.Left() > nMaxX ) + return; + if ( aClipRec.Right() > nMaxX ) + aClipRec.Right() = nMaxX; + } + + sal_Bool bClipRegion = pOutWin->IsClipRegion(); + Region aOldRegion = pOutWin->GetClipRegion(); + pOutWin->IntersectClipRegion( aClipRec ); + + Paint( pOutWin, aClipRec, aStartPos ); + + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + + pView->DrawSelection(); + } + +} + +void ImpEditEngine::InsertContent( ContentNode* pNode, sal_uInt16 nPos ) +{ + DBG_ASSERT( pNode, "NULL-Poointer in InsertContent! " ); + DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" ); + ParaPortion* pNew = new ParaPortion( pNode ); + GetParaPortions().Insert( pNew, nPos ); + aEditDoc.Insert( pNode, nPos ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPos ); +} + +EditPaM ImpEditEngine::SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" ); + DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" ); + DBG_ASSERT( nSepPos <= pNode->Len(), "Index im Wald: SplitContent" ); + EditPaM aPaM( pNode, nSepPos ); + return ImpInsertParaBreak( aPaM ); +} + +EditPaM ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward ) +{ + ContentNode* pLeftNode = aEditDoc.SaveGetObject( nLeftNode ); + ContentNode* pRightNode = aEditDoc.SaveGetObject( nLeftNode+1 ); + DBG_ASSERT( pLeftNode, "Ungueltiger linker Node in ConnectContents" ); + DBG_ASSERT( pRightNode, "Ungueltiger rechter Node in ConnectContents" ); + DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" ); + return ImpConnectParagraphs( pLeftNode, pRightNode, bBackward ); +} + +void ImpEditEngine::SetUpdateMode( sal_Bool bUp, EditView* pCurView, sal_Bool bForceUpdate ) +{ + sal_Bool bChanged = ( GetUpdateMode() != bUp ); + + // Beim Umschalten von sal_True auf sal_False waren alle Selektionen sichtbar, + // => Wegmalen + // Umgekehrt waren alle unsichtbar => malen + +// DrawAllSelections(); sieht im Outliner schlecht aus ! +// EditView* pView = aEditViewList.First(); +// while ( pView ) +// { +// DBG_CHKOBJ( pView, EditView, 0 ); +// pView->pImpEditView->DrawSelection(); +// pView = aEditViewList.Next(); +// } + + // Wenn !bFormatted, also z.B. nach SetText, braucht bei UpdateMode sal_True + // nicht sofort formatiert werden, weil warscheinlich noch Text kommt. + // Spaetestens bei einem Paint / CalcTextWidth wird formatiert. + + bUpdate = bUp; + if ( bUpdate && ( bChanged || bForceUpdate ) ) + FormatAndUpdate( pCurView ); +} + +void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ) +{ + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "ShowParagraph: Absatz existiert nicht!" ); + if ( pPPortion && ( pPPortion->IsVisible() != bShow ) ) + { + pPPortion->SetVisible( bShow ); + + if ( !bShow ) + { + // Als deleted kenzeichnen, damit keine Selektion auf diesem + // Absatz beginnt oder endet... + DeletedNodeInfo* pDelInfo = new DeletedNodeInfo( (sal_uIntPtr)pPPortion->GetNode(), nParagraph ); + aDeletedNodes.Insert( pDelInfo, aDeletedNodes.Count() ); + UpdateSelections(); + // Dann kriege ich den unteren Bereich nicht invalidiert, + // wenn UpdateMode = sal_False! + // Wenn doch, dann vor SetVisible auf sal_False merken! +// nCurTextHeight -= pPPortion->GetHeight(); + } + + if ( bShow && ( pPPortion->IsInvalid() || !pPPortion->nHeight ) ) + { + if ( !GetTextRanger() ) + { + if ( pPPortion->IsInvalid() ) + { + Font aOldFont( GetRefDevice()->GetFont() ); + CreateLines( nParagraph, 0 ); // 0: Kein TextRanger + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( aOldFont ); + } + else + { + CalcHeight( pPPortion ); + } + nCurTextHeight += pPPortion->GetHeight(); + } + else + { + nCurTextHeight = 0x7fffffff; + } + } + + pPPortion->SetMustRepaint( sal_True ); + if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() ) + { + aInvalidRec = Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion ) ), + Point( GetPaperSize().Width(), nCurTextHeight ) ); + UpdateViews( GetActiveView() ); + } + } +} + +sal_Bool ImpEditEngine::IsParagraphVisible( sal_uInt16 nParagraph ) +{ + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "IsParagraphVisible: Absatz existiert nicht!" ); + if ( pPPortion ) + return pPPortion->IsVisible(); + return sal_False; +} + +EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_uInt16 nNewPos, EditView* pCurView ) +{ + DBG_ASSERT( GetParaPortions().Count() != 0, "Keine Absaetze gefunden: MoveParagraphs" ); + if ( GetParaPortions().Count() == 0 ) + return EditSelection(); + aOldPositions.Justify(); + + EditSelection aSel( ImpMoveParagraphs( aOldPositions, nNewPos ) ); + + if ( nNewPos >= GetParaPortions().Count() ) + nNewPos = GetParaPortions().Count() - 1; + + // Dort, wo der Absatz eingefuegt wurde, muss richtig gepainted werden: + // Dort, wo der Absatz entfernt wurde, muss richtig gepainted werden: + // ( Und dazwischen entsprechend auch...) + if ( pCurView && ( GetUpdateMode() == sal_True ) ) + { + // in diesem Fall kann ich direkt neu malen, ohne die + // Portions zu Invalidieren. + sal_uInt16 nFirstPortion = Min( (sal_uInt16)aOldPositions.Min(), nNewPos ); + sal_uInt16 nLastPortion = Max( (sal_uInt16)aOldPositions.Max(), nNewPos ); + + ParaPortion* pUpperPortion = GetParaPortions().SaveGetObject( nFirstPortion ); + ParaPortion* pLowerPortion = GetParaPortions().SaveGetObject( nLastPortion ); + + aInvalidRec = Rectangle(); // leermachen + aInvalidRec.Left() = 0; + aInvalidRec.Right() = aPaperSize.Width(); + aInvalidRec.Top() = GetParaPortions().GetYOffset( pUpperPortion ); + aInvalidRec.Bottom() = GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight(); + + UpdateViews( pCurView ); + } + else + { + // aber der oberen ungueltigen Position neu painten... + sal_uInt16 nFirstInvPara = Min( (sal_uInt16)aOldPositions.Min(), nNewPos ); + InvalidateFromParagraph( nFirstInvPara ); + } + return aSel; +} + +void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara ) +{ + // Es werden nicht die folgenden Absaetze invalidiert, + // da ResetHeight() => Groessenanderung => alles folgende wird + // sowieso neu ausgegeben. + ParaPortion* pTmpPortion; + if ( nFirstInvPara != 0 ) + { + pTmpPortion = GetParaPortions().GetObject( nFirstInvPara-1 ); + pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 ); + } + else + { + pTmpPortion = GetParaPortions().GetObject( 0 ); + pTmpPortion->MarkSelectionInvalid( 0, pTmpPortion->GetNode()->Len() ); + } + pTmpPortion->ResetHeight(); +} + +IMPL_LINK_INLINE_START( ImpEditEngine, StatusTimerHdl, Timer *, EMPTYARG ) +{ + CallStatusHdl(); + return 0; +} +IMPL_LINK_INLINE_END( ImpEditEngine, StatusTimerHdl, Timer *, EMPTYARG ) + +void ImpEditEngine::CallStatusHdl() +{ + if ( aStatusHdlLink.IsSet() && aStatus.GetStatusWord() ) + { + // Der Status muss vor Call zurueckgesetzt werden, + // da im Hdl evtl. weitere Fags gesetzt werden... + EditStatus aTmpStatus( aStatus ); + aStatus.Clear(); + aStatusHdlLink.Call( &aTmpStatus ); + aStatusTimer.Stop(); // Falls von Hand gerufen... + } +} + +ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode* pCurNode ) +{ + ParaPortion* pPortion = FindParaPortion( pCurNode ); + DBG_ASSERT( pPortion, "GetPrevVisibleNode: Keine passende Portion!" ); + pPortion = GetPrevVisPortion( pPortion ); + if ( pPortion ) + return pPortion->GetNode(); + return 0; +} + +ContentNode* ImpEditEngine::GetNextVisNode( ContentNode* pCurNode ) +{ + ParaPortion* pPortion = FindParaPortion( pCurNode ); + DBG_ASSERT( pPortion, "GetNextVisibleNode: Keine passende Portion!" ); + pPortion = GetNextVisPortion( pPortion ); + if ( pPortion ) + return pPortion->GetNode(); + return 0; +} + +ParaPortion* ImpEditEngine::GetPrevVisPortion( ParaPortion* pCurPortion ) +{ + sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion ); + DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisPortion" ); + ParaPortion* pPortion = nPara ? GetParaPortions()[--nPara] : 0; + while ( pPortion && !pPortion->IsVisible() ) + pPortion = nPara ? GetParaPortions()[--nPara] : 0; + + return pPortion; +} + +ParaPortion* ImpEditEngine::GetNextVisPortion( ParaPortion* pCurPortion ) +{ + sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion ); + DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisNode" ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( ++nPara ); + while ( pPortion && !pPortion->IsVisible() ) + pPortion = GetParaPortions().SaveGetObject( ++nPara ); + + return pPortion; +} + +EditPaM ImpEditEngine::InsertParagraph( sal_uInt16 nPara ) +{ + EditPaM aPaM; + if ( nPara != 0 ) + { + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara-1 ); + if ( !pNode ) + pNode = GetEditDoc().SaveGetObject( GetEditDoc().Count() - 1 ); + DBG_ASSERT( pNode, "Kein einziger Absatz in InsertParagraph ?" ); + aPaM = EditPaM( pNode, pNode->Len() ); + } + else + { + ContentNode* pNode = GetEditDoc().SaveGetObject( 0 ); + aPaM = EditPaM( pNode, 0 ); + } + + return ImpInsertParaBreak( aPaM ); +} + +EditSelection* ImpEditEngine::SelectParagraph( sal_uInt16 nPara ) +{ + EditSelection* pSel = 0; + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERTWARNING( pNode, "Absatz existiert nicht: SelectParagraph" ); + if ( pNode ) + pSel = new EditSelection( EditPaM( pNode, 0 ), EditPaM( pNode, pNode->Len() ) ); + + return pSel; +} + +void ImpEditEngine::FormatAndUpdate( EditView* pCurView ) +{ + if ( bDowning ) + return ; + + if ( IsInUndo() ) + IdleFormatAndUpdate( pCurView ); + else + { + FormatDoc(); + UpdateViews( pCurView ); + } +} + +void ImpEditEngine::SetFlatMode( sal_Bool bFlat ) +{ + if ( bFlat != aStatus.UseCharAttribs() ) + return; + + if ( !bFlat ) + aStatus.TurnOnFlags( EE_CNTRL_USECHARATTRIBS ); + else + aStatus.TurnOffFlags( EE_CNTRL_USECHARATTRIBS ); + + aEditDoc.CreateDefFont( !bFlat ); + + FormatFullDoc(); + UpdateViews( (EditView*) 0); + if ( pActiveView ) + pActiveView->ShowCursor(); +} + +void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY ) +{ + if ( !IsVertical() ) + { + nStretchX = nX; + nStretchY = nY; + } + else + { + nStretchX = nY; + nStretchY = nX; + } + + if ( aStatus.DoStretch() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } +} + +void ImpEditEngine::DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ) +{ + UndoActionStart( EDITUNDO_STRETCH ); + sal_uInt16 nParas = GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ContentNode* pNode = GetEditDoc()[nPara]; + SfxItemSet aTmpSet( pNode->GetContentAttribs().GetItems() ); + + if ( nX != 100 ) + { + // Fontbreite + SvxCharScaleWidthItem* pNewWidth = (SvxCharScaleWidthItem*) pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH ).Clone(); + sal_uInt32 nProp = pNewWidth->GetValue(); // sal_uInt32, kann temporaer gross werden + nProp *= nX; + nProp /= 100; + pNewWidth->SetValue( (sal_uInt16)nProp ); + aTmpSet.Put( *pNewWidth ); + delete pNewWidth; + + // Kerning: + const SvxKerningItem& rKerningItem = + (const SvxKerningItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_KERNING ); + SvxKerningItem* pNewKerning = (SvxKerningItem*)rKerningItem.Clone(); + long nKerning = pNewKerning->GetValue(); + if ( nKerning > 0 ) + { + nKerning *= nX; + nKerning /= 100; + } + else if ( nKerning < 0 ) + { + // Bei Negativen Werten: + // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt. + nKerning *= 100; + nKerning /= nX; + } + pNewKerning->SetValue( (short)nKerning ); + aTmpSet.Put( *pNewKerning); + delete pNewKerning; + } + else + aTmpSet.ClearItem( EE_CHAR_FONTWIDTH ); + + if ( nY != 100 ) + { + // Fonthoehe + for ( int nItem = 0; nItem < 3; nItem++ ) + { + USHORT nItemId = EE_CHAR_FONTHEIGHT; + if ( nItem == 1 ) + nItemId = EE_CHAR_FONTHEIGHT_CJK; + else if ( nItem == 2 ) + nItemId = EE_CHAR_FONTHEIGHT_CTL; + + const SvxFontHeightItem& rHeightItem = + (const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( nItemId ); + SvxFontHeightItem* pNewHeight = (SvxFontHeightItem*)rHeightItem.Clone(); + sal_uInt32 nHeight = pNewHeight->GetHeight(); + nHeight *= nY; + nHeight /= 100; + pNewHeight->SetHeightValue( nHeight ); + aTmpSet.Put( *pNewHeight ); + delete pNewHeight; + } + + // Absatzabstaende + const SvxULSpaceItem& rULSpaceItem = + (const SvxULSpaceItem&)pNode->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + SvxULSpaceItem* pNewUL = (SvxULSpaceItem*)rULSpaceItem.Clone(); + sal_uInt32 nUpper = pNewUL->GetUpper(); + nUpper *= nY; + nUpper /= 100; + pNewUL->SetUpper( (sal_uInt16)nUpper ); + sal_uInt32 nLower = pNewUL->GetLower(); + nLower *= nY; + nLower /= 100; + pNewUL->SetLower( (sal_uInt16)nLower ); + aTmpSet.Put( *pNewUL ); + delete pNewUL; + } + else + aTmpSet.ClearItem( EE_CHAR_FONTHEIGHT ); + + SetParaAttribs( nPara, aTmpSet ); + + // harte Attribute: + sal_uInt16 nLastEnd = 0; // damit nach entfernen und neu nicht nochmal + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttribs = rAttribs.Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( pAttr->GetStart() >= nLastEnd ) + { + sal_uInt16 nWhich = pAttr->Which(); + SfxPoolItem* pNew = 0; + if ( nWhich == EE_CHAR_FONTHEIGHT ) + { + SvxFontHeightItem* pNewHeight = (SvxFontHeightItem*)pAttr->GetItem()->Clone(); + sal_uInt32 nHeight = pNewHeight->GetHeight(); + nHeight *= nY; + nHeight /= 100; + pNewHeight->SetHeightValue( nHeight ); + pNew = pNewHeight; + } + else if ( nWhich == EE_CHAR_FONTWIDTH ) + { + SvxCharScaleWidthItem* pNewWidth = (SvxCharScaleWidthItem*)pAttr->GetItem()->Clone(); + sal_uInt32 nProp = pNewWidth->GetValue(); + nProp *= nX; + nProp /= 100; + pNewWidth->SetValue( (sal_uInt16)nProp ); + pNew = pNewWidth; + } + else if ( nWhich == EE_CHAR_KERNING ) + { + SvxKerningItem* pNewKerning = (SvxKerningItem*)pAttr->GetItem()->Clone(); + long nKerning = pNewKerning->GetValue(); + if ( nKerning > 0 ) + { + nKerning *= nX; + nKerning /= 100; + } + else if ( nKerning < 0 ) + { + // Bei Negativen Werten: + // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt. + nKerning *= 100; + nKerning /= nX; + } + pNewKerning->SetValue( (short)nKerning ); + pNew = pNewKerning; + } + if ( pNew ) + { + SfxItemSet _aTmpSet( GetEmptyItemSet() ); + _aTmpSet.Put( *pNew ); + SetAttribs( EditSelection( EditPaM( pNode, pAttr->GetStart() ), + EditPaM( pNode, pAttr->GetEnd() ) ), _aTmpSet ); + + nLastEnd = pAttr->GetEnd(); + delete pNew; + } + } + } + } + UndoActionEnd( EDITUNDO_STRETCH ); +} + +const SvxNumberFormat* ImpEditEngine::GetNumberFormat( const ContentNode *pNode ) const +{ + const SvxNumberFormat *pRes = 0; + + if (pNode) + { + // get index of paragraph + USHORT nPara = GetEditDoc().GetPos( const_cast< ContentNode * >(pNode) ); + DBG_ASSERT( nPara < USHRT_MAX, "node not found in array" ); + if (nPara < USHRT_MAX) + { + // the called function may be overloaded by an OutlinerEditEng object to provide + // access to the SvxNumberFormat of the Outliner. + // The EditEngine implementation will just return 0. + pRes = pEditEngine->GetNumberFormat( nPara ); + } + } + + return pRes; +} + +sal_Int32 ImpEditEngine::GetSpaceBeforeAndMinLabelWidth( + const ContentNode *pNode, + sal_Int32 *pnSpaceBefore, sal_Int32 *pnMinLabelWidth ) const +{ + // nSpaceBefore matches the ODF attribut text:space-before + // nMinLabelWidth matches the ODF attribut text:min-label-width + + const SvxNumberFormat *pNumFmt = GetNumberFormat( pNode ); + + // if no number format was found we have no Outliner or the numbering level + // within the Outliner is -1 which means no number format should be applied. + // Thus the default values to be returned are 0. + sal_Int32 nSpaceBefore = 0; + sal_Int32 nMinLabelWidth = 0; + + if (pNumFmt) + { + nMinLabelWidth = -pNumFmt->GetFirstLineOffset(); + nSpaceBefore = pNumFmt->GetAbsLSpace() - nMinLabelWidth; + DBG_ASSERT( nMinLabelWidth >= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" ); + } + if (pnSpaceBefore) + *pnSpaceBefore = nSpaceBefore; + if (pnMinLabelWidth) + *pnMinLabelWidth = nMinLabelWidth; + + return nSpaceBefore + nMinLabelWidth; +} + +const SvxLRSpaceItem& ImpEditEngine::GetLRSpaceItem( ContentNode* pNode ) +{ + return (const SvxLRSpaceItem&)pNode->GetContentAttribs().GetItem( aStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE ); +} + +// Either sets the digit mode at the output device or +// modifies the passed string according to the text numeral setting: +void ImpEditEngine::ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eCurLang ) +{ + // #114278# Also setting up digit language from Svt options + // (cannot reliably inherit the outdev's setting) + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + LanguageType eLang = eCurLang; + const SvtCTLOptions::TextNumerals nCTLTextNumerals = pCTLOptions->GetCTLTextNumerals(); + + if ( SvtCTLOptions::NUMERALS_HINDI == nCTLTextNumerals ) + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + else if ( SvtCTLOptions::NUMERALS_ARABIC == nCTLTextNumerals ) + eLang = LANGUAGE_ENGLISH; + else if ( SvtCTLOptions::NUMERALS_SYSTEM == nCTLTextNumerals ) + eLang = (LanguageType) Application::GetSettings().GetLanguage(); + + if(pOutDev) + { + pOutDev->SetDigitLanguage( eLang ); + } + else if (pString) + { + // see sallayout.cxx in vcl + int nOffset; + switch( eLang & LANGUAGE_MASK_PRIMARY ) + { + default: + nOffset = 0; + break; + case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0660 - '0'; // arabic-indic digits + break; + case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //??? + case LANGUAGE_SINDHI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x06F0 - '0'; // eastern arabic-indic digits + break; + } + if (nOffset) + { + const xub_StrLen nEnd = nStt + nLen; + for( xub_StrLen nIdx = nStt; nIdx < nEnd; ++nIdx ) + { + sal_Unicode nChar = pString->GetChar( nIdx ); + if( (nChar < '0') || ('9' < nChar) ) + continue; + nChar = (sal_Unicode)(nChar + nOffset); + pString->SetChar( nIdx, nChar ); + } + } + } +} + +void ImpEditEngine::ImplInitLayoutMode( OutputDevice* pOutDev, USHORT nPara, USHORT nIndex ) +{ + BOOL bCTL = FALSE; + BYTE bR2L = FALSE; + if ( nIndex == 0xFFFF ) + { + bCTL = HasScriptType( nPara, i18n::ScriptType::COMPLEX ); + bR2L = IsRightToLeft( nPara ); + } + else + { + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + short nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); + bCTL = nScriptType == i18n::ScriptType::COMPLEX; + bR2L = GetRightToLeft( nPara, nIndex + 1); // this change was discussed in issue 37190 + // it also works for issue 55927 + } + + ULONG nLayoutMode = pOutDev->GetLayoutMode(); + + // We always use the left postion for DrawText() + nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL); + + if ( !bCTL && !bR2L) + { + // No CTL/Bidi checking neccessary + nLayoutMode |= ( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); + } + else + { + // CTL/Bidi checking neccessary + // Don't use BIDI_STRONG, VCL must do some checks. + nLayoutMode &= ~( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); + + if ( bR2L ) + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT; + } + + pOutDev->SetLayoutMode( nLayoutMode ); + + // #114278# Also setting up digit language from Svt options + // (cannot reliably inherit the outdev's setting) + LanguageType eLang; + + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + if ( SvtCTLOptions::NUMERALS_HINDI == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + else if ( SvtCTLOptions::NUMERALS_ARABIC == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ENGLISH; + else + eLang = (LanguageType) Application::GetSettings().GetLanguage(); + + pOutDev->SetDigitLanguage( eLang ); +} + +Reference < i18n::XBreakIterator > ImpEditEngine::ImplGetBreakIterator() const +{ + if ( !xBI.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() ); + xBI.set( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY ); + } + return xBI; +} + +Reference < i18n::XExtendedInputSequenceChecker > ImpEditEngine::ImplGetInputSequenceChecker() const +{ + if ( !xISC.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) ); + x >>= xISC; + } + } + return xISC; +} + +Color ImpEditEngine::GetAutoColor() const +{ + Color aColor = const_cast<ImpEditEngine*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR ).nColor; + + if ( GetBackgroundColor() != COL_AUTO ) + { + if ( GetBackgroundColor().IsDark() && aColor.IsDark() ) + aColor = COL_WHITE; + else if ( GetBackgroundColor().IsBright() && aColor.IsBright() ) + aColor = COL_BLACK; + } + + return aColor; +} + + +BOOL ImpEditEngine::ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, USHORT nStartPos, sal_Int32* pDXArray, USHORT n100thPercentFromMax, BOOL bManipulateDXArray ) +{ + DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" ); + DBG_ASSERT( pTextPortion->GetLen(), "ImplCalcAsianCompression - Empty Portion?" ); + + // Percent is 1/100 Percent... + + if ( n100thPercentFromMax == 10000 ) + pTextPortion->SetExtraInfos( NULL ); + + BOOL bCompressed = FALSE; + + if ( GetScriptType( EditPaM( pNode, nStartPos+1 ) ) == i18n::ScriptType::ASIAN ) + { + long nNewPortionWidth = pTextPortion->GetSize().Width(); + USHORT nPortionLen = pTextPortion->GetLen(); + for ( USHORT n = 0; n < nPortionLen; n++ ) + { + BYTE nType = GetCharTypeForCompression( pNode->GetChar( n+nStartPos ) ); + + BOOL bCompressPunctuation = ( nType == CHAR_PUNCTUATIONLEFT ) || ( nType == CHAR_PUNCTUATIONRIGHT ); + BOOL bCompressKana = ( nType == CHAR_KANA ) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA ); + + // create Extra infos only if needed... + if ( bCompressPunctuation || bCompressKana ) + { + if ( !pTextPortion->GetExtraInfos() ) + { + ExtraPortionInfo* pExtraInfos = new ExtraPortionInfo; + pTextPortion->SetExtraInfos( pExtraInfos ); + pExtraInfos->nOrgWidth = pTextPortion->GetSize().Width(); + pExtraInfos->nAsianCompressionTypes = CHAR_NORMAL; + } + pTextPortion->GetExtraInfos()->nMaxCompression100thPercent = n100thPercentFromMax; + pTextPortion->GetExtraInfos()->nAsianCompressionTypes |= nType; +// pTextPortion->GetExtraInfos()->nCompressedChars++; + + long nOldCharWidth; + if ( (n+1) < nPortionLen ) + { + nOldCharWidth = pDXArray[n]; + } + else + { + if ( bManipulateDXArray ) + nOldCharWidth = nNewPortionWidth - pTextPortion->GetExtraInfos()->nPortionOffsetX; + else + nOldCharWidth = pTextPortion->GetExtraInfos()->nOrgWidth; + } + nOldCharWidth -= ( n ? pDXArray[n-1] : 0 ); + + long nCompress = 0; + + if ( bCompressPunctuation ) + { + // pTextPortion->GetExtraInfos()->nComressionWeight += 5; + nCompress = nOldCharWidth / 2; + } + else // Kana + { + // pTextPortion->GetExtraInfos()->nComressionWeight += 1; + nCompress = nOldCharWidth / 10; + } + + if ( n100thPercentFromMax != 10000 ) + { + nCompress *= n100thPercentFromMax; + nCompress /= 10000; + } + + if ( nCompress ) + { + bCompressed = TRUE; + nNewPortionWidth -= nCompress; + pTextPortion->GetExtraInfos()->bCompressed = TRUE; + + + // Special handling for rightpunctuation: For the 'compression' we must + // start th eoutput before the normal char position.... + if ( bManipulateDXArray && ( pTextPortion->GetLen() > 1 ) ) + { + if ( !pTextPortion->GetExtraInfos()->pOrgDXArray ) + pTextPortion->GetExtraInfos()->SaveOrgDXArray( pDXArray, pTextPortion->GetLen()-1 ); + + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + // If it's the first char, I must handle it in Paint()... + if ( n ) + { + // -1: No entry for the last character + for ( USHORT i = n-1; i < (nPortionLen-1); i++ ) + pDXArray[i] -= nCompress; + } + else + { + pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation = TRUE; + pTextPortion->GetExtraInfos()->nPortionOffsetX = -nCompress; + } + } + else + { + // -1: No entry for the last character + for ( USHORT i = n; i < (nPortionLen-1); i++ ) + pDXArray[i] -= nCompress; + } + } + } + } + } + + if ( bCompressed && ( n100thPercentFromMax == 10000 ) ) + pTextPortion->GetExtraInfos()->nWidthFullCompression = nNewPortionWidth; + + pTextPortion->GetSize().Width() = nNewPortionWidth; + + if ( pTextPortion->GetExtraInfos() && ( n100thPercentFromMax != 10000 ) ) + { + // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected + long nShrink = pTextPortion->GetExtraInfos()->nOrgWidth - pTextPortion->GetExtraInfos()->nWidthFullCompression; + nShrink *= n100thPercentFromMax; + nShrink /= 10000; + long nNewWidth = pTextPortion->GetExtraInfos()->nOrgWidth - nShrink; + if ( nNewWidth < pTextPortion->GetSize().Width() ) + pTextPortion->GetSize().Width() = nNewWidth; + } + } + return bCompressed; +} + + +void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth ) +{ + BOOL bFoundCompressedPortion = FALSE; + long nCompressed = 0; +// long nCompressWeight = 0; + TextPortionList aCompressedPortions; + + USHORT nPortion = pLine->GetEndPortion(); + TextPortion* pTP = pParaPortion->GetTextPortions()[ nPortion ]; + while ( pTP && ( pTP->GetKind() == PORTIONKIND_TEXT ) ) + { + if ( pTP->GetExtraInfos() && pTP->GetExtraInfos()->bCompressed ) + { + bFoundCompressedPortion = TRUE; + nCompressed += pTP->GetExtraInfos()->nOrgWidth - pTP->GetSize().Width(); + aCompressedPortions.Insert( pTP, aCompressedPortions.Count() ); + } + pTP = ( nPortion > pLine->GetStartPortion() ) ? pParaPortion->GetTextPortions()[ --nPortion ] : NULL; + } + + if ( bFoundCompressedPortion ) + { + long nCompressPercent = 0; + if ( nCompressed > nRemainingWidth ) + { + nCompressPercent = nCompressed - nRemainingWidth; + DBG_ASSERT( nCompressPercent < 200000, "ImplExpandCompressedPortions - Overflow!" ); + nCompressPercent *= 10000; + nCompressPercent /= nCompressed; + } + + for ( USHORT n = 0; n < aCompressedPortions.Count(); n++ ) + { + pTP = aCompressedPortions[n]; + pTP->GetExtraInfos()->bCompressed = FALSE; + pTP->GetSize().Width() = pTP->GetExtraInfos()->nOrgWidth; + if ( nCompressPercent ) + { + USHORT nTxtPortion = pParaPortion->GetTextPortions().GetPos( pTP ); + USHORT nTxtPortionStart = pParaPortion->GetTextPortions().GetStartPos( nTxtPortion ); + DBG_ASSERT( nTxtPortionStart >= pLine->GetStart(), "Portion doesn't belong to the line!!!" ); + sal_Int32* pDXArray = const_cast< sal_Int32* >( pLine->GetCharPosArray().GetData()+( nTxtPortionStart-pLine->GetStart() ) ); + if ( pTP->GetExtraInfos()->pOrgDXArray ) + memcpy( pDXArray, pTP->GetExtraInfos()->pOrgDXArray, (pTP->GetLen()-1)*sizeof(sal_Int32) ); + ImplCalcAsianCompression( pParaPortion->GetNode(), pTP, nTxtPortionStart, pDXArray, (USHORT)nCompressPercent, TRUE ); + } + } + } + + aCompressedPortions.Remove( 0, aCompressedPortions.Count() ); +} + +// redesigned to work with TextMarkingVector +void ImpEditEngine::ImplFillTextMarkingVector(const lang::Locale& rLocale, EEngineData::TextMarkingVector& rTextMarkingVector, const String& rTxt, const USHORT nIdx, const USHORT nLen) const +{ + // determine relevant logical text elements for the just-rendered + // string of characters. + Reference< i18n::XBreakIterator > _xBI(ImplGetBreakIterator()); + + if(_xBI.is()) + { + sal_Int32 nDone; + sal_Int32 nNextCellBreak(_xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + i18n::Boundary nNextWordBoundary(_xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True)); + sal_Int32 nNextSentenceBreak(_xBI->endOfSentence(rTxt, nIdx, rLocale)); + + const sal_Int32 nEndPos(nIdx + nLen); + sal_Int32 i; + + for(i = nIdx; i < nEndPos; i++) + { + // create the entries for the respective break positions + if(i == nNextCellBreak) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfCaracter, i - nIdx)); + nNextCellBreak = _xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + if(i == nNextWordBoundary.endPos) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfWord, i - nIdx)); + nNextWordBoundary = _xBI->getWordBoundary(rTxt, i + 1, rLocale, i18n::WordType::ANY_WORD, sal_True); + } + if(i == nNextSentenceBreak) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfSentence, i - nIdx)); + nNextSentenceBreak = _xBI->endOfSentence(rTxt, i + 1, rLocale); + } + } + } +} + +// eof diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx new file mode 100644 index 000000000000..c45c6faf2b6a --- /dev/null +++ b/editeng/source/editeng/impedit4.cxx @@ -0,0 +1,2955 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <svl/srchitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> + +#include <eertfpar.hxx> +#include <editeng/editeng.hxx> +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <eehtml.hxx> +#include <editobj2.hxx> +#include <i18npool/lang.h> + +#include "editxml.hxx" + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/emphitem.hxx> +#include <textconv.hxx> +#include <rtl/tencinfo.h> +#include <svtools/rtfout.hxx> +#include <edtspell.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <com/sun/star/linguistic2/XMeaning.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/textsearch.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/help.hxx> +#include <svtools/rtfkeywd.hxx> +#include <editeng/edtdlg.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + +void SwapUSHORTs( sal_uInt16& rX, sal_uInt16& rY ) +{ + sal_uInt16 n = rX; + rX = rY; + rY = n; +} + +EditPaM ImpEditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + sal_Bool _bUpdate = GetUpdateMode(); + SetUpdateMode( sal_False ); + EditPaM aPaM; + if ( eFormat == EE_FORMAT_TEXT ) + aPaM = ReadText( rInput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + aPaM = ReadRTF( rInput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + aPaM = ReadXML( rInput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + aPaM = ReadHTML( rInput, rBaseURL, aSel, pHTTPHeaderAttrs ); + else if ( eFormat == EE_FORMAT_BIN) + aPaM = ReadBin( rInput, aSel ); + else + { + DBG_ERROR( "Read: Unbekanntes Format" ); + } + + FormatFullDoc(); // reicht vielleicht auch ein einfaches Format? + SetUpdateMode( _bUpdate ); + + return aPaM; +} + +EditPaM ImpEditEngine::ReadText( SvStream& rInput, EditSelection aSel ) +{ + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditPaM aPaM = aSel.Max(); + + XubString aTmpStr, aStr; + sal_Bool bDone = rInput.ReadByteStringLine( aTmpStr ); + while ( bDone ) + { + aTmpStr.Erase( MAXCHARSINPARA ); + aPaM = ImpInsertText( EditSelection( aPaM, aPaM ), aTmpStr ); + aPaM = ImpInsertParaBreak( aPaM ); + bDone = rInput.ReadByteStringLine( aTmpStr ); + } + return aPaM; +} + +EditPaM ImpEditEngine::ReadXML( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + + ESelection aESel = CreateESel( aSel ); + + ::SvxReadXML( *GetEditEnginePtr(), rInput, aESel ); + + return aSel.Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadRTF( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + +#if defined (EDITDEBUG) && !defined( UNX ) + SvFileStream aRTFOut( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_in.rtf" ) ), STREAM_WRITE ); + aRTFOut << rInput; + aRTFOut.Close(); + rInput.Seek( 0 ); +#endif + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + // Der SvRTF-Parser erwartet, dass das Which-Mapping am uebergebenen Pool, + // nicht an einem Secondary haengt. + SfxItemPool* pPool = &aEditDoc.GetItemPool(); + while ( pPool->GetSecondaryPool() && !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) + { + pPool = pPool->GetSecondaryPool(); + + } + DBG_ASSERT( pPool && pPool->GetName().EqualsAscii( "EditEngineItemPool" ), "ReadRTF: Kein EditEnginePool!" ); + + EditRTFParserRef xPrsr = new EditRTFParser( rInput, aSel, *pPool, this ); + SvParserState eState = xPrsr->CallParser(); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurPaM(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ +#ifndef SVX_LIGHT + + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + EditHTMLParserRef xPrsr = new EditHTMLParser( rInput, rBaseURL, pHTTPHeaderAttrs ); + SvParserState eState = xPrsr->CallParser( this, aSel.Max() ); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurSelection().Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadBin( SvStream& rInput, EditSelection aSel ) +{ + // Einfach ein temporaeres TextObject missbrauchen... + EditTextObject* pObj = EditTextObject::Create( rInput, NULL ); + + EditPaM aLastPaM = aSel.Max(); + if ( pObj ) + aLastPaM = InsertText( *pObj, aSel ).Max(); + + delete pObj; + return aLastPaM; +} + +#ifndef SVX_LIGHT +void ImpEditEngine::Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ) +{ + if ( !rOutput.IsWritable() ) + rOutput.SetError( SVSTREAM_WRITE_ERROR ); + + if ( !rOutput.GetError() ) + { + if ( eFormat == EE_FORMAT_TEXT ) + WriteText( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + WriteRTF( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + WriteXML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + WriteHTML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_BIN) + WriteBin( rOutput, aSel ); + else + { + DBG_ERROR( "Write: Unbekanntes Format" ); + } + } +} +#endif + +sal_uInt32 ImpEditEngine::WriteText( SvStream& rOutput, EditSelection aSel ) +{ + sal_uInt16 nStartNode, nEndNode; + sal_Bool bRange = aSel.HasRange(); + if ( bRange ) + { + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + } + else + { + nStartNode = 0; + nEndNode = aEditDoc.Count()-1; + } + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( bRange ) + { + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + } + XubString aTmpStr = aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); + rOutput.WriteByteStringLine( aTmpStr ); + } + + return rOutput.GetError(); +} + +sal_Bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + const SfxPoolItem* pAttrItem = rLst.First(); + while ( pAttrItem ) + { + WriteItemAsRTF( *pAttrItem, rOutput, nPara, nPos,rFontTable, rColorList ); + pAttrItem = rLst.Next(); + } + return ( rLst.Count() ? sal_True : sal_False ); +} + +void lcl_FindValidAttribs( ItemList& rLst, ContentNode* pNode, sal_uInt16 nIndex, USHORT nScriptType ) +{ + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nIndex ) ) + { + // Start wird in While ueberprueft... + if ( pAttr->GetEnd() > nIndex ) + { + if ( IsScriptItemValid( pAttr->GetItem()->Which(), nScriptType ) ) + rLst.Insert( pAttr->GetItem(), LIST_APPEND ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +sal_uInt32 ImpEditEngine::WriteBin( SvStream& rOutput, EditSelection aSel, BOOL bStoreUnicodeStrings ) const +{ + BinTextObject* pObj = (BinTextObject*)CreateBinTextObject( aSel, NULL ); + pObj->StoreUnicodeStrings( bStoreUnicodeStrings ); + pObj->Store( rOutput ); + delete pObj; + return 0; +} + +#ifndef SVX_LIGHT +sal_uInt32 ImpEditEngine::WriteXML( SvStream& rOutput, EditSelection aSel ) +{ + ESelection aESel = CreateESel( aSel ); + + SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel ); + + return 0; +} +#endif + +static sal_uInt16 getStylePos( const SfxStyles& rStyles, SfxStyleSheet* pSheet ) +{ + sal_uInt16 nNumber = 0; + SfxStyles::const_iterator iter( rStyles.begin() ); + while( iter != rStyles.end() ) + { + if( (*iter++).get() == pSheet ) + return nNumber; + ++nNumber; + } + return 0; +} + +sal_uInt32 ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + DBG_ASSERT( GetUpdateMode(), "WriteRTF bei UpdateMode = sal_False!" ); + CheckIdleFormatter(); + if ( !IsFormatted() ) + FormatDoc(); + + sal_uInt16 nStartNode, nEndNode; + aSel.Adjust( aEditDoc ); + + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + // RTF-Vorspann... + rOutput << '{' ; + + rOutput << OOO_STRING_SVTOOLS_RTF_RTF; + + rOutput << OOO_STRING_SVTOOLS_RTF_ANSI; + rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_MS_1252; + + // Fonttabelle erzeugen und rausschreiben... + SvxFontTable aFontTable; + // DefaultFont muss ganz vorne stehen, damit DEF-Font im RTF + aFontTable.Insert( 0, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO ) ) ); + aFontTable.Insert( 1, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CJK ) ) ); + aFontTable.Insert( 2, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CTL ) ) ); + for ( USHORT nScriptType = 0; nScriptType < 3; nScriptType++ ) + { + USHORT nWhich = EE_CHAR_FONTINFO; + if ( nScriptType == 1 ) + nWhich = EE_CHAR_FONTINFO_CJK; + else if ( nScriptType == 2 ) + nWhich = EE_CHAR_FONTINFO_CTL; + + sal_uInt16 i = 0; + SvxFontItem* pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, i ); + while ( pFontItem ) + { + bool bAlreadyExist = false; + ULONG nTestMax = nScriptType ? aFontTable.Count() : 1; + for ( ULONG nTest = 0; !bAlreadyExist && ( nTest < nTestMax ); nTest++ ) + { + bAlreadyExist = *aFontTable.Get( nTest ) == *pFontItem; + } + + if ( !bAlreadyExist ) + aFontTable.Insert( aFontTable.Count(), new SvxFontItem( *pFontItem ) ); + + pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, ++i ); + } + } + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL; + sal_uInt16 j; + for ( j = 0; j < aFontTable.Count(); j++ ) + { + SvxFontItem* pFontItem = aFontTable.Get( j ); + rOutput << '{'; + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( j ); + switch ( pFontItem->GetFamily() ) + { + case FAMILY_DONTKNOW: rOutput << OOO_STRING_SVTOOLS_RTF_FNIL; + break; + case FAMILY_DECORATIVE: rOutput << OOO_STRING_SVTOOLS_RTF_FDECOR; + break; + case FAMILY_MODERN: rOutput << OOO_STRING_SVTOOLS_RTF_FMODERN; + break; + case FAMILY_ROMAN: rOutput << OOO_STRING_SVTOOLS_RTF_FROMAN; + break; + case FAMILY_SCRIPT: rOutput << OOO_STRING_SVTOOLS_RTF_FSCRIPT; + break; + case FAMILY_SWISS: rOutput << OOO_STRING_SVTOOLS_RTF_FSWISS; + break; + default: + break; + } + rOutput << OOO_STRING_SVTOOLS_RTF_FPRQ; + sal_uInt16 nVal = 0; + switch( pFontItem->GetPitch() ) + { + case PITCH_FIXED: nVal = 1; break; + case PITCH_VARIABLE: nVal = 2; break; + default: + break; + } + rOutput.WriteNumber( nVal ); + + CharSet eChrSet = pFontItem->GetCharSet(); + DBG_ASSERT( eChrSet != 9, "SystemCharSet?!" ); + if( RTL_TEXTENCODING_DONTKNOW == eChrSet ) + eChrSet = gsl_getSystemTextEncoding(); + rOutput << OOO_STRING_SVTOOLS_RTF_FCHARSET; + rOutput.WriteNumber( rtl_getBestWindowsCharsetFromTextEncoding( eChrSet ) ); + + rOutput << ' '; + RTFOutFuncs::Out_String( rOutput, pFontItem->GetFamilyName(), eDestEnc ); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + + // ColorList rausschreiben... + SvxColorList aColorList; + sal_uInt16 i = 0; + SvxColorItem* pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, i ); + while ( pColorItem ) + { + USHORT nPos = i; + if ( pColorItem->GetValue() == COL_AUTO ) + nPos = 0; + aColorList.Insert( new SvxColorItem( *pColorItem ), nPos ); + pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, ++i ); + } + aColorList.Insert( new SvxColorItem( (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR) ), (sal_uInt32)i ); + + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_COLORTBL; + for ( j = 0; j < aColorList.Count(); j++ ) + { + pColorItem = aColorList.GetObject( j ); + if ( !j || ( pColorItem->GetValue() != COL_AUTO ) ) + { + rOutput << OOO_STRING_SVTOOLS_RTF_RED; + rOutput.WriteNumber( pColorItem->GetValue().GetRed() ); + rOutput << OOO_STRING_SVTOOLS_RTF_GREEN; + rOutput.WriteNumber( pColorItem->GetValue().GetGreen() ); + rOutput << OOO_STRING_SVTOOLS_RTF_BLUE; + rOutput.WriteNumber( pColorItem->GetValue().GetBlue() ); + } + rOutput << ';'; + } + rOutput << '}'; + rOutput << endl; + + // StyleSheets... + if ( GetStyleSheetPool() ) + { + sal_uInt16 nStyles = (sal_uInt16)GetStyleSheetPool()->GetStyles().size(); + if ( nStyles ) + { + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_STYLESHEET; + + for ( sal_uInt16 nStyle = 0; nStyle < nStyles; nStyle++ ) + { + + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->GetStyles()[ nStyle ].get(); + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) (nStyle + 1); + rOutput.WriteNumber( nNumber ); + + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pStyle->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pStyle->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + } + + // Parent...(nur wenn noetig) + if ( pStyle->GetParent().Len() && ( pStyle->GetParent() != pStyle->GetName() ) ) + { + SfxStyleSheet* pParent = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetParent(), pStyle->GetFamily() ); + DBG_ASSERT( pParent, "Parent nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SBASEDON; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pParent ) + 1; + rOutput.WriteNumber( nNumber ); + } + + // Folgevorlage...(immer) + SfxStyleSheet* pNext = pStyle; + if ( pStyle->GetFollow().Len() && ( pStyle->GetFollow() != pStyle->GetName() ) ) + pNext = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetFollow(), pStyle->GetFamily() ); + + DBG_ASSERT( pNext, "Naechsten nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SNEXT; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNext ) + 1; + rOutput.WriteNumber( nNumber ); + + // Namen der Vorlage... + rOutput << " " << ByteString( pStyle->GetName(), eDestEnc ).GetBuffer(); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + } + } + + // Die Pool-Defaults vorweg schreiben... + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaults"; + for ( sal_uInt16 nPoolDefItem = EE_PARA_START; nPoolDefItem <= EE_CHAR_END; nPoolDefItem++) + { + const SfxPoolItem& rItem = aEditDoc.GetItemPool().GetDefaultItem( nPoolDefItem ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + rOutput << '}' << endl; + + // Def-Hoehe vorweg, da sonst 12Pt + // Doch nicht, onst in jedem Absatz hart! + // SfxItemSet aTmpSet( GetEmptyItemSet() ); + // const SvxFontHeightItem& rDefFontHeight = (const SvxFontHeightItem&)aTmpSet.Get( EE_CHAR_FONTHEIGHT ); + // WriteItemAsRTF( rDefFontHeight, rOutput, aFontTable, aColorList ); + // rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaultHeight}" << endl; + + // DefTab: + MapMode aTwpMode( MAP_TWIP ); + sal_uInt16 nDefTabTwps = (sal_uInt16) GetRefDevice()->LogicToLogic( + Point( aEditDoc.GetDefTab(), 0 ), + &GetRefMapMode(), &aTwpMode ).X(); + rOutput << OOO_STRING_SVTOOLS_RTF_DEFTAB; + rOutput.WriteNumber( nDefTabTwps ); + rOutput << endl; + + // ueber die Absaetze iterieren... + rOutput << '{' << endl; + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + // Die Absatzattribute vorweg... + sal_Bool bAttr = sal_False; + + // Vorlage ? + if ( pNode->GetStyleSheet() ) + { + // Nummer der Vorlage + rOutput << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNode->GetStyleSheet() ) + 1; + rOutput.WriteNumber( nNumber ); + + // Alle Attribute + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pNode->GetStyleSheet()->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetStyleSheet()->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + } + + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { +// const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nParAttr ); + // Jetzt, wo StyleSheet-Verarbeitung, nur noch harte Absatzattribute! + if ( pNode->GetContentAttribs().GetItems().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + if ( bAttr ) + rOutput << ' '; // Separator + + ItemList aAttribItems; + ParaPortion* pParaPortion = FindParaPortion( pNode ); + DBG_ASSERT( pParaPortion, "Portion nicht gefunden: WriteRTF" ); + + sal_uInt16 nIndex = 0; + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + sal_uInt16 nStartPortion = 0; + sal_uInt16 nEndPortion = (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1; + sal_Bool bFinishPortion = sal_False; + sal_uInt16 nPortionStart; + + if ( nNode == nStartNode ) + { + nStartPos = aSel.Min().GetIndex(); + nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart ); + if ( nStartPos != 0 ) + { + aAttribItems.Clear(); + lcl_FindValidAttribs( aAttribItems, pNode, nStartPos, GetScriptType( EditPaM( pNode, 0 ) ) ); + if ( aAttribItems.Count() ) + { + // Diese Attribute duerfen nicht fuer den gesamten + // Absatz gelten: + rOutput << '{'; + WriteItemListAsRTF( aAttribItems, rOutput, nNode, nStartPos, aFontTable, aColorList ); + bFinishPortion = sal_True; + } + aAttribItems.Clear(); + } + } + if ( nNode == nEndNode ) // kann auch == nStart sein! + { + nEndPos = aSel.Max().GetIndex(); + nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart ); + } + + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + // Bei 0 anfangen, damit der Index richtig ist... + + for ( sal_uInt16 n = 0; n <= nEndPortion; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject(n); + if ( n < nStartPortion ) + { + nIndex = nIndex + pTextPortion->GetLen(); + continue; + } + + if ( pNextFeature && ( pNextFeature->GetStart() == nIndex ) && ( pNextFeature->GetItem()->Which() != EE_FEATURE_FIELD ) ) + { + WriteItemAsRTF( *pNextFeature->GetItem(), rOutput, nNode, nIndex, aFontTable, aColorList ); + pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); + } + else + { + aAttribItems.Clear(); + USHORT nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); + if ( !n || IsScriptChange( EditPaM( pNode, nIndex ) ) ) + { + SfxItemSet aAttribs = GetAttribs( nNode, nIndex+1, nIndex+1 ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ) ), LIST_APPEND ); + } + // #96298# Insert hard attribs AFTER CJK attribs... + lcl_FindValidAttribs( aAttribItems, pNode, nIndex, nScriptType ); + + rOutput << '{'; + if ( WriteItemListAsRTF( aAttribItems, rOutput, nNode, nIndex, aFontTable, aColorList ) ) + rOutput << ' '; + + USHORT nS = nIndex; + USHORT nE = nIndex + pTextPortion->GetLen(); + if ( n == nStartPortion ) + nS = nStartPos; + if ( n == nEndPortion ) + nE = nEndPos; + + XubString aRTFStr = aEditDoc.GetParaAsString( pNode, nS, nE); + RTFOutFuncs::Out_String( rOutput, aRTFStr, eDestEnc ); + rOutput << '}'; + } + if ( bFinishPortion ) + { + rOutput << '}'; + bFinishPortion = sal_False; + } + + nIndex = nIndex + pTextPortion->GetLen(); + } + + rOutput << OOO_STRING_SVTOOLS_RTF_PAR << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN;; + rOutput << endl; + } + // RTF-Nachspann... + rOutput << "}}"; // 1xKlammerung Absaetze, 1x Klammerung RTF-Dokument + rOutput.Flush(); + +#if defined (EDITDEBUG) && !defined( UNX ) + { + SvFileStream aStream( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_out.rtf" ) ), STREAM_WRITE|STREAM_TRUNC ); + ULONG nP = rOutput.Tell(); + rOutput.Seek( 0 ); + aStream << rOutput; + rOutput.Seek( nP ); + } +#endif + + return rOutput.GetError(); +#else + return 0; +#endif +} + + +void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + sal_uInt16 nWhich = rItem.Which(); + switch ( nWhich ) + { + case EE_PARA_WRITINGDIR: + { + const SvxFrameDirectionItem& rWritingMode = (const SvxFrameDirectionItem&)rItem; + if ( rWritingMode.GetValue() == FRMDIR_HORI_RIGHT_TOP ) + rOutput << "\\rtlpar"; + else + rOutput << "\\ltrpar"; + } + break; + case EE_PARA_OUTLLEVEL: + { + sal_Int16 nLevel = ((const SfxInt16Item&)rItem).GetValue(); + if( nLevel >= 0 ) + { + rOutput << "\\level"; + rOutput.WriteNumber( nLevel ); + } + } + break; + case EE_PARA_OUTLLRSPACE: + case EE_PARA_LRSPACE: + { +// const ContentNode *pNode = aEditDoc.GetObject( nPara ); + + rOutput << OOO_STRING_SVTOOLS_RTF_FI; + short nTxtFirst = ((const SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst(); + nTxtFirst = (short)LogicToTwips( nTxtFirst ); + rOutput.WriteNumber( nTxtFirst ); + rOutput << OOO_STRING_SVTOOLS_RTF_LI; + sal_uInt16 nTxtLeft = static_cast< sal_uInt16 >(((const SvxLRSpaceItem&)rItem).GetTxtLeft()); + nTxtLeft = (sal_uInt16)LogicToTwips( nTxtLeft ); + rOutput.WriteNumber( nTxtLeft ); + rOutput << OOO_STRING_SVTOOLS_RTF_RI; + sal_uInt32 nTxtRight = ((const SvxLRSpaceItem&)rItem).GetRight(); + nTxtRight = LogicToTwips( nTxtRight); + rOutput.WriteNumber( nTxtRight ); + } + break; + case EE_PARA_ULSPACE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SB; + sal_uInt16 nUpper = ((const SvxULSpaceItem&)rItem).GetUpper(); + nUpper = (sal_uInt16)LogicToTwips( nUpper ); + rOutput.WriteNumber( nUpper ); + rOutput << OOO_STRING_SVTOOLS_RTF_SA; + sal_uInt16 nLower = ((const SvxULSpaceItem&)rItem).GetLower(); + nLower = (sal_uInt16)LogicToTwips( nLower ); + rOutput.WriteNumber( nLower ); + } + break; + case EE_PARA_SBL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + long nVal = ((const SvxLineSpacingItem&)rItem).GetLineHeight(); + char cMult = '0'; + if ( ((const SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + // Woher kriege ich jetzt den Wert? + // Der SwRTF-Parser geht von einem 240er Font aus! + nVal = ((const SvxLineSpacingItem&)rItem).GetPropLineSpace(); + nVal *= 240; + nVal /= 100; + cMult = '1'; + } + rOutput.WriteNumber( nVal ); + rOutput << OOO_STRING_SVTOOLS_RTF_SLMULT << cMult; + } + break; + case EE_PARA_JUST: + { + SvxAdjust eJustification = ((const SvxAdjustItem&)rItem).GetAdjust(); + switch ( eJustification ) + { + case SVX_ADJUST_CENTER: rOutput << OOO_STRING_SVTOOLS_RTF_QC; + break; + case SVX_ADJUST_RIGHT: rOutput << OOO_STRING_SVTOOLS_RTF_QR; + break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_QL; + break; + } + } + break; + case EE_PARA_TABS: + { + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; + for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + rOutput << OOO_STRING_SVTOOLS_RTF_TX; + rOutput.WriteNumber( LogicToTwips( rTab.GetTabPos() ) ); + } + } + break; + case EE_CHAR_COLOR: + { + sal_uInt32 n = rColorList.GetId( (const SvxColorItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_CF; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + sal_uInt32 n = rFontTable.GetId( (const SvxFontItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_FS; + long nHeight = ((const SvxFontHeightItem&)rItem).GetHeight(); + nHeight = LogicToTwips( nHeight ); + // Twips => HalfPoints + nHeight /= 10; + rOutput.WriteNumber( nHeight ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + FontWeight e = ((const SvxWeightItem&)rItem).GetWeight(); + switch ( e ) + { + case WEIGHT_BOLD: rOutput << OOO_STRING_SVTOOLS_RTF_B; break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_B << '0'; break; + } + } + break; + case EE_CHAR_UNDERLINE: + { + // muesste bei WordLineMode ggf. ulw werden, + // aber die Information fehlt hier + FontUnderline e = ((const SvxUnderlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_ULNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_UL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_ULDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_ULD; break; + default: + break; + } + } + break; + case EE_CHAR_OVERLINE: + { + FontUnderline e = ((const SvxOverlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_OLNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_OL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_OLDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_OLD; break; + default: + break; + } + } + break; + case EE_CHAR_STRIKEOUT: + { + FontStrikeout e = ((const SvxCrossedOutItem&)rItem).GetStrikeout(); + switch ( e ) + { + case STRIKEOUT_SINGLE: + case STRIKEOUT_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE; break; + case STRIKEOUT_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + FontItalic e = ((const SvxPostureItem&)rItem).GetPosture(); + switch ( e ) + { + case ITALIC_OBLIQUE: + case ITALIC_NORMAL: rOutput << OOO_STRING_SVTOOLS_RTF_I; break; + case ITALIC_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_I << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_OUTLINE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_OUTL; + if ( ((const SvxContourItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_CHAR_RELIEF: + { + USHORT nRelief = ((const SvxCharReliefItem&)rItem).GetValue(); + if ( nRelief == RELIEF_EMBOSSED ) + rOutput << OOO_STRING_SVTOOLS_RTF_EMBO; + if ( nRelief == RELIEF_ENGRAVED ) + rOutput << OOO_STRING_SVTOOLS_RTF_IMPR; + } + break; + case EE_CHAR_EMPHASISMARK: + { + USHORT nMark = ((const SvxEmphasisMarkItem&)rItem).GetValue(); + if ( nMark == EMPHASISMARK_NONE ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCNONE; + else if ( nMark == EMPHASISMARK_SIDE_DOTS ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCCOMMA; + else + rOutput << OOO_STRING_SVTOOLS_RTF_ACCDOT; + } + break; + case EE_CHAR_SHADOW: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SHAD; + if ( ((const SvxShadowedItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_FEATURE_TAB: + { + rOutput << OOO_STRING_SVTOOLS_RTF_TAB; + } + break; + case EE_FEATURE_LINEBR: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + } + break; + case EE_CHAR_KERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_EXPNDTW; + rOutput.WriteNumber( LogicToTwips( + ((const SvxKerningItem&)rItem).GetValue() ) ); + } + break; + case EE_CHAR_PAIRKERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_KERNING; + rOutput.WriteNumber( ((const SvxAutoKernItem&)rItem).GetValue() ? 1 : 0 ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + SvxFont aFont; + ContentNode* pNode = aEditDoc.GetObject( nPara ); + SeekCursor( pNode, nPos, aFont ); + MapMode aPntMode( MAP_POINT ); + long nFontHeight = GetRefDevice()->LogicToLogic( + aFont.GetSize(), &GetRefMapMode(), &aPntMode ).Height(); + nFontHeight *=2; // HalfPoints + sal_uInt16 nProp = ((const SvxEscapementItem&)rItem).GetProp(); + sal_uInt16 nProp100 = nProp*100; // Fuer SWG-Token Prop in 100tel Prozent. + short nEsc = ((const SvxEscapementItem&)rItem).GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + { + nEsc = 100 - nProp; + nProp100++; // Eine 1 hinten bedeutet 'automatisch'. + } + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + { + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + nProp100++; + } + // SWG: + if ( nEsc ) + rOutput << "{\\*\\updnprop" << ByteString::CreateFromInt32( nProp100 ).GetBuffer() << '}'; + long nUpDown = nFontHeight * Abs( nEsc ) / 100; + ByteString aUpDown = ByteString::CreateFromInt32( nUpDown ); + if ( nEsc < 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_DN << aUpDown.GetBuffer(); + else if ( nEsc > 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_UP << aUpDown.GetBuffer(); + } + break; + } +} + +sal_uInt32 ImpEditEngine::WriteHTML( SvStream&, EditSelection ) +{ + return 0; +} + + +EditTextObject* ImpEditEngine::CreateTextObject() +{ + EditSelection aCompleteSelection; + aCompleteSelection.Min() = aEditDoc.GetStartPaM(); + aCompleteSelection.Max() = aEditDoc.GetEndPaM(); + + return CreateTextObject( aCompleteSelection ); +} + +EditTextObject* ImpEditEngine::CreateTextObject( EditSelection aSel ) +{ + return CreateBinTextObject( aSel, GetEditTextObjectPool(), aStatus.AllowBigObjects(), nBigTextObjectStart ); +} + +EditTextObject* ImpEditEngine::CreateBinTextObject( EditSelection aSel, SfxItemPool* pPool, sal_Bool bAllowBigObjects, sal_uInt16 nBigObjectStart ) const +{ + BinTextObject* pTxtObj = new BinTextObject( pPool ); + pTxtObj->SetVertical( IsVertical() ); + MapUnit eMapUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + pTxtObj->SetMetric( (sal_uInt16) eMapUnit ); + if ( pTxtObj->IsOwnerOfPool() ) + pTxtObj->GetPool()->SetDefaultMetric( (SfxMapUnit) eMapUnit ); + + sal_uInt16 nStartNode, nEndNode; + sal_uInt32 nTextPortions = 0; + + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + sal_Bool bOnlyFullParagraphs = ( aSel.Min().GetIndex() || + ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) ) ? + sal_False : sal_True; + + // Vorlagen werden nicht gespeichert! + // ( Nur Name und Familie, Vorlage selbst muss in App stehen! ) + + pTxtObj->SetScriptType( GetScriptType( aSel ) ); + + // ueber die Absaetze iterieren... + sal_uInt16 nNode; + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + if ( bOnlyFullParagraphs ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + nTextPortions += pParaPortion->GetTextPortions().Count(); + } + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + + sal_Bool bEmptyPara = nEndPos ? sal_False : sal_True; + + if ( ( nNode == nStartNode ) && !bOnlyFullParagraphs ) + nStartPos = aSel.Min().GetIndex(); + if ( ( nNode == nEndNode ) && !bOnlyFullParagraphs ) + nEndPos = aSel.Max().GetIndex(); + + + ContentInfo* pC = pTxtObj->CreateAndInsertContent(); + + // Die Absatzattribute... + pC->GetParaAttribs().Set( pNode->GetContentAttribs().GetItems() ); + + // Das StyleSheet... + if ( pNode->GetStyleSheet() ) + { + pC->GetStyle() = pNode->GetStyleSheet()->GetName(); + pC->GetFamily() = pNode->GetStyleSheet()->GetFamily(); + } + + // Der Text... + pC->GetText() = pNode->Copy( nStartPos, nEndPos-nStartPos ); + + // und die Attribute... + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + // In einem leeren Absatz die Attribute behalten! + if ( bEmptyPara || + ( ( pAttr->GetEnd() > nStartPos ) && ( pAttr->GetStart() < nEndPos ) ) ) + { + XEditAttribute* pX = pTxtObj->CreateAttrib( *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + // Evtl. korrigieren... + if ( ( nNode == nStartNode ) && ( nStartPos != 0 ) ) + { + pX->GetStart() = ( pX->GetStart() > nStartPos ) ? pX->GetStart()-nStartPos : 0; + pX->GetEnd() = pX->GetEnd() - nStartPos; + + } + if ( nNode == nEndNode ) + { + if ( pX->GetEnd() > (nEndPos-nStartPos) ) + pX->GetEnd() = nEndPos-nStartPos; + } + DBG_ASSERT( pX->GetEnd() <= (nEndPos-nStartPos), "CreateBinTextObject: Attribut zu lang!" ); + if ( !pX->GetLen() && !bEmptyPara ) + pTxtObj->DestroyAttrib( pX ); + else + pC->GetAttribs().Insert( pX, pC->GetAttribs().Count() ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + +#ifndef SVX_LIGHT + // ggf. Online-Spelling + if ( bAllowBigObjects && bOnlyFullParagraphs && pNode->GetWrongList() ) + pC->SetWrongList( pNode->GetWrongList()->Clone() ); +#endif // !SVX_LIGHT + + } + + // Bei grossen Textobjekten die PortionInfos merken: + // Schwelle rauf setzen, wenn Olli die Absaetze nicht mehr zerhackt! + if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) ) + { + XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width() ); + pTxtObj->SetPortionInfo( pXList ); + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + XParaPortion* pX = new XParaPortion; + pXList->Insert( pX, pXList->Count() ); + + pX->nHeight = pParaPortion->GetHeight(); + pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset(); + + // Die TextPortions + sal_uInt16 nCount = pParaPortion->GetTextPortions().Count(); + sal_uInt16 n; + for ( n = 0; n < nCount; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions()[n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pX->aTextPortions.Insert( pNew, pX->aTextPortions.Count() ); + } + + // Die Zeilen + nCount = pParaPortion->GetLines().Count(); + for ( n = 0; n < nCount; n++ ) + { + EditLine* pLine = pParaPortion->GetLines()[n]; + EditLine* pNew = pLine->Clone(); + pX->aLines.Insert( pNew, pX->aLines.Count() ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + return pTxtObj; +} + +void ImpEditEngine::SetText( const EditTextObject& rTextObject ) +{ + // Da Setzen eines TextObject ist nicht Undo-faehig! + ResetUndoManager(); + sal_Bool _bUpdate = GetUpdateMode(); + sal_Bool _bUndo = IsUndoEnabled(); + + SetText( XubString() ); + EditPaM aPaM = aEditDoc.GetStartPaM(); + + SetUpdateMode( sal_False ); + EnableUndo( sal_False ); + + InsertText( rTextObject, EditSelection( aPaM, aPaM ) ); + SetVertical( rTextObject.IsVertical() ); + +#ifndef SVX_LIGHT + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Woher kommt das Undo in SetText ?!" ); +#endif + SetUpdateMode( _bUpdate ); + EnableUndo( _bUndo ); +} + +EditSelection ImpEditEngine::InsertText( const EditTextObject& rTextObject, EditSelection aSel ) +{ + EnterBlockNotifications(); + aSel.Adjust( aEditDoc ); + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditSelection aNewSel = InsertBinTextObject( (BinTextObject&)rTextObject, aSel.Max() ); + LeaveBlockNotifications(); + return aNewSel; + + // MT 05/00: InsertBinTextObject direkt hier machen... +} + +EditSelection ImpEditEngine::InsertBinTextObject( BinTextObject& rTextObject, EditPaM aPaM ) +{ + // Optimieren: + // Kein GetPos undFindParaportion, sondern Index berechnen! + EditSelection aSel( aPaM, aPaM ); + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + + sal_Bool bUsePortionInfo = sal_False; +// sal_Bool bFields = sal_False; + XParaPortionList* pPortionInfo = rTextObject.GetPortionInfo(); + + if ( pPortionInfo && ( (long)pPortionInfo->GetPaperWidth() == aPaperSize.Width() ) + && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() ) ) + { + if ( ( pPortionInfo->GetRefDevPtr() == (sal_uIntPtr)GetRefDevice() ) || + ( ( pPortionInfo->GetRefDevType() == OUTDEV_VIRDEV ) && + ( GetRefDevice()->GetOutDevType() == OUTDEV_VIRDEV ) ) ) + bUsePortionInfo = sal_True; + } + + sal_Bool bConvertItems = sal_False; + MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit(); + if ( rTextObject.HasMetric() ) + { + eSourceUnit = (MapUnit)rTextObject.GetMetric(); + eDestUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + if ( eSourceUnit != eDestUnit ) + bConvertItems = sal_True; + } + + sal_uInt16 nContents = rTextObject.GetContents().Count(); + sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() ); + + for ( sal_uInt16 n = 0; n < nContents; n++, nPara++ ) + { + ContentInfo* pC = rTextObject.GetContents().GetObject( n ); + sal_Bool bNewContent = aPaM.GetNode()->Len() ? sal_False: sal_True; + sal_uInt16 nStartPos = aPaM.GetIndex(); + + aPaM = ImpFastInsertText( aPaM, pC->GetText() ); + + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in FastInsertText" ); + pPortion->MarkInvalid( nStartPos, pC->GetText().Len() ); + + // Zeicheattribute... + sal_Bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() ? sal_True : sal_False; + sal_uInt16 nNewAttribs = pC->GetAttribs().Count(); + if ( nNewAttribs ) + { + BOOL bUpdateFields = FALSE; + for ( sal_uInt16 nAttr = 0; nAttr < nNewAttribs; nAttr++ ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); + // Kann passieren wenn Absaetze >16K entstehen, dann wird einfach umgebrochen. + if ( pX->GetEnd() <= aPaM.GetNode()->Len() ) + { + if ( !bAllreadyHasAttribs || pX->IsFeature() ) + { + // Normale Attribute gehen dann schneller... + // Features duerfen nicht ueber EditDoc::InsertAttrib + // eingefuegt werden, sie sind bei FastInsertText schon im TextFluss + DBG_ASSERT( pX->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut zu gross!" ); + EditCharAttrib* pAttr; + if ( !bConvertItems ) + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(pX->GetItem()), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + else + { + SfxPoolItem* pNew = pX->GetItem()->Clone(); + ConvertItem( *pNew, eSourceUnit, eDestUnit ); + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + delete pNew; + } + DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (1)" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr ); + if ( pAttr->Which() == EE_FEATURE_FIELD ) + bUpdateFields = TRUE; + } + else + { + DBG_ASSERT( pX->GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (2)" ); + // Tabs und andere Features koennen nicht ueber InsertAttrib eingefuegt werden: + aEditDoc.InsertAttrib( aPaM.GetNode(), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos, *pX->GetItem() ); + } + } + } + if ( bUpdateFields ) + UpdateFields(); + + // Sonst QuickFormat => Keine Attribute! + pPortion->MarkSelectionInvalid( nStartPos, pC->GetText().Len() ); + } + + DBG_ASSERT( CheckOrderedList( aPaM.GetNode()->GetCharAttribs().GetAttribs(), sal_True ), "InsertBinTextObject: Start-Liste verdreht" ); + + sal_Bool bParaAttribs = sal_False; + if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) ) + { + bParaAttribs = sal_False; + // #101512# Don't overwrite level/style from existing paragraph in OutlineView + // MT 10/2002: Removed because of #103874#, handled in Outliner::EndPasteOrDropHdl now. +// if ( !aStatus.IsOutliner() || n ) + { + // nur dann Style und ParaAttribs, wenn neuer Absatz, oder + // komplett inneliegender... + bParaAttribs = pC->GetParaAttribs().Count() ? sal_True : sal_False; + if ( GetStyleSheetPool() && pC->GetStyle().Len() ) + { + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); + DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); + SetStyleSheet( nPara, pStyle ); + } + if ( !bConvertItems ) + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() ); + else + { + SfxItemSet aAttribs( GetEmptyItemSet() ); + ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit ); + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs ); + } + } + if ( bNewContent && bUsePortionInfo ) + { + XParaPortion* pXP = pPortionInfo->GetObject( n ); + DBG_ASSERT( pXP, "InsertBinTextObject: PortionInfo?" ); + ParaPortion* pParaPortion = GetParaPortions()[ nPara ]; + DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" ); + pParaPortion->nHeight = pXP->nHeight; + pParaPortion->nFirstLineOffset = pXP->nFirstLineOffset; + pParaPortion->bForceRepaint = sal_True; + pParaPortion->SetValid(); // Nicht formatieren + + // Die TextPortions + pParaPortion->GetTextPortions().Reset(); + sal_uInt16 nCount = pXP->aTextPortions.Count(); + for ( sal_uInt16 _n = 0; _n < nCount; _n++ ) + { + TextPortion* pTextPortion = pXP->aTextPortions[_n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pParaPortion->GetTextPortions().Insert( pNew, _n ); + } + + // Die Zeilen + pParaPortion->GetLines().Reset(); + nCount = pXP->aLines.Count(); + for ( sal_uInt16 m = 0; m < nCount; m++ ) + { + EditLine* pLine = pXP->aLines[m]; + EditLine* pNew = pLine->Clone(); + pNew->SetInvalid(); // neu Painten! + pParaPortion->GetLines().Insert( pNew, m ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + if ( !bParaAttribs ) // DefFont wird bei FastInsertParagraph nicht berechnet + { + aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); + if ( aStatus.UseCharAttribs() ) + aPaM.GetNode()->CreateDefFont(); + } + +#ifndef SVX_LIGHT + if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() ) + { + aPaM.GetNode()->DestroyWrongList(); // otherwise MLK, if list exists... + aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() ); + } +#endif // !SVX_LIGHT + + // Zeilenumbruch, wenn weitere folgen... + if ( n < ( nContents-1) ) + { + if ( bNewContent ) + aPaM = ImpFastInsertParagraph( nPara+1 ); + else + aPaM = ImpInsertParaBreak( aPaM, sal_False ); + } + } + + aSel.Max() = aPaM; + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + return aSel; +} + +LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, USHORT* pEndPos ) const +{ + short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen + USHORT nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + const SvxLanguageItem* pLangItem = &(const SvxLanguageItem&)rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ); + EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() ); + if ( pAttr ) + pLangItem = (const SvxLanguageItem*)pAttr->GetItem(); + + if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) ) + *pEndPos = pAttr->GetEnd(); + + return pLangItem->GetLanguage(); +} + +::com::sun::star::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const +{ + return SvxCreateLocale( GetLanguage( rPaM ) ); +} + +Reference< XSpellChecker1 > ImpEditEngine::GetSpeller() +{ +#ifndef SVX_LIGHT + if ( !xSpeller.is() ) + xSpeller = SvxGetSpellChecker(); +#endif + return xSpeller; +} + +EESpellState ImpEditEngine::Spell( EditView* pEditView, sal_Bool bMultipleDoc ) +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + + DBG_ASSERTWARNING( xSpeller.is(), "Kein Speller gesetzt!" ); + + if ( !xSpeller.is() ) + return EE_SPELL_NOSPELLER; + + aOnlineSpellTimer.Stop(); + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + { + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + } + + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart ) ) + bIsStart = sal_True; + + EditSpellWrapper* pWrp = new EditSpellWrapper( Application::GetDefDialogParent(), + xSpeller, bIsStart, sal_False, pEditView ); + pWrp->SpellDocument(); + delete pWrp; + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + EESpellState eState = pSpellInfo->eState; + delete pSpellInfo; + pSpellInfo = 0; + return eState; +#endif +} + + +sal_Bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang ) +{ +#ifdef SVX_LIGHT + return sal_False; +#else + sal_Bool bHasConvTxt = sal_False; + + USHORT nParas = pEditEngine->GetParagraphCount(); + for (USHORT k = 0; k < nParas; ++k) + { + SvUShorts aPortions; + pEditEngine->GetPortions( k, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // if the paragraph is not empty we need to increase the index + // by one since the attribute of the character left to the + // specified position is evaluated. + if (nEnd > nStart) // empty para? + ++nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + bHasConvTxt = (nSrcLang == nLangFound) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + if (bHasConvTxt) + return bHasConvTxt; + } + } + +#endif + return bHasConvTxt; +} + + +void ImpEditEngine::Convert( EditView* pEditView, + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ) +{ + // modified version of ImpEditEngine::Spell + +#ifdef SVX_LIGHT +#else + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + + // + // initialize pConvInfo + // + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Adjust( aEditDoc ); + pConvInfo = new ConvInfo; + pConvInfo->bMultipleDoc = bMultipleDoc; + pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() ); + // + // if it is not just a selection and we are about to begin + // with the current conversion for the very first time + // we need to find the start of the current (initial) + // convertible unit in order for the text conversion to give + // the correct result for that. Since it is easier to obtain + // the start of the word we use that though. + if (!aCurSel.HasRange() && ImplGetBreakIterator().is()) + { + EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() ); + + // since #118246 / #117803 still occurs if the cursor is placed + // between the two chinese characters to be converted (because both + // of them are words on their own!) using the word boundary here does + // not work. Thus since chinese conversion is not interactive we start + // at the begin of the paragraph to solve the problem, i.e. have the + // TextConversion service get those characters together in the same call. + USHORT nStartIdx = ( editeng::HangulHanjaConversion::IsChinese( nSrcLang ) ) ? + 0 : aWordStartPaM.GetIndex(); + pConvInfo->aConvStart.nIndex = nStartIdx; + } + // + pConvInfo->aConvContinue = pConvInfo->aConvStart; + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart ) + bIsStart = sal_True; + + bImpConvertFirstCall = sal_True; // next ImpConvert call is the very first in this conversion turn + + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + TextConvWrapper aWrp( Application::GetDefDialogParent(), xMSF, + SvxCreateLocale( nSrcLang ), SvxCreateLocale( nDestLang ), + pDestFont, + nOptions, bIsInteractive, + bIsStart, pEditView ); + + // + //!! optimization does not work since when update mode is false + //!! the object is 'lying' about it portions, paragraphs, + //!! EndPaM... later on. + //!! Should not be a great problem since text boxes or cells in + //!! Calc usually have only a rather short text. + // + // disallow formatting, updating the view, ... while + // non-interactively converting the document. (saves time) + //if (!bIsInteractive) + // SetUpdateMode( FALSE ); + + aWrp.Convert(); + + //if (!bIsInteractive) + //SetUpdateMode( TRUE, 0, TRUE ); + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + delete pConvInfo; + pConvInfo = 0; +#endif +} + + +void ImpEditEngine::SetLanguageAndFont( + const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ) +{ + ESelection aOldSel = pActiveView->GetSelection(); + pActiveView->SetSelection( rESel ); + + // set new language attribute + SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() ); + aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); + + // new font to be set? + DBG_ASSERT( pFont, "target font missing?" ); + if (pFont) + { + // set new font attribute + SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); + aFontItem.GetFamilyName() = pFont->GetName(); + aFontItem.GetFamily() = pFont->GetFamily(); + aFontItem.GetStyleName() = pFont->GetStyleName(); + aFontItem.GetPitch() = pFont->GetPitch(); + aFontItem.GetCharSet() = pFont->GetCharSet(); + aNewSet.Put( aFontItem ); + } + + // apply new attributes + pActiveView->SetAttribs( aNewSet ); + + pActiveView->SetSelection( aOldSel ); +} + + +void ImpEditEngine::ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, + EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, + sal_Bool bAllowImplicitChangesForNotConvertibleText, + LanguageType nTargetLang, const Font *pTargetFont ) +{ + // modified version of ImpEditEngine::ImpSpell + + // looks for next convertible text portion to be passed on to the wrapper + + String aRes; + LanguageType nResLang = LANGUAGE_NONE; + +#ifdef SVX_LIGHT + rConvTxt = rtl::OUString(); + rConvTxtLang = LANGUAGE_NONE; +#else + + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + + EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) ); + EditSelection aCurSel = EditSelection( aPos, aPos ); + + String aWord; + + while (!aRes.Len()) + { + // empty paragraph found that needs to have language and font set? + if (bAllowImplicitChangesForNotConvertibleText && + !pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).Len()) + { + USHORT nPara = pConvInfo->aConvContinue.nPara; + ESelection aESel( nPara, 0, nPara, 0 ); + // see comment for below same function call + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + + if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara && + pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex) + break; + +/* + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pConvInfo->bConvToEnd || pConvInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode && + aCurSel.Max().GetIndex() >= pLastNode->Len() ) + break; + } +*/ + + USHORT nAttribStart = USHRT_MAX; + USHORT nAttribEnd = USHRT_MAX; + USHORT nCurPos = USHRT_MAX; + EPaM aCurStart = CreateEPaM( aCurSel.Min() ); + SvUShorts aPortions; + pEditEngine->GetPortions( (USHORT)aCurStart.nPara, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // the language attribute is obtained from the left character + // (like usually all other attributes) + // thus we usually have to add 1 in order to get the language + // of the text right to the cursor position + USHORT nLangIdx = nEnd > nStart ? nStart + 1 : nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + sal_Bool bLangOk = (nLangFound == nSrcLang) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + + if (nAttribEnd != USHRT_MAX) // start already found? + { + DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" ); + DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" ); + if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang) + nAttribEnd = nEnd; + else // language attrib has changed + break; + } + if (nAttribStart == USHRT_MAX && // start not yet found? + nEnd > aCurStart.nIndex && bLangOk) + { + nAttribStart = nStart; + nAttribEnd = nEnd; + nResLang = nLangFound; + } + //! the list of portions may have changed compared to the previous + //! call to this function (because of possibly changed language + //! attribute!) + //! But since we don't want to start in the already processed part + //! we clip the start accordingly. + if (nAttribStart < aCurStart.nIndex) + { + nAttribStart = aCurStart.nIndex; + } + + // check script type to the right of the start of the current portion + EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) ); + sal_Bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetScriptType( aPaM )); + // not yet processed text part with for conversion + // not suitable language found that needs to be changed? + if (bAllowImplicitChangesForNotConvertibleText && + !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex) + { + ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd ); + // set language and font to target language and font of conversion + //! Now this especially includes all non convertible text e.g. + //! spaces, empty paragraphs and western text. + // This is in order for every *new* text entered at *any* position to + // have the correct language and font attributes set. + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + nCurPos = nEnd; + } + + if (nAttribStart != USHRT_MAX && nAttribEnd != USHRT_MAX) + { + aCurSel.Min().SetIndex( nAttribStart ); + aCurSel.Max().SetIndex( nAttribEnd ); + } + else if (nCurPos != USHRT_MAX) + { + // set selection to end of scanned text + // (used to set the position where to continue from later on) + aCurSel.Min().SetIndex( nCurPos ); + aCurSel.Max().SetIndex( nCurPos ); + } + + if ( !pConvInfo->bConvToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Min() ) ); + if ( !( aEPaM < pConvInfo->aConvTo ) ) + break; + } + + // clip selected word to the converted area + // (main use when conversion starts/ends **within** a word) + EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) ); + if (pConvInfo->bConvToEnd && + aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvContinue ); + if (aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvTo ); + if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&& + aCurSel.Max().GetNode() == aPaM.GetNode() && + aCurSel.Max().GetIndex() > aPaM.GetIndex()) + aCurSel.Max().SetIndex( aPaM.GetIndex() ); + + aWord = GetSelected( aCurSel ); + + if ( aWord.Len() > 0 /* && bLangOk */) + aRes = aWord; + + // move to next word/paragraph if necessary + if ( !aRes.Len() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + + pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() ); + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + + rConvTxt = aRes; + if (rConvTxt.getLength()) + rConvTxtLang = nResLang; +#endif +} + + +Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView ) +{ +#ifdef SVX_LIGHT + return Reference< XSpellAlternatives >(); +#else + + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + + ContentNode* pLastNode = aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Min() = aCurSel.Max(); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode ) + { + if ( ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + break; + } + } + else if ( !pSpellInfo->bSpellToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < pSpellInfo->aSpellTo ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + return xSpellAlt; +#endif +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::EndSpelling() +{ + DELETEZ(pSpellInfo); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + DBG_ASSERT(!pSpellInfo, "pSpellInfo already set?"); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + Search for the next wrong word within the given selection + -----------------------------------------------------------------------*/ +Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection) +{ + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( rSelection.Min() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + //check if the end of the selection has been reached + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + xSpellAlt = xSpeller->spell( aWord, GetLanguage( aCurSel.Max() ), aEmptySeq ); + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + { + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + rSelection = aCurSel; + } + } + return xSpellAlt; +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool ImpEditEngine::SpellSentence(EditView& rEditView, ::svx::SpellPortions& rToFill, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + bool bRet = false; + //the pSpellInfo has to be created on demand + if(!pSpellInfo) + { + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = sal_True; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + } + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + pSpellInfo->aLastSpellPortions.clear(); + pSpellInfo->aLastSpellContentSelections.clear(); + rToFill.clear(); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + //if no selection previously exists the range is extended to the end of the object + if(aCurSel.Min() == aCurSel.Max()) + { + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1); + aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len()); + } + Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel); + if(xAlt.is()) + { + bRet = true; + //find the sentence boundaries + EditSelection aSentencePaM = SelectSentence(aCurSel); + //make sure that the sentence is never smaller than the error range! + if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex()) + aSentencePaM.Max() = aCurSel.Max(); + //add the portion preceeding the error + EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min()); + if(aStartSelection.HasRange()) + AddPortionIterated(rEditView, aStartSelection, 0, rToFill); + //add the error portion + AddPortionIterated(rEditView, aCurSel, xAlt, rToFill); + //find the end of the sentence + //search for all errors in the rest of the sentence and add all the portions + do + { + EditSelection aNextSel = EditSelection(aCurSel.Max(), aSentencePaM.Max()); + xAlt = ImpFindNextError(aNextSel); + if(xAlt.is()) + { + //add the part between the previous and the current error + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), 0, rToFill); + //add the current error + AddPortionIterated(rEditView, aNextSel, xAlt, rToFill); + } + else + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill); + aCurSel = aNextSel; + } + while( xAlt.is() ); + //set the selection to the end of the current sentence + rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max()); + } +#endif + return bRet; +} + +/*-- 15.10.2003 16:09:12--------------------------------------------------- + adds one portion to the SpellPortions + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortion( + const EditSelection rSel, + uno::Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill, + bool bIsField) +{ +#ifdef SVX_LIGHT +#else + if(rSel.HasRange()) + { + svx::SpellPortion aPortion; + aPortion.sText = GetSelected( rSel ); + aPortion.eLanguage = GetLanguage( rSel.Min() ); + aPortion.xAlternatives = xAlt; + aPortion.bIsField = bIsField; + rToFill.push_back(aPortion); + + //save the spelled portions for later use + pSpellInfo->aLastSpellPortions.push_back(aPortion); + pSpellInfo->aLastSpellContentSelections.push_back(rSel); + + } +#endif +} + +/*-- 15.10.2003 16:07:47--------------------------------------------------- + adds one or more portions of text to the SpellPortions depending on language changes + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortionIterated( + EditView& rEditView, + const EditSelection rSel, + Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill) +{ +#ifdef SVX_LIGHT +#else + if(rSel.Min() != rSel.Max()) + { + if(xAlt.is()) + { + AddPortion(rSel, xAlt, rToFill, false); + } + else + { + //iterate and search for language attribute changes + //save the start and end positions + bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex(); + EditPaM aStart(bTest ? rSel.Min() : rSel.Max()); + EditPaM aEnd(bTest ? rSel.Max() : rSel.Min()); + //iterate over the text to find changes in language + //set the mark equal to the point + EditPaM aCursor(aStart); + rEditView.pImpEditView->SetEditSelection( aCursor ); + LanguageType eStartLanguage = GetLanguage( aCursor ); + //search for a field attribute at the beginning - only the end position + //of this field is kept to end a portion at that position + const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bool bIsField = pFieldAttr && + pFieldAttr->GetStart() == aCursor.GetIndex() && + pFieldAttr->GetStart() != pFieldAttr->GetEnd() && + pFieldAttr->Which() == EE_FEATURE_FIELD; + USHORT nEndField = bIsField ? pFieldAttr->GetEnd() : USHRT_MAX; + bool bIsEndField = false; + do + { + aCursor = CursorRight( aCursor); + //determine whether a field and has been reached + bIsEndField = nEndField == aCursor.GetIndex(); + //search for a new field attribute + EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bIsField = _pFieldAttr && + _pFieldAttr->GetStart() == aCursor.GetIndex() && + _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() && + _pFieldAttr->Which() == EE_FEATURE_FIELD; + //on every new field move the end position + if(bIsField) + nEndField = bIsField ? _pFieldAttr->GetEnd() : USHRT_MAX; + + LanguageType eCurLanguage = GetLanguage( aCursor ); + if(eCurLanguage != eStartLanguage || bIsField || bIsEndField) + { + eStartLanguage = eCurLanguage; + //go one step back - the cursor currently selects the first character + //with a different language + //create a selection from start to the current Cursor + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsEndField); + aStart = aCursor; + } + } + while(aCursor.GetIndex() < aEnd.GetIndex()); + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsField); + } + } +#endif +} + +/*-- 13.10.2003 16:43:33--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized"); + if(pSpellInfo) + { + UndoActionStart( EDITUNDO_INSERT ); + if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size()) + { + //the simple case: the same number of elements on both sides + //each changed element has to be applied to the corresponding source element + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); + svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end(); + SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end(); + bool bSetToEnd = false; + do + { + --aCurrentNewPortion; + --aCurrentOldPortion; + --aCurrentOldPosition; + //set the cursor to the end of the sentence - necessary to + //resume there at the next step + if(!bSetToEnd) + { + bSetToEnd = true; + rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() ); + } + + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); +// LanguageType eTextLanguage = GetLanguage( aCurrentOldPosition->Min() ); + + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) + { + //change text and apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText ); + } + else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) + { + //apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + } + if(aCurrentNewPortion == rNewPortions.begin()) + break; + } + while(aCurrentNewPortion != rNewPortions.begin()); + } + else + { + //select the complete sentence + SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end(); + --aCurrentEndPosition; + SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin(); + EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max()); + + //delete the sentence completely + ImpDeleteSelection( aAllSentence ); + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); + EditPaM aCurrentPaM = aAllSentence.Min(); + while(aCurrentNewPortion != rNewPortions.end()) + { + //set the language attribute + LanguageType eCurLanguage = GetLanguage( aCurrentPaM ); + if(eCurLanguage != aCurrentNewPortion->eLanguage) + { + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( aCurrentPaM, aSet ); + } + //insert the new string and set the cursor to the end of the inserted string + aCurrentPaM = ImpInsertText( aCurrentPaM , aCurrentNewPortion->sText ); + ++aCurrentNewPortion; + } + } + UndoActionEnd( EDITUNDO_INSERT ); + } + FormatAndUpdate(); + aEditDoc.SetModified(TRUE); +#endif +} +/*-- 08.09.2008 11:33:02--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::PutSpellingToSentenceStart( EditView& rEditView ) +{ +#ifdef SVX_LIGHT +#else + if( pSpellInfo && pSpellInfo->aLastSpellContentSelections.size() ) + { + rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() ); + } + +#endif +} + + +void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, sal_Bool bSpellAtCursorPos, sal_Bool bInteruptable ) +{ +#ifndef SVX_LIGHT + /* + Er wird ueber alle Absaetze iteriert, nur Absaetze mit invalidierter + WrongList werden geprueft... + + Es werden alle Woerter im invalidierten Bereich geprueft. + Ist ein Wort falsch, aber noch nicht in der WrongList, oder umgekehrt, + wird der Bereich des Wortes invalidiert + ( kein Invalidate, sondern wenn nur Uebergaenge von richtig=>falsch, + einfaches Paint, bei Uebergaengen von falsch=>richtig mit VDev + ueberplaetten ) + */ + + if ( !xSpeller.is() ) + return; + + EditPaM aCursorPos; + if( pActiveView && !bSpellAtCursorPos ) + { + DBG_CHKOBJ( pActiveView, EditView, 0 ); + aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max(); + } + sal_Bool bRestartTimer = sal_False; + + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + sal_uInt16 nNodes = GetEditDoc().Count(); + sal_uInt16 nInvalids = 0; + Sequence< PropertyValue > aEmptySeq; + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = GetEditDoc().GetObject( n ); + if ( pThisNodeOnly ) + pNode = pThisNodeOnly; + + if ( pNode->GetWrongList()->IsInvalid() ) + { + WrongList* pWrongList = pNode->GetWrongList(); + sal_uInt16 nInvStart = pWrongList->GetInvalidStart(); + sal_uInt16 nInvEnd = pWrongList->GetInvalidEnd(); + + sal_uInt16 nWrongs = 0; // Auch im Absatz mal die Kontrolle abgeben... +// sal_Bool bStop = sal_False; + + sal_uInt16 nPaintFrom = 0xFFFF, nPaintTo = 0; + sal_Bool bSimpleRepaint = sal_True; + + pWrongList->SetValid(); + + EditPaM aPaM( pNode, nInvStart ); + EditSelection aSel( aPaM, aPaM ); + while ( ( aSel.Max().GetNode() == pNode ) /* && !bStop */ ) + { + if ( ( aSel.Min().GetIndex() > nInvEnd ) + || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) ) + break; // Dokument- oder Ungueltigkeitsbereich-Ende + + aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aSel ) ); + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + sal_Bool bDottAdded = sal_False; + if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) + { + sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aSel.Max().GetIndex()++; + aWord += cNext; + bDottAdded = sal_True; + } + } + + + sal_Bool bChanged = sal_False; + if ( aWord.Len() > 0 ) + { + sal_uInt16 nWStart = aSel.Min().GetIndex(); + sal_uInt16 nWEnd= aSel.Max().GetIndex(); + if ( !xSpeller->isValid( aWord, GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) ), aEmptySeq ) ) + { + // Pruefen, ob schon richtig markiert... + nWrongs++; + // Nur bei SimpleRepaint stoppen, sonst zu oft VDev + // if ( ( nWrongs > 8 ) && bSimpleRepaint ) + // { + // bStop = sal_True; + // pWrongList->MarkInvalid( aSel.Max().GetIndex(), nInvEnd ); + // } + sal_uInt16 nXEnd = bDottAdded ? nWEnd -1 : nWEnd; + if ( !pWrongList->HasWrong( nWStart, nXEnd ) ) + { + // Wort als falsch markieren... + // Aber nur, wenn nicht an Cursor-Position... + sal_Bool bCursorPos = sal_False; + if ( aCursorPos.GetNode() == pNode ) + { + if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() ) + bCursorPos = sal_True; + } + if ( bCursorPos ) + { + // Dann weiter als ungueltig markieren... + pWrongList->GetInvalidStart() = nWStart; + pWrongList->GetInvalidEnd() = nWEnd; + bRestartTimer = sal_True; + } + else + { + // Es kann sein, dass die Wrongs in der Liste nicht + // genau ueber Woerter aufgespannt sind, weil die + // WordDelimiters beim Expandieren nicht ausgewrtet werden. + pWrongList->InsertWrong( nWStart, nXEnd, sal_True ); + bChanged = sal_True; + } + } + } + else + { + // Pruefen, ob nicht als als falsch markiert.... + if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) ) + { + pWrongList->ClearWrongs( nWStart, nWEnd, pNode ); + bSimpleRepaint = sal_False; + bChanged = sal_True; + } + } + if ( bChanged ) + { + if ( nPaintFrom == 0xFFFF ) + nPaintFrom = nWStart; + nPaintTo = nWEnd; + } + } + + EditPaM aLastEnd( aSel.Max() ); + aSel = WordRight( aSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + if ( bChanged && ( aSel.Min().GetNode() == pNode ) && + ( ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) ) ) + { + // Wenn zwei Worte durch mehr Zeichen als ein Blank getrennt + // sind, kann es passieren, dass beim Aufsplitten eines Wrongs + // der Start den zweiten Wortes vor dem tatsaechlich Wort liegt + pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode ); + } + } + + // Invalidieren? + if ( ( nPaintFrom != 0xFFFF ) ) + { + aStatus.GetStatusWord() |= EE_STAT_WRONGWORDCHANGED; + CallStatusHdl(); + + if ( aEditViews.Count() ) + { + // Bei SimpleRepaint wuerde ein uebermalen ohne VDev reichen, + // aber dann muesste ich ueber alle Views, Intersecten, + // Clippen, ... + // Lohnt wahrscheinlich nicht. + EditPaM aStartPaM( pNode, nPaintFrom ); + EditPaM aEndPaM( pNode, nPaintTo ); + Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) ); + Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) ); + DBG_ASSERT( aInvalidRec.IsEmpty(), "InvalidRect gesetzt!" ); + aInvalidRec.Left() = 0; + aInvalidRec.Right() = GetPaperSize().Width(); + aInvalidRec.Top() = aStartCursor.Top(); + aInvalidRec.Bottom() = aEndCursor.Bottom(); + if ( pActiveView && pActiveView->HasSelection() ) + { + // Dann darf nicht ueber VDev ausgegeben werden + UpdateViews( NULL ); + } + else if ( bSimpleRepaint ) + { + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + Rectangle aClipRec( aInvalidRec ); + aClipRec.Intersection( pView->GetVisArea() ); + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + aClipRec.SetPos( pView->pImpEditView->GetWindowPos( aClipRec.TopLeft() ) ); + // Wenn Selektion, dann VDev... + Paint( pView->pImpEditView, aClipRec, pView->HasSelection() ); + } + } + } + else + { + UpdateViews( pActiveView ); + } + aInvalidRec = Rectangle(); + } + } + // Nach zwei korrigierten Nodes die Kontrolle abgeben... + nInvalids++; + if ( bInteruptable && ( nInvalids >= 2 ) ) + { + bRestartTimer = sal_True; + break; + } + } + + if ( pThisNodeOnly ) + break; + } + if ( bRestartTimer ) + aOnlineSpellTimer.Start(); +#endif // !SVX_LIGHT +} + + +EESpellState ImpEditEngine::HasSpellErrors() +{ + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + +#ifndef SVX_LIGHT + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + EditSelection aCurSel( aEditDoc.GetStartPaM() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while ( !xSpellAlt.is() ) + { + if ( ( aCurSel.Max().GetNode() == pLastNode ) && + ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + { + return EE_SPELL_OK; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + aCurSel = WordRight( aCurSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } +#endif + + return EE_SPELL_ERRORFOUND; +} + +EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView ) +{ +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + if ( !aCurSel.HasRange() ) + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aCurSel ) ); + + Reference< XThesaurus > xThes( SvxGetThesaurus() ); + if (!xThes.is()) + return EE_SPELL_ERRORFOUND; + + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pEditView->GetWindow(), xThes, aWord, GetLanguage( aCurSel.Max() ) ); + if ( pDlg->Execute() == RET_OK ) + { + // Wort ersetzen... + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->InsertText( pDlg->GetWord() ); + pEditView->ShowCursor( sal_True, sal_False ); + } + + delete pDlg; + return EE_SPELL_OK; +#else + return EE_SPELL_NOSPELLER; +#endif +} + +sal_uInt16 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ) +{ + sal_uInt16 nFound = 0; + +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + + // FIND_ALL ohne Mehrfachselektion nicht moeglich. + if ( ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND ) || + ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL ) ) + { + if ( Search( rSearchItem, pEditView ) ) + nFound++; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE ) + { + // Das Wort ist selektiert, wenn der Anwender die Selektion + // nicht zwischendurch manipuliert: + if ( aCurSel.HasRange() ) + { + pEditView->InsertText( rSearchItem.GetReplaceString() ); + nFound = 1; + } + else + if( Search( rSearchItem, pEditView ) ) + nFound = 1; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL ) + { + // Der Writer ersetzt alle, vorn Anfang bis Ende... + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + + pEditView->pImpEditView->DrawSelection(); + + aCurSel.Adjust( aEditDoc ); + EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM(); + EditSelection aFoundSel( aCurSel.Max() ); + sal_Bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + if ( bFound ) + UndoActionStart( EDITUNDO_REPLACEALL ); + while ( bFound ) + { + nFound++; + aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() ); + bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + } + if ( nFound ) + { + EditPaM aNewPaM( aFoundSel.Max() ); + if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() ) + aNewPaM.GetIndex() = aNewPaM.GetNode()->Len(); + pEditView->pImpEditView->SetEditSelection( aNewPaM ); + FormatAndUpdate( pEditView ); + UndoActionEnd( EDITUNDO_REPLACEALL ); + } + else + { + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + } +#endif // !SVX_LIGHT + return nFound; +} + +BOOL ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView ) +{ + EditSelection aSel( pEditView->pImpEditView->GetEditSelection() ); + aSel.Adjust( aEditDoc ); + EditPaM aStartPaM( aSel.Max() ); + if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() ) + aStartPaM = aSel.Min(); + + EditSelection aFoundSel; + BOOL bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + if ( bFound && ( aFoundSel == aSel ) ) // Bei Rueckwaetssuche + { + aStartPaM = aSel.Min(); + bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + } + + pEditView->pImpEditView->DrawSelection(); + if ( bFound ) + { + // Erstmal das Min einstellen, damit das ganze Wort in den sichtbaren Bereich kommt. + pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() ); + pEditView->ShowCursor( TRUE, FALSE ); + pEditView->pImpEditView->SetEditSelection( aFoundSel ); + } + else + pEditView->pImpEditView->SetEditSelection( aSel.Max() ); + + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( TRUE, FALSE ); + return bFound; +} + +sal_Bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem, + const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ) +{ +#ifndef SVX_LIGHT + util::SearchOptions aSearchOptions( rSearchItem.GetSearchOptions() ); + aSearchOptions.Locale = GetLocale( rStartPos ); + + sal_Bool bBack = rSearchItem.GetBackward(); + sal_Bool bSearchInSelection = rSearchItem.GetSelection(); + sal_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() ); + sal_uInt16 nEndNode; + if ( bSearchInSelection ) + { + nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() ); + } + else + { + nEndNode = bBack ? 0 : aEditDoc.Count()-1; + } + + utl::TextSearch aSearcher( aSearchOptions ); + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; + bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ; + bBack ? nNode-- : nNode++ ) + { + // Bei rueckwaertsuche, wenn nEndNode = 0: + if ( nNode >= 0xFFFF ) + return sal_False; + + ContentNode* pNode = aEditDoc.GetObject( nNode ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + { + if ( bBack ) + nEndPos = rStartPos.GetIndex(); + else + nStartPos = rStartPos.GetIndex(); + } + if ( ( nNode == nEndNode ) && bSearchInSelection ) + { + if ( bBack ) + nStartPos = rSearchSelection.Min().GetIndex(); + else + nEndPos = rSearchSelection.Max().GetIndex(); + } + + // Suchen... + XubString aParaStr( GetEditDoc().GetParaAsString( pNode ) ); + bool bFound = false; + if ( bBack ) + { + SwapUSHORTs( nStartPos, nEndPos ); + bFound = aSearcher.SearchBkwrd( aParaStr, &nStartPos, &nEndPos); + } + else + bFound = aSearcher.SearchFrwrd( aParaStr, &nStartPos, &nEndPos); + + if ( bFound ) + { + rFoundSel.Min().SetNode( pNode ); + rFoundSel.Min().SetIndex( nStartPos ); + rFoundSel.Max().SetNode( pNode ); + rFoundSel.Max().SetIndex( nEndPos ); + return sal_True; + } + } +#endif // !SVX_LIGHT + return sal_False; +} + +sal_Bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem ) +{ +#ifndef SVX_LIGHT + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + aTmpItem.SetSelection( sal_False ); + + EditPaM aStartPaM( aEditDoc.GetStartPaM() ); + EditSelection aDummySel( aStartPaM ); + EditSelection aFoundSel; + return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel ); +#else + return sal_False; +#endif +} + +void ImpEditEngine::SetAutoCompleteText( const String& rStr, sal_Bool bClearTipWindow ) +{ +#ifndef SVX_LIGHT + aAutoCompleteText = rStr; + if ( bClearTipWindow && pActiveView ) + Help::ShowQuickHelp( pActiveView->GetWindow(), Rectangle(), String(), 0 ); +#endif // !SVX_LIGHT +} + +EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ) +{ + EditSelection aSel( rSelection ); + aSel.Adjust( aEditDoc ); + + if ( !aSel.HasRange() ) + aSel = SelectWord( aSel ); + + EditSelection aNewSel( aSel ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + BOOL bChanges = FALSE; + BOOL bLenChanged = FALSE; + EditUndoTransliteration* pUndo = NULL; + + utl::TransliterationWrapper aTranslitarationWrapper( ::comphelper::getProcessServiceFactory(), nTransliterationMode ); + BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); + + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + USHORT nCurrentStart = nStartPos; + USHORT nCurrentEnd = nEndPos; + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + + do + { + if ( bConsiderLanguage ) + { + nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd ); + if ( nCurrentEnd > nEndPos ) + nCurrentEnd = nEndPos; + } + + xub_StrLen nLen = nCurrentEnd - nCurrentStart; + + Sequence <sal_Int32> aOffsets; + String aNewText( aTranslitarationWrapper.transliterate( *pNode, nLanguage, nCurrentStart, nLen, &aOffsets ) ); + + if( ( nLen != aNewText.Len() ) || !pNode->Equals( aNewText, nCurrentStart, nLen ) ) + { + bChanges = TRUE; + if ( nLen != aNewText.Len() ) + bLenChanged = TRUE; + +#ifndef SVX_LIGHT + // Create UndoAction on Demand.... + if ( !pUndo && IsUndoEnabled() && !IsInUndo() ) + { + ESelection aESel( CreateESel( aSel ) ); + pUndo = new EditUndoTransliteration( this, aESel, nTransliterationMode ); + + if ( ( nStartNode == nEndNode ) && !aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() ) ) + pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) ); + else + pUndo->SetText( CreateBinTextObject( aSel, NULL ) ); + } +#endif + + // Change text without loosing the attributes + USHORT nCharsAfterTransliteration = + sal::static_int_cast< USHORT >(aOffsets.getLength()); + const sal_Int32* pOffsets = aOffsets.getConstArray(); + short nDiffs = 0; + for ( USHORT n = 0; n < nCharsAfterTransliteration; n++ ) + { + USHORT nCurrentPos = nCurrentStart+n; + sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n]; + + if ( !nDiff ) + { + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + } + else if ( nDiff < 0 ) + { + // Replace first char, delete the rest... + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + + DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" ); + GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), sal::static_int_cast< USHORT >(-nDiff) ); + } + else + { + DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." ); + GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), aNewText.GetChar(n) ); + + } + nDiffs = sal::static_int_cast< short >(nDiffs + nDiff); + } + + if ( nNode == nEndNode ) + aNewSel.Max().GetIndex() = + aNewSel.Max().GetIndex() + nDiffs; + + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + pParaPortion->MarkSelectionInvalid( nCurrentStart, std::max< USHORT >( nCurrentStart+nLen, nCurrentStart+aNewText.Len() ) ); + + } + nCurrentStart = nCurrentEnd; + } while( nCurrentEnd < nEndPos ); + } + +#ifndef SVX_LIGHT + if ( pUndo ) + { + ESelection aESel( CreateESel( aNewSel ) ); + pUndo->SetNewSelection( aESel ); + InsertUndo( pUndo ); + } +#endif + + if ( bChanges ) + { + TextModified(); + SetModifyFlag( sal_True ); + if ( bLenChanged ) + UpdateSelections(); + FormatAndUpdate(); + } + + return aNewSel; +} + +void ImpEditEngine::SetAsianCompressionMode( USHORT n ) +{ + if ( n != nAsianCompressionMode ) + { + nAsianCompressionMode = n; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetKernAsianPunctuation( BOOL b ) +{ + if ( b != bKernAsianPunctuation ) + { + bKernAsianPunctuation = b; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetAddExtLeading( BOOL bExtLeading ) +{ + if ( IsAddExtLeading() != bExtLeading ) + { + bAddExtLeading = bExtLeading; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +}; + + + +BOOL ImpEditEngine::ImplHasText() const +{ + return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() ); +} + +long ImpEditEngine::LogicToTwips( long n ) +{ + Size aSz( n, 0 ); + MapMode aTwipsMode( MAP_TWIP ); + aSz = pRefDev->LogicToLogic( aSz, NULL, &aTwipsMode ); + return aSz.Width(); +} + + diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx new file mode 100644 index 000000000000..2efbb60b6c0f --- /dev/null +++ b/editeng/source/editeng/impedit5.cxx @@ -0,0 +1,911 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editdbg.hxx> + +#include <svl/smplhint.hxx> + + +#include <editeng/lrspitem.hxx> + +void ImpEditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool ) +{ + if ( pStylePool != pSPool ) + { +// if ( pStylePool ) +// EndListening( *pStylePool, TRUE ); + + pStylePool = pSPool; + +// if ( pStylePool ) +// StartListening( *pStylePool, TRUE ); + } +} + +SfxStyleSheet* ImpEditEngine::GetStyleSheet( USHORT nPara ) const +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + return pNode ? pNode->GetContentAttribs().GetStyleSheet() : NULL; +} + +void ImpEditEngine::SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle ) +{ + aSel.Adjust( aEditDoc ); + + USHORT nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() ); + + BOOL _bUpdate = GetUpdateMode(); + SetUpdateMode( FALSE ); + + for ( USHORT n = nStartPara; n <= nEndPara; n++ ) + SetStyleSheet( n, pStyle ); + + SetUpdateMode( _bUpdate, 0 ); +} + +void ImpEditEngine::SetStyleSheet( USHORT nPara, SfxStyleSheet* pStyle ) +{ + DBG_ASSERT( GetStyleSheetPool() || !pStyle, "SetStyleSheet: No StyleSheetPool registered!" ); + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + SfxStyleSheet* pCurStyle = pNode->GetStyleSheet(); + if ( pStyle != pCurStyle ) + { + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + XubString aPrevStyleName; + if ( pCurStyle ) + aPrevStyleName = pCurStyle->GetName(); + + XubString aNewStyleName; + if ( pStyle ) + aNewStyleName = pStyle->GetName(); + + InsertUndo( + new EditUndoSetStyleSheet( this, aEditDoc.GetPos( pNode ), + aPrevStyleName, pCurStyle ? pCurStyle->GetFamily() : SFX_STYLE_FAMILY_PARA, + aNewStyleName, pStyle ? pStyle->GetFamily() : SFX_STYLE_FAMILY_PARA, + pNode->GetContentAttribs().GetItems() ) ); + } + if ( pCurStyle ) + EndListening( *pCurStyle, FALSE ); + pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() ); + if ( pStyle ) + StartListening( *pStyle, FALSE ); + ParaAttribsChanged( pNode ); + } + FormatAndUpdate(); +} + +void ImpEditEngine::UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle ) +{ + SvxFont aFontFromStyle; + CreateFont( aFontFromStyle, pStyle->GetItemSet() ); + + BOOL bUsed = FALSE; + for ( USHORT nNode = 0; nNode < aEditDoc.Count(); nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + if ( pNode->GetStyleSheet() == pStyle ) + { + bUsed = TRUE; + if ( aStatus.UseCharAttribs() ) + pNode->SetStyleSheet( pStyle, aFontFromStyle ); + else + pNode->SetStyleSheet( pStyle, FALSE ); + + ParaAttribsChanged( pNode ); + } + } + if ( bUsed ) + { + GetEditEnginePtr()->StyleSheetChanged( pStyle ); + FormatAndUpdate(); + } +} + +void ImpEditEngine::RemoveStyleFromParagraphs( SfxStyleSheet* pStyle ) +{ + for ( USHORT nNode = 0; nNode < aEditDoc.Count(); nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject(nNode); + if ( pNode->GetStyleSheet() == pStyle ) + { + pNode->SetStyleSheet( NULL ); + ParaAttribsChanged( pNode ); + } + } + FormatAndUpdate(); +} + +void ImpEditEngine::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + // Damit nicht beim Destruieren unnoetig formatiert wird: + if ( !bDowning ) + { + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + SfxStyleSheet* pStyle = NULL; + ULONG nId = 0; + + if ( rHint.ISA( SfxStyleSheetHint ) ) + { + const SfxStyleSheetHint& rH = (const SfxStyleSheetHint&) rHint; + DBG_ASSERT( rH.GetStyleSheet()->ISA( SfxStyleSheet ), "Kein SfxStyleSheet!" ); + pStyle = (SfxStyleSheet*) rH.GetStyleSheet(); + nId = rH.GetHint(); + } + else if ( ( rHint.Type() == TYPE(SfxSimpleHint ) ) && ( rBC.ISA( SfxStyleSheet ) ) ) + { + pStyle = (SfxStyleSheet*)&rBC; + nId = ((SfxSimpleHint&)rHint).GetId(); + } + + if ( pStyle ) + { + if ( ( nId == SFX_HINT_DYING ) || + ( nId == SFX_STYLESHEET_INDESTRUCTION ) || + ( nId == SFX_STYLESHEET_ERASED ) ) + { + RemoveStyleFromParagraphs( pStyle ); + } + else if ( ( nId == SFX_HINT_DATACHANGED ) || + ( nId == SFX_STYLESHEET_MODIFIED ) ) + { + UpdateParagraphsWithStyleSheet( pStyle ); + + // Alle Absaetze mit EditStyles, die das geaenderte Style + // irgendwie als Parent haben, muessen formatiert werden. + // ULONG nStyles = pMyStylePool->GetStyles().Count(); + // for ( ULONG nStyle = 0; nStyle < nStyles; nStyle++ ) + // { + // EditStyleSheet* pES = (EditStyleSheet*)pMyStylePool->GetStyles().GetObject( nStyle ); + // DBG_ASSERT( pES, "NULL-Pointer im StyleSheetPool!" ); + // if ( pES->IsUsed() && pES->HasStyleAsAnyParent( *pStyle ) ) + // UpdateParagraphsWithStyleSheet( pES ); + // } + } + } + } +} + +EditUndoSetAttribs* ImpEditEngine::CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet ) +{ + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateAttribUndo: Fehlerhafte Selektion" ); + aSel.Adjust( aEditDoc ); + + ESelection aESel( CreateESel( aSel ) ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + DBG_ASSERT( nStartNode <= nEndNode, "CreateAttribUndo: Start > End ?!" ); + + EditUndoSetAttribs* pUndo = NULL; + if ( rSet.GetPool() != &aEditDoc.GetItemPool() ) + { + SfxItemSet aTmpSet( GetEmptyItemSet() ); + aTmpSet.Put( rSet ); + pUndo = new EditUndoSetAttribs( this, aESel, aTmpSet ); + } + else + { + pUndo = new EditUndoSetAttribs( this, aESel, rSet ); + } + + SfxItemPool* pPool = pUndo->GetNewAttribs().GetPool(); + + for ( USHORT nPara = nStartNode; nPara <= nEndNode; nPara++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( aEditDoc.SaveGetObject( nPara ), "Node nicht gefunden: CreateAttribUndo" ); + ContentAttribsInfo* pInf = new ContentAttribsInfo( pNode->GetContentAttribs().GetItems() ); + pUndo->GetContentInfos().Insert( pInf, pUndo->GetContentInfos().Count() ); + + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ]; + if ( pAttr->GetLen() ) + { + EditCharAttribPtr pNew = MakeCharAttrib( *pPool, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + pInf->GetPrevCharAttribs().Insert( pNew, pInf->GetPrevCharAttribs().Count() ); + } + } + } + return pUndo; +} + +void ImpEditEngine::UndoActionStart( USHORT nId, const ESelection& aSel ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId ); + DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" ); + pUndoMarkSelection = new ESelection( aSel ); + } +} + +void ImpEditEngine::UndoActionStart( USHORT nId ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId ); + DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" ); + } +} + +void ImpEditEngine::UndoActionEnd( USHORT ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().LeaveListAction(); + delete pUndoMarkSelection; + pUndoMarkSelection = NULL; + } +} + +void ImpEditEngine::InsertUndo( EditUndo* pUndo, BOOL bTryMerge ) +{ + DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" ); + if ( pUndoMarkSelection ) + { + EditUndoMarkSelection* pU = new EditUndoMarkSelection( this, *pUndoMarkSelection ); + GetUndoManager().AddUndoAction( pU, FALSE ); + delete pUndoMarkSelection; + pUndoMarkSelection = NULL; + } + GetUndoManager().AddUndoAction( pUndo, bTryMerge ); + + mbLastTryMerge = bTryMerge; +} + +void ImpEditEngine::ResetUndoManager() +{ + if ( HasUndoManager() ) + GetUndoManager().Clear(); +} + +void ImpEditEngine::EnableUndo( BOOL bEnable ) +{ + // Beim Umschalten des Modus Liste loeschen: + if ( bEnable != IsUndoEnabled() ) + ResetUndoManager(); + + bUndoEnabled = bEnable; +} + +BOOL ImpEditEngine::Undo( EditView* pView ) +{ + if ( HasUndoManager() && GetUndoManager().GetUndoActionCount() ) + { + SetActiveView( pView ); + GetUndoManager().Undo( 1 ); + return TRUE; + } + return FALSE; +} + +BOOL ImpEditEngine::Redo( EditView* pView ) +{ + if ( HasUndoManager() && GetUndoManager().GetRedoActionCount() ) + { + SetActiveView( pView ); + GetUndoManager().Redo( 0 ); + return TRUE; + } + return FALSE; +} + +BOOL ImpEditEngine::Repeat( EditView* /* pView */ ) +{ + if ( HasUndoManager() && GetUndoManager().GetRepeatActionCount() ) + { + DBG_WARNING( "Repeat nicht implementiert!" ); + return TRUE; + } + return FALSE; +} + +SfxItemSet ImpEditEngine::GetAttribs( EditSelection aSel, BOOL bOnlyHardAttrib ) +{ + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + aSel.Adjust( aEditDoc ); + +#if OSL_DEBUG_LEVEL > 1 +// if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && ( bOnlyHardAttrib == EditEngineAttribs_All ) ) +// return GetAttribs( aEditDoc.GetPos( aSel.Min().GetNode() ), aSel.Min().GetIndex(), aSel.Max().GetIndex(), GETATTRIBS_ALL ); +#endif + + + SfxItemSet aCurSet( GetEmptyItemSet() ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetAttrib" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // Problem: Vorlagen.... + // => Andersrum: + // 1) Harte Zeichenattribute, wie gehabt... + // 2) Nur wenn OFF, Style and Absatzattr. pruefen... + + // Erst die ganz harte Formatierung... + aEditDoc.FindAttribs( pNode, nStartPos, nEndPos, aCurSet ); + + if( bOnlyHardAttrib != EditEngineAttribs_OnlyHard ) + { + // Und dann Absatzformatierung und Vorlage... + // SfxStyleSheet* pStyle = pNode->GetStyleSheet(); + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich ); + aCurSet.Put( rItem ); + } + else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nWhich ); + aCurSet.Put( rItem ); + } + } + else if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem* pItem = NULL; + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + pItem = &pNode->GetContentAttribs().GetItem( nWhich ); + } + else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON ) + { + pItem = &pNode->GetContentAttribs().GetItems().Get( nWhich ); + } + // pItem can only be NULL when bOnlyHardAttrib... + if ( !pItem || ( *pItem != aCurSet.Get( nWhich ) ) ) + { + // Problem: Wenn Absatzvorlage mit z.B. Font, + // aber Font hart und anders und komplett in Selektion + // Falsch, wenn invalidiert.... + // => Lieber nicht invalidieren, UMSTELLEN! + // Besser waere, Absatzweise ein ItemSet zu fuellen + // und dieses mit dem gesmten vergleichen. + // aCurSet.InvalidateItem( nWhich ); + if ( nWhich <= EE_PARA_END ) + aCurSet.InvalidateItem( nWhich ); + } + } + } + } + } + + // Leere Slots mit Defaults fuellen... + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + aCurSet.Put( aEditDoc.GetItemPool().GetDefaultItem( nWhich ) ); + } + } + } + return aCurSet; +} + + +SfxItemSet ImpEditEngine::GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags ) const +{ + // MT: #94002# Optimized function with less Puts(), which cause unnecessary cloning from default items. + // If this works, change GetAttribs( EditSelection ) to use this for each paragraph and merge the results! + + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" ); + DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" ); + + SfxItemSet aAttribs( ((ImpEditEngine*)this)->GetEmptyItemSet() ); + + if ( pNode ) + { + if ( nEnd > pNode->Len() ) + nEnd = pNode->Len(); + + if ( nStart > nEnd ) + nStart = nEnd; + + // StyleSheet / Parattribs... + + if ( pNode->GetStyleSheet() && ( nFlags & GETATTRIBS_STYLESHEET ) ) + aAttribs.Set( pNode->GetStyleSheet()->GetItemSet(), TRUE ); + + if ( nFlags & GETATTRIBS_PARAATTRIBS ) + aAttribs.Put( pNode->GetContentAttribs().GetItems() ); + + // CharAttribs... + + if ( nFlags & GETATTRIBS_CHARATTRIBS ) + { + // Make testing easier... + pNode->GetCharAttribs().OptimizeRanges( ((ImpEditEngine*)this)->GetEditDoc().GetItemPool() ); + + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( USHORT nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs.GetObject( nAttr ); + + if ( nStart == nEnd ) + { + USHORT nCursorPos = nStart; + if ( ( pAttr->GetStart() <= nCursorPos ) && ( pAttr->GetEnd() >= nCursorPos ) ) + { + // To be used the attribute has to start BEFORE the position, or it must be a + // new empty attr AT the position, or we are on position 0. + if ( ( pAttr->GetStart() < nCursorPos ) || pAttr->IsEmpty() || !nCursorPos ) + { + // maybe this attrib ends here and a new attrib with 0 Len may follow and be valid here, + // but that s no problem, the empty item will come later and win. + aAttribs.Put( *pAttr->GetItem() ); + } + } + } + else + { + // Check every attribute covering the area, partial or full. + if ( ( pAttr->GetStart() < nEnd ) && ( pAttr->GetEnd() > nStart ) ) + { + if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) + { + // full coverage + aAttribs.Put( *pAttr->GetItem() ); + } + else + { + // OptimizeRagnge() assures that not the same attr can follow for full coverage + // only partial, check with current, when using para/styhe, otherwise invalid. + if ( !( nFlags & (GETATTRIBS_PARAATTRIBS|GETATTRIBS_STYLESHEET) ) || + ( *pAttr->GetItem() != aAttribs.Get( pAttr->Which() ) ) ) + { + aAttribs.InvalidateItem( pAttr->Which() ); + } + } + } + } + + if ( pAttr->GetStart() > nEnd ) + { + break; + } + } + } + } + + return aAttribs; +} + + +void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, BYTE nSpecial ) +{ + aSel.Adjust( aEditDoc ); + + // Wenn keine Selektion => die Attribute aufs Wort anwenden. + // ( Der RTF-Perser sollte die Methode eigentlich nie ohne Range rufen ) + if ( ( nSpecial == ATTRSPECIAL_WHOLEWORD ) && !aSel.HasRange() ) + aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, FALSE ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, rSet ); + pUndo->SetSpecial( nSpecial ); + InsertUndo( pUndo ); + } + + BOOL bCheckLanguage = FALSE; + if ( GetStatus().DoOnlineSpelling() ) + { + bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SFX_ITEM_ON ) || + ( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SFX_ITEM_ON ) || + ( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SFX_ITEM_ON ); + } + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + BOOL bParaAttribFound = FALSE; + BOOL bCharAttribFound = FALSE; + + ContentNode* pNode = aEditDoc.GetObject( nNode ); + ParaPortion* pPortion = GetParaPortions().GetObject( nNode ); + + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" ); + DBG_ASSERT( GetParaPortions().GetObject( nNode ), "Portion nicht gefunden: SetAttribs" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // ueber die Items iterieren... +#ifdef EDITDEBUG +// FILE* fp = fopen( "d:\\debug.log", "a" ); +// if ( fp ) +// { +// fprintf( fp, "\n\n=> Zeichen-Attribute: Absatz %i, %i-%i\n", nNode, nStartPos, nEndPos ); +// DbgOutItemSet( fp, rSet, TRUE, FALSE ); +// fclose( fp ); +// } +#endif + + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + if ( rSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rSet.Get( nWhich ); + if ( nWhich <= EE_PARA_END ) + { + pNode->GetContentAttribs().GetItems().Put( rItem ); + bParaAttribFound = TRUE; + } + else + { + aEditDoc.InsertAttrib( pNode, nStartPos, nEndPos, rItem ); + bCharAttribFound = TRUE; + if ( nSpecial == ATTRSPECIAL_EDGE ) + { + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + USHORT nAttrs = rAttribs.Count(); + for ( USHORT n = 0; n < nAttrs; n++ ) + { + EditCharAttrib* pAttr = rAttribs.GetObject( n ); + if ( pAttr->GetStart() > nEndPos ) + break; + + if ( ( pAttr->GetEnd() == nEndPos ) && ( pAttr->Which() == nWhich ) ) + { + pAttr->SetEdge( TRUE ); + break; + } + } + } + } + } + } + + if ( bParaAttribFound ) + { + ParaAttribsChanged( pPortion->GetNode() ); + } + else if ( bCharAttribFound ) + { + bFormatted = FALSE; + if ( !pNode->Len() || ( nStartPos != nEndPos ) ) + { + pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos ); + if ( bCheckLanguage ) + pNode->GetWrongList()->MarkInvalid( nStartPos, nEndPos ); + } + } + } +} + +void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, BOOL bRemoveParaAttribs, USHORT nWhich ) +{ + aSel.Adjust( aEditDoc ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : 0; + + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + // Eventuel spezielles Undo, oder ItemSet* + EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, GetEmptyItemSet() ); + pUndo->SetRemoveAttribs( TRUE ); + pUndo->SetRemoveParaAttribs( bRemoveParaAttribs ); + pUndo->SetRemoveWhich( nWhich ); + InsertUndo( pUndo ); + } + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + ParaPortion* pPortion = GetParaPortions().GetObject( nNode ); + + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" ); + DBG_ASSERT( GetParaPortions().SaveGetObject( nNode ), "Portion nicht gefunden: SetAttribs" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // Optimieren: Wenn ganzer Absatz, dann RemoveCharAttribs( nPara )?! + BOOL bChanged = aEditDoc.RemoveAttribs( pNode, nStartPos, nEndPos, nWhich ); + if ( bRemoveParaAttribs ) + { + SetParaAttribs( nNode, *_pEmptyItemSet ); // Invalidiert + } + else + { + // Bei 'Format-Standard' sollen auch die Zeichenattribute verschwinden, + // die von der DrawingEngine als Absatzattribute eingestellt wurden. + // Diese koennen sowieso nicht vom Anwender eingestellt worden sein. + + // #106871# Not when nWhich + // Would have been better to offer a separate method for format/standard... + if ( !nWhich ) + { + SfxItemSet aAttribs( GetParaAttribs( nNode ) ); + for ( USHORT nW = EE_CHAR_START; nW <= EE_CHAR_END; nW++ ) + aAttribs.ClearItem( nW ); + SetParaAttribs( nNode, aAttribs ); + } + } + + if ( bChanged && !bRemoveParaAttribs ) + { + bFormatted = FALSE; + pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos ); + } + } +} + +typedef EditCharAttrib* EditCharAttribPtr; + +void ImpEditEngine::RemoveCharAttribs( USHORT nPara, USHORT nWhich, BOOL bRemoveFeatures ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara ); + + DBG_ASSERT( pNode, "Node nicht gefunden: RemoveCharAttribs" ); + DBG_ASSERT( pPortion, "Portion nicht gefunden: RemoveCharAttribs" ); + + if ( !pNode ) + return; + + USHORT nAttr = 0; + EditCharAttribPtr pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + if ( ( !pAttr->IsFeature() || bRemoveFeatures ) && + ( !nWhich || ( pAttr->GetItem()->Which() == nWhich ) ) ) + { + pNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + delete pAttr; + nAttr--; + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); +} + +void ImpEditEngine::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + + if ( !pNode ) + return; + +#ifdef EDITDEBUG +// FILE* fp = fopen( "d:\\debug.log", "a" ); +// if ( fp ) +// { +// fprintf( fp, "\n\n=> Absatz-Attribute: Absatz %i\n", nPara ); +// DbgOutItemSet( fp, rSet, TRUE, FALSE ); +// fclose( fp ); +// } +#endif + + if ( !( pNode->GetContentAttribs().GetItems() == rSet ) ) + { + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + if ( rSet.GetPool() != &aEditDoc.GetItemPool() ) + { + SfxItemSet aTmpSet( GetEmptyItemSet() ); + aTmpSet.Put( rSet ); + InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet ) ); + } + else + { + InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), rSet ) ); + } + } + pNode->GetContentAttribs().GetItems().Set( rSet ); + if ( aStatus.UseCharAttribs() ) + pNode->CreateDefFont(); + + ParaAttribsChanged( pNode ); + } +} + +const SfxItemSet& ImpEditEngine::GetParaAttribs( USHORT nPara ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttribs" ); + return pNode->GetContentAttribs().GetItems(); +} + +BOOL ImpEditEngine::HasParaAttrib( USHORT nPara, USHORT nWhich ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: HasParaAttrib" ); + + return pNode->GetContentAttribs().HasItem( nWhich ); +} + +const SfxPoolItem& ImpEditEngine::GetParaAttrib( USHORT nPara, USHORT nWhich ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttrib" ); + + return pNode->GetContentAttribs().GetItem( nWhich ); +} + +void ImpEditEngine::GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const +{ + rLst.Remove( 0, rLst.Count() ); + ContentNode* pNode = aEditDoc.GetObject( nPara ); + if ( pNode ) + { + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ]; + EECharAttrib aEEAttr; + aEEAttr.pAttr = pAttr->GetItem(); + aEEAttr.nPara = nPara; + aEEAttr.nStart = pAttr->GetStart(); + aEEAttr.nEnd = pAttr->GetEnd(); + rLst.Insert( aEEAttr, rLst.Count() ); + } + } +} + +void ImpEditEngine::ParaAttribsToCharAttribs( ContentNode* pNode ) +{ + pNode->GetCharAttribs().DeleteEmptyAttribs( GetEditDoc().GetItemPool() ); + xub_StrLen nEndPos = pNode->Len(); + for ( USHORT nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + if ( pNode->GetContentAttribs().HasItem( nWhich ) ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich ); + // Die Luecken auffuellen: + USHORT nLastEnd = 0; + EditCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ); + while ( pAttr ) + { + nLastEnd = pAttr->GetEnd(); + if ( pAttr->GetStart() > nLastEnd ) + aEditDoc.InsertAttrib( pNode, nLastEnd, pAttr->GetStart(), rItem ); + // #112831# Last Attr might go from 0xffff to 0x0000 + pAttr = nLastEnd ? pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ) : NULL; + } + + // Und den Rest: + if ( nLastEnd < nEndPos ) + aEditDoc.InsertAttrib( pNode, nLastEnd, nEndPos, rItem ); + } + } + bFormatted = FALSE; + // Portion braucht hier nicht invalidiert werden, geschieht woanders. +} + +IdleFormattter::IdleFormattter() +{ + pView = 0; + nRestarts = 0; +} + +IdleFormattter::~IdleFormattter() +{ + pView = 0; +} + +void IdleFormattter::DoIdleFormat( EditView* pV ) +{ + pView = pV; + + if ( IsActive() ) + nRestarts++; + + if ( nRestarts > 4 ) + ForceTimeout(); + else + Start(); +} + +void IdleFormattter::ForceTimeout() +{ + if ( IsActive() ) + { + Stop(); + ((Link&)GetTimeoutHdl()).Call( this ); + } +} + +ImplIMEInfos::ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos ) + : aOldTextAfterStartPos( rOldTextAfterStartPos ) +{ + aPos = rPos; + nLen = 0; + bCursor = TRUE; + pAttribs = NULL; + bWasCursorOverwrite = FALSE; +} + +ImplIMEInfos::~ImplIMEInfos() +{ + delete[] pAttribs; +} + +void ImplIMEInfos::CopyAttribs( const USHORT* pA, USHORT nL ) +{ + nLen = nL; + delete pAttribs; + pAttribs = new USHORT[ nL ]; + memcpy( pAttribs, pA, nL*sizeof(USHORT) ); +} + +void ImplIMEInfos::DestroyAttribs() +{ + delete[] pAttribs; + pAttribs = NULL; + nLen = 0; +} diff --git a/editeng/source/editeng/makefile.mk b/editeng/source/editeng/makefile.mk new file mode 100644 index 000000000000..4a8f8f254070 --- /dev/null +++ b/editeng/source/editeng/makefile.mk @@ -0,0 +1,80 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME=editeng +TARGET=editeng +AUTOSEG=true + +#PROJECTPCH4DLL=TRUE +#PROJECTPCH=eeng_pch +#PROJECTPCHSOURCE=eeng_pch + +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Allgemein ---------------------------------------------------------- + +.IF "$(editdebug)" != "" || "$(EDITDEBUG)" != "" +CDEFS+=-DEDITDEBUG +.ENDIF + +SLOFILES = \ + $(SLO)$/textconv.obj \ + $(SLO)$/editattr.obj \ + $(SLO)$/editdbg.obj \ + $(SLO)$/editdoc.obj \ + $(SLO)$/editdoc2.obj \ + $(SLO)$/editeng.obj \ + $(SLO)$/editobj.obj \ + $(SLO)$/editsel.obj \ + $(SLO)$/editundo.obj \ + $(SLO)$/editview.obj \ + $(SLO)$/edtspell.obj \ + $(SLO)$/eehtml.obj \ + $(SLO)$/eerdll.obj \ + $(SLO)$/eeobj.obj \ + $(SLO)$/eertfpar.obj \ + $(SLO)$/impedit.obj \ + $(SLO)$/impedit2.obj \ + $(SLO)$/impedit3.obj \ + $(SLO)$/impedit4.obj \ + $(SLO)$/impedit5.obj + +SRS1NAME=$(TARGET) +SRC1FILES= editeng.src + +EXCEPTIONSFILES= \ + $(SLO)$/unolingu.obj + +.INCLUDE : target.mk + diff --git a/editeng/source/editeng/textconv.cxx b/editeng/source/editeng/textconv.cxx new file mode 100644 index 000000000000..e46a40f09e02 --- /dev/null +++ b/editeng/source/editeng/textconv.cxx @@ -0,0 +1,629 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <editeng/langitem.hxx> +#include <editeng/fontitem.hxx> +#include <textconv.hxx> + + +using ::rtl::OUString; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::linguistic2; + +#define C2U(cChar) OUString::createFromAscii(cChar) + +////////////////////////////////////////////////////////////////////// + +TextConvWrapper::TextConvWrapper( Window* pWindow, + const Reference< XMultiServiceFactory >& rxMSF, + const Locale& rSourceLocale, + const Locale& rTargetLocale, + const Font* pTargetFont, + sal_Int32 nOptions, + sal_Bool bIsInteractive, + BOOL bIsStart, + EditView* pView ) : + HangulHanjaConversion( pWindow, rxMSF, rSourceLocale, rTargetLocale, pTargetFont, nOptions, bIsInteractive ) +{ + DBG_ASSERT( pWindow, "TextConvWrapper: window missing" ); + + nConvTextLang = LANGUAGE_NONE; + nUnitOffset = 0; + + bStartChk = sal_False; + bStartDone = bIsStart; + bEndDone = sal_False; + pWin = pWindow; + pEditView = pView; + + aConvSel = pEditView->GetSelection(); + aConvSel.Adjust(); // make Start <= End + + bAllowChange = sal_False; +} + + +TextConvWrapper::~TextConvWrapper() +{ +} + + +sal_Bool TextConvWrapper::ConvNext_impl() +{ + // modified version of SvxSpellWrapper::SpellNext + + if( bStartChk ) + bStartDone = sal_True; + else + bEndDone = sal_True; + + if ( bStartDone && bEndDone ) + { + if ( ConvMore_impl() ) // ein weiteres Dokument pruefen? + { + bStartDone = sal_True; + bEndDone = sal_False; + ConvStart_impl( SVX_SPELL_BODY ); + return sal_True; + } + return sal_False; + + } + + //ResMgr* pMgr = DIALOG_MGR(); + sal_Bool bGoOn = sal_False; + + if ( bStartDone && bEndDone ) + { + if ( ConvMore_impl() ) // ein weiteres Dokument pruefen? + { + bStartDone = sal_True; + bEndDone = sal_False; + ConvStart_impl( SVX_SPELL_BODY ); + return sal_True; + } + } + else + { + // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich +/* + pWin->LeaveWait(); + + sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE; + QueryBox aBox( pWin, ResId( nResId, pMgr ) ); + if ( aBox.Execute() != RET_YES ) + { + // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich + pWin->EnterWait(); + bStartDone = bEndDone = sal_True; + return ConvNext_impl(); + } + else + { +*/ + if (!aConvSel.HasRange()) + { + bStartChk = !bStartDone; + ConvStart_impl( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + bGoOn = sal_True; + } +/* + } + pWin->EnterWait(); +*/ + } + return bGoOn; +} + + +sal_Bool TextConvWrapper::FindConvText_impl() +{ + // modified version of SvxSpellWrapper::FindSpellError + + //ShowLanguageErrors(); + + sal_Bool bFound = sal_False; + + pWin->EnterWait(); + sal_Bool bConvert = sal_True; + + while ( bConvert ) + { + bFound = ConvContinue_impl(); + if (bFound) + { + bConvert = sal_False; + } + else + { + ConvEnd_impl(); + bConvert = ConvNext_impl(); + } + } + pWin->LeaveWait(); + return bFound; +} + + +sal_Bool TextConvWrapper::ConvMore_impl() +{ + // modified version of SvxSpellWrapper::SpellMore + + sal_Bool bMore = sal_False; + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + if ( pConvInfo->bMultipleDoc ) + { + bMore = pImpEE->GetEditEnginePtr()->ConvertNextDocument(); + if ( bMore ) + { + // Der Text wurde in diese Engine getreten... + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + return bMore; +} + + +void TextConvWrapper::ConvStart_impl( SvxSpellArea eArea ) +{ + // modified version of EditSpellWrapper::SpellStart + + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + + if ( eArea == SVX_SPELL_BODY_START ) + { + // Wird gerufen, wenn Spell-Forwad am Ende angekomment ist + // und soll von vorne beginnen + if ( bEndDone ) + { + pConvInfo->bConvToEnd = sal_False; + pConvInfo->aConvTo = pConvInfo->aConvStart; + pConvInfo->aConvContinue = EPaM( 0, 0 ); + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + else + { + pConvInfo->bConvToEnd = sal_True; + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY_END ) + { + // Wird gerufen, wenn Spell-Forwad gestartet wird + pConvInfo->bConvToEnd = sal_True; + if (aConvSel.HasRange()) + { + // user selection: convert to end of selection + pConvInfo->aConvTo.nPara = aConvSel.nEndPara; + pConvInfo->aConvTo.nIndex = aConvSel.nEndPos; + pConvInfo->bConvToEnd = sal_False; + } + else + { + // nothing selected: convert to end of document + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY ) + { + // called by ConvNext_impl... + pConvInfo->aConvContinue = pConvInfo->aConvStart; + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + // pSpellInfo->bSpellToEnd = sal_True; + } + else + { + DBG_ERROR( "ConvStart_impl: Unknown Area!" ); + } +} + + +void TextConvWrapper::ConvEnd_impl() +{ +} + + +sal_Bool TextConvWrapper::ConvContinue_impl() +{ + // modified version of EditSpellWrapper::SpellContinue + + // get next convertible text portion and its language + aConvText = rtl::OUString(); + nConvTextLang = LANGUAGE_NONE; + pEditView->GetImpEditEngine()->ImpConvert( aConvText, nConvTextLang, + pEditView, GetSourceLanguage(), aConvSel, + bAllowChange, GetTargetLanguage(), GetTargetFont() ); + return aConvText.getLength() != 0; +} + + +void TextConvWrapper::SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ) +{ + ESelection aOldSel = pEditView->GetSelection(); + pEditView->SetSelection( rESel ); + + // set new language attribute + SfxItemSet aNewSet( pEditView->GetEmptyItemSet() ); + aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); + + // new font to be set? + DBG_ASSERT( pFont, "target font missing?" ); + if (pFont) + { + // set new font attribute + SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); + aFontItem.GetFamilyName() = pFont->GetName(); + aFontItem.GetFamily() = pFont->GetFamily(); + aFontItem.GetStyleName() = pFont->GetStyleName(); + aFontItem.GetPitch() = pFont->GetPitch(); + aFontItem.GetCharSet() = pFont->GetCharSet(); + aNewSet.Put( aFontItem ); + } + + // apply new attributes + pEditView->SetAttribs( aNewSet ); + + pEditView->SetSelection( aOldSel ); +} + + +void TextConvWrapper::SelectNewUnit_impl( + const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ) +{ + BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd; + DBG_ASSERT( bOK, "invalid arguments" ); + if (!bOK) + return; + + ESelection aSelection = pEditView->GetSelection(); + DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara, + "paragraph mismatch in selection" ); + aSelection.nStartPos = (USHORT) (nLastPos + nUnitOffset + nUnitStart); + aSelection.nEndPos = (USHORT) (nLastPos + nUnitOffset + nUnitEnd); + pEditView->SetSelection( aSelection ); +} + + +void TextConvWrapper::GetNextPortion( + ::rtl::OUString& /* [out] */ rNextPortion, + LanguageType& /* [out] */ rLangOfPortion, + sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText ) +{ + bAllowChange = _bAllowImplicitChangesForNotConvertibleText; + + FindConvText_impl(); + rNextPortion = aConvText; + rLangOfPortion = nConvTextLang; + nUnitOffset = 0; + + ESelection aSelection = pEditView->GetSelection(); + DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara, + "paragraph mismatch in selection" ); + DBG_ASSERT( aSelection.nStartPos <= aSelection.nEndPos, + "start pos > end pos" ); + nLastPos = aSelection.nStartPos; +} + + +void TextConvWrapper::HandleNewUnit( + const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ) +{ + SelectNewUnit_impl( nUnitStart, nUnitEnd ); +} + + +void TextConvWrapper::ReplaceUnit( + const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd, + const ::rtl::OUString& rOrigText, + const ::rtl::OUString& rReplaceWith, + const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets, + ReplacementAction eAction, + LanguageType *pNewUnitLanguage ) +{ + BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd; + DBG_ASSERT( bOK, "invalid arguments" ); + if (!bOK) + return; + + static OUString aBracketedStart( C2U( "(" ) ); + static OUString aBracketedEnd( C2U( ")" ) ); + + // select current unit + SelectNewUnit_impl( nUnitStart, nUnitEnd ); + + OUString aOrigTxt( pEditView->GetSelected() ); + OUString aNewTxt( rReplaceWith ); + String aNewOrigText; + switch (eAction) + { + case eExchange : + break; + case eReplacementBracketed : + (((aNewTxt = aOrigTxt) += aBracketedStart) += rReplaceWith) += aBracketedEnd; + break; + case eOriginalBracketed : + (((aNewTxt = rReplaceWith) += aBracketedStart) += aOrigTxt) += aBracketedEnd; + break; + case eReplacementAbove : + case eOriginalAbove : + case eReplacementBelow : + case eOriginalBelow : + DBG_ERROR( "Rubies not supported" ); + break; + default: + DBG_ERROR( "unexpected case" ); + } + nUnitOffset = sal::static_int_cast< USHORT >( + nUnitOffset + nUnitStart + aNewTxt.getLength()); + + // remember current original language for kater use + ImpEditEngine *pImpEditEng = pEditView->GetImpEditEngine(); + ESelection _aOldSel = pEditView->GetSelection(); + //EditSelection aOldEditSel = pEditView->GetImpEditView()->GetEditSelection(); + +#ifdef DBG_UTIL + LanguageType nOldLang = pImpEditEng->GetLanguage( pImpEditEng->CreateSel( _aOldSel ).Min() ); +#endif + + pImpEditEng->UndoActionStart( EDITUNDO_INSERT ); + + // according to FT we should currently not bother about keeping + // attributes in Hangul/Hanja conversion and leave that untouched. + // Thus we do this only for Chinese translation... + sal_Bool bIsChineseConversion = IsChinese( GetSourceLanguage() ); + if (bIsChineseConversion) + ChangeText( aNewTxt, rOrigText, &rOffsets, &_aOldSel ); + else + ChangeText( aNewTxt, rOrigText, NULL, NULL ); + + // change language and font if necessary + if (bIsChineseConversion) + { + DBG_ASSERT( GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED || GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL, + "TextConvWrapper::ReplaceUnit : unexpected target language" ); + + ESelection aOldSel = pEditView->GetSelection(); + ESelection aNewSel( aOldSel ); + aNewSel.nStartPos = sal::static_int_cast< xub_StrLen >( + aNewSel.nStartPos - aNewTxt.getLength()); +// DBG_ASSERT( aOldSel.nEndPos >= 0, "error while building selection" ); + + if (pNewUnitLanguage) + { + DBG_ASSERT(!IsSimilarChinese( *pNewUnitLanguage, nOldLang ), + "similar language should not be changed!"); + SetLanguageAndFont( aNewSel, *pNewUnitLanguage, EE_CHAR_LANGUAGE_CJK, + GetTargetFont(), EE_CHAR_FONTINFO_CJK ); + } + } + + pImpEditEng->UndoActionEnd( EDITUNDO_INSERT ); + + // adjust ConvContinue / ConvTo if necessary + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + sal_Int32 nDelta = aNewTxt.getLength() - aOrigTxt.getLength(); + if (nDelta != 0) + { + // Note: replacement is always done in the current paragraph + // which is the one ConvContinue points to + pConvInfo->aConvContinue.nIndex = sal::static_int_cast< USHORT >( + pConvInfo->aConvContinue.nIndex + nDelta); + + // if that is the same as the one where the conversions ends + // the end needs to be updated also + if (pConvInfo->aConvTo.nPara == pConvInfo->aConvContinue.nPara) + pConvInfo->aConvTo.nIndex = sal::static_int_cast< USHORT >( + pConvInfo->aConvTo.nIndex + nDelta); + } +} + + +void TextConvWrapper::ChangeText( const String &rNewText, + const OUString& rOrigText, + const uno::Sequence< sal_Int32 > *pOffsets, + ESelection *pESelection ) +{ + //!! code is a modifed copy of SwHHCWrapper::ChangeText from sw !! + + DBG_ASSERT( rNewText.Len() != 0, "unexpected empty string" ); + if (rNewText.Len() == 0) + return; + + if (pOffsets && pESelection) // try to keep as much attributation as possible ? + { + pESelection->Adjust(); + + // remember cursor start position for later setting of the cursor + const xub_StrLen nStartIndex = pESelection->nStartPos; + + const sal_Int32 nIndices = pOffsets->getLength(); + const sal_Int32 *pIndices = pOffsets->getConstArray(); + xub_StrLen nConvTextLen = rNewText.Len(); + xub_StrLen nPos = 0; + xub_StrLen nChgPos = STRING_NOTFOUND; + xub_StrLen nChgLen = 0; + xub_StrLen nConvChgPos = STRING_NOTFOUND; + xub_StrLen nConvChgLen = 0; + + // offset to calculate the position in the text taking into + // account that text may have been replaced with new text of + // different length. Negative values allowed! + long nCorrectionOffset = 0; + + DBG_ASSERT(nIndices == 0 || nIndices == nConvTextLen, + "mismatch between string length and sequence length!" ); + + // find all substrings that need to be replaced (and only those) + while (sal_True) + { + // get index in original text that matches nPos in new text + xub_StrLen nIndex; + if (nPos < nConvTextLen) + nIndex = (sal_Int32) nPos < nIndices ? (xub_StrLen) pIndices[nPos] : nPos; + else + { + nPos = nConvTextLen; + nIndex = static_cast< xub_StrLen >( rOrigText.getLength() ); + } + + if (rOrigText.getStr()[nIndex] == rNewText.GetChar(nPos) || + nPos == nConvTextLen /* end of string also terminates non-matching char sequence */) + { + // substring that needs to be replaced found? + if (nChgPos != STRING_NOTFOUND && nConvChgPos != STRING_NOTFOUND) + { + nChgLen = nIndex - nChgPos; + nConvChgLen = nPos - nConvChgPos; +#ifdef DEBUG + String aInOrig( rOrigText.copy( nChgPos, nChgLen ) ); +#endif + String aInNew( rNewText.Copy( nConvChgPos, nConvChgLen ) ); + + // set selection to sub string to be replaced in original text + ESelection aSel( *pESelection ); + xub_StrLen nChgInNodeStartIndex = static_cast< xub_StrLen >( nStartIndex + nCorrectionOffset + nChgPos ); + aSel.nStartPos = nChgInNodeStartIndex; + aSel.nEndPos = nChgInNodeStartIndex + nChgLen; + pEditView->SetSelection( aSel ); +#ifdef DEBUG + String aSelTxt1( pEditView->GetSelected() ); +#endif + + // replace selected sub string with the corresponding + // sub string from the new text while keeping as + // much from the attributes as possible + ChangeText_impl( aInNew, sal_True ); + + nCorrectionOffset += nConvChgLen - nChgLen; + + nChgPos = STRING_NOTFOUND; + nConvChgPos = STRING_NOTFOUND; + } + } + else + { + // begin of non-matching char sequence found ? + if (nChgPos == STRING_NOTFOUND && nConvChgPos == STRING_NOTFOUND) + { + nChgPos = nIndex; + nConvChgPos = nPos; + } + } + if (nPos >= nConvTextLen) + break; + ++nPos; + } + + // set cursor to the end of the inserted text + // (as it would happen after ChangeText_impl (Delete and Insert) + // of the whole text in the 'else' branch below) + pESelection->nStartPos = pESelection->nEndPos = nStartIndex + nConvTextLen; + } + else + { + ChangeText_impl( rNewText, sal_False ); + } +} + + +void TextConvWrapper::ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes ) +{ + if (bKeepAttributes) + { + // save attributes to be restored + SfxItemSet aSet( pEditView->GetAttribs() ); + +#ifdef DEBUG + String aSelTxt1( pEditView->GetSelected() ); +#endif + // replace old text and select new text + pEditView->InsertText( rNewText, sal_True ); +#ifdef DEBUG + String aSelTxt2( pEditView->GetSelected() ); +#endif + + // since 'SetAttribs' below function like merging with the attributes + // from the itemset with any existing ones we have to get rid of all + // all attributes now. (Those attributes that may take effect left + // to the position where the new text gets inserted after the old text + // was deleted) + pEditView->RemoveAttribs(); + // apply saved attributes to new inserted text + pEditView->SetAttribs( aSet ); + } + else + { + pEditView->InsertText( rNewText ); + } +} + + +void TextConvWrapper::Convert() +{ + bStartChk = sal_False; + ConvStart_impl( SVX_SPELL_BODY_END ); + ConvertDocument(); + ConvEnd_impl(); +} + + +sal_Bool TextConvWrapper::HasRubySupport() const +{ + return sal_False; +} + +////////////////////////////////////////////////////////////////////// + diff --git a/editeng/source/editeng/textconv.hxx b/editeng/source/editeng/textconv.hxx new file mode 100644 index 000000000000..8ffc00291fe9 --- /dev/null +++ b/editeng/source/editeng/textconv.hxx @@ -0,0 +1,122 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _TEXTCONV_HXX +#define _TEXTCONV_HXX + +#include <editeng/splwrap.hxx> +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.hxx> +#include <editeng/hangulhanja.hxx> + +class EditView; +class ImpEditEngine; +class ContentNode; + +class TextConvWrapper : public editeng::HangulHanjaConversion +{ + rtl::OUString aConvText; // convertible text part found last time + LanguageType nConvTextLang; // language of aConvText + USHORT nLastPos; // starting position of the last found text portion (word) + USHORT nUnitOffset; // offset of current unit in the current text portion (word) + + ESelection aConvSel; // selection to be converted if + // 'HasRange' is true, other conversion + // starts from the cursor position + + EditView * pEditView; + Window * pWin; + + sal_Bool bStartChk; + sal_Bool bStartDone; + sal_Bool bEndDone; + sal_Bool bAllowChange; // storage for _bAllowImplicitChangesForNotConvertibleText + // paramters value of function GetNextPortion. + // used to transport the value to where it is needed. + + + // from SvxSpellWrapper copied and modified + sal_Bool ConvNext_impl(); // former SpellNext + sal_Bool FindConvText_impl(); // former FindSpellError + sal_Bool ConvMore_impl(); // former SpellMore + + // from EditSpellWrapper copied and modified + void ConvStart_impl( SvxSpellArea eSpell ); // former SpellStart + void ConvEnd_impl(); // former SpellEnd + sal_Bool ConvContinue_impl(); // former SpellContinue + + void SelectNewUnit_impl( const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ); + + void ChangeText( const String &rNewText, + const ::rtl::OUString& rOrigText, + const ::com::sun::star::uno::Sequence< sal_Int32 > *pOffsets, + ESelection *pESelection ); + void ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes ); + + // Forbidden and not implemented. + TextConvWrapper (const TextConvWrapper &); + TextConvWrapper & operator= (const TextConvWrapper &); + +protected: + virtual void GetNextPortion( ::rtl::OUString& /* [out] */ rNextPortion, + LanguageType& /* [out] */ rLangOfPortion, + sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText ); + virtual void HandleNewUnit( const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ); + virtual void ReplaceUnit( + const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd, + const ::rtl::OUString& rOrigText, + const ::rtl::OUString& rReplaceWith, + const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets, + ReplacementAction eAction, + LanguageType *pNewUnitLanguage ); + + virtual sal_Bool HasRubySupport() const; + + void SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ); + + +public: + TextConvWrapper( Window* pWindow, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxMSF, + const ::com::sun::star::lang::Locale& rSourceLocale, + const ::com::sun::star::lang::Locale& rTargetLocale, + const Font* pTargetFont, + INT32 nOptions, + sal_Bool bIsInteractive, + BOOL bIsStart, EditView* pView ); + + virtual ~TextConvWrapper(); + + void Convert(); +}; + +#endif + |