/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * 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 "svditext.hxx"
#include "svdview.hxx"  // Objekt gerade editiert wird
#include "svdtouch.hxx"
#include "svdio.hxx"
#include "svdetc.hxx"
#include "svdoutl.hxx"
#include "svdstr.hrc"   // Objektname
#include "svdtxhdl.hxx"  // DrawTextToPath
#include "writingmodeitem.hxx"

#include <editstat.hxx>
#include <outlobj.hxx>
#include <editobj.hxx>

#include "fhgtitem.hxx"

#include <bf_svtools/itempool.hxx>

#include "adjitem.hxx"
#include "itemdata.hxx"
#include "flditem.hxx"

#include <vcl/salbtype.hxx>     // FRound

#include "xflgrit.hxx"
#include "xoutx.hxx"

#include <bf_goodies/matrix3d.hxx>

namespace binfilter {

// #104018# replace macros above with type-safe methods
inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TEXTOBJ
//
////////////////////////////////////////////////////////////////////////////////////////////////////

/*N*/ TYPEINIT1(SdrTextObj,SdrAttrObj);

/*N*/ SdrTextObj::SdrTextObj():
/*N*/   pOutlinerParaObject(NULL),
/*N*/   pFormTextBoundRect(NULL),
/*N*/   eTextKind(OBJ_TEXT)
/*N*/ {
/*N*/   bTextSizeDirty=FALSE;
/*N*/   bPortionInfoChecked=FALSE;
/*N*/   bTextFrame=FALSE;
/*N*/   bNoShear=FALSE;
/*N*/   bNoMirror=FALSE;
/*N*/ }

/*N*/ SdrTextObj::SdrTextObj(const Rectangle& rNewRect):
/*N*/   aRect(rNewRect),
/*N*/   pOutlinerParaObject(NULL),
/*N*/   pFormTextBoundRect(NULL),
/*N*/   eTextKind(OBJ_TEXT)
/*N*/ {
/*N*/   bTextSizeDirty=FALSE;
/*N*/   bPortionInfoChecked=FALSE;
/*N*/   bTextFrame=FALSE;
/*N*/   bNoShear=FALSE;
/*N*/   bNoMirror=FALSE;
/*N*/   ImpJustifyRect(aRect);
/*N*/ }

/*N*/ SdrTextObj::SdrTextObj(SdrObjKind eNewTextKind):
/*N*/   pOutlinerParaObject(NULL),
/*N*/   pFormTextBoundRect(NULL),
/*N*/   eTextKind(eNewTextKind)
/*N*/ {
/*N*/   bTextSizeDirty=FALSE;
/*N*/   bTextFrame=TRUE;
/*N*/   bNoShear=TRUE;
/*N*/   bNoMirror=TRUE;
/*N*/   bPortionInfoChecked=FALSE;
/*N*/ }

/*N*/ SdrTextObj::SdrTextObj(SdrObjKind eNewTextKind, const Rectangle& rNewRect):
/*N*/   aRect(rNewRect),
/*N*/   pOutlinerParaObject(NULL),
/*N*/   pFormTextBoundRect(NULL),
/*N*/   eTextKind(eNewTextKind)
/*N*/ {
/*N*/   bTextSizeDirty=FALSE;
/*N*/   bTextFrame=TRUE;
/*N*/   bNoShear=TRUE;
/*N*/   bNoMirror=TRUE;
/*N*/   bPortionInfoChecked=FALSE;
/*N*/   ImpJustifyRect(aRect);
/*N*/ }

/*N*/ SdrTextObj::~SdrTextObj()
/*N*/ {
/*N*/   if( pModel )
/*N*/   {
/*N*/       SdrOutliner& rOutl = pModel->GetHitTestOutliner();
/*N*/       if( rOutl.GetTextObj() == this )
/*N*/           rOutl.SetTextObj( NULL );
/*N*/   }
/*N*/
/*N*/   if (pOutlinerParaObject!=NULL) {
/*N*/       delete pOutlinerParaObject;
/*N*/   }
/*N*/   if (pFormTextBoundRect!=NULL) {
/*N*/       delete pFormTextBoundRect;
/*N*/   }
/*N*/   ImpLinkAbmeldung();
/*N*/ }

/*N*/ const Size& SdrTextObj::GetTextSize() const
/*N*/ {
/*N*/   if (bTextSizeDirty) {
/*N*/       Size aSiz;
/*N*/       if (pOutlinerParaObject!=NULL) {
/*N*/           SdrOutliner& rOutliner=ImpGetDrawOutliner();
/*N*/           rOutliner.SetText(*pOutlinerParaObject);
/*N*/           rOutliner.SetUpdateMode(TRUE);
/*N*/           aSiz=rOutliner.CalcTextSize();
/*N*/           rOutliner.Clear();
/*N*/       }
/*N*/       // 2x casting auf nonconst
/*N*/       ((SdrTextObj*)this)->aTextSize=aSiz;
/*N*/       ((SdrTextObj*)this)->bTextSizeDirty=FALSE;
/*N*/   }
/*N*/   return aTextSize;
/*N*/ }

/*N*/ bool SdrTextObj::IsAutoGrowHeight() const
/*N*/ {
/*N*/   if(!bTextFrame)
/*N*/       return FALSE; // AutoGrow nur bei TextFrames
/*N*/
/*N*/   const SfxItemSet& rSet = GetItemSet();
/*N*/   BOOL bRet = ((SdrTextAutoGrowHeightItem&)(rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT))).GetValue();
/*N*/
/*N*/   if(bRet)
/*N*/   {
/*N*/       SdrTextAniKind eAniKind = ((SdrTextAniKindItem&)(rSet.Get(SDRATTR_TEXT_ANIKIND))).GetValue();
/*N*/
/*N*/       if(eAniKind == SDRTEXTANI_SCROLL || eAniKind == SDRTEXTANI_ALTERNATE || eAniKind == SDRTEXTANI_SLIDE)
/*N*/       {
/*N*/           SdrTextAniDirection eDirection = ((SdrTextAniDirectionItem&)(rSet.Get(SDRATTR_TEXT_ANIDIRECTION))).GetValue();
/*N*/
/*N*/           if(eDirection == SDRTEXTANI_UP || eDirection == SDRTEXTANI_DOWN)
/*N*/           {
/*N*/               bRet = FALSE;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   return bRet;
/*N*/ }

/*N*/ bool SdrTextObj::IsAutoGrowWidth() const
/*N*/ {
/*N*/   if(!bTextFrame)
/*N*/       return FALSE; // AutoGrow nur bei TextFrames
/*N*/
/*N*/   const SfxItemSet& rSet = GetItemSet();
/*N*/   BOOL bRet = ((SdrTextAutoGrowHeightItem&)(rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH))).GetValue();
/*N*/
/*N*/   if(bRet)
/*N*/   {
/*N*/       SdrTextAniKind eAniKind = ((SdrTextAniKindItem&)(rSet.Get(SDRATTR_TEXT_ANIKIND))).GetValue();
/*N*/
/*N*/       if(eAniKind == SDRTEXTANI_SCROLL || eAniKind == SDRTEXTANI_ALTERNATE || eAniKind == SDRTEXTANI_SLIDE)
/*N*/       {
/*?*/           SdrTextAniDirection eDirection = ((SdrTextAniDirectionItem&)(rSet.Get(SDRATTR_TEXT_ANIDIRECTION))).GetValue();
/*?*/
/*?*/           if(eDirection == SDRTEXTANI_LEFT || eDirection == SDRTEXTANI_RIGHT)
/*?*/           {
/*?*/               bRet = FALSE;
/*?*/           }
/*N*/       }
/*N*/   }
/*N*/   return bRet;
/*N*/ }

/*N*/ SdrTextHorzAdjust SdrTextObj::GetTextHorizontalAdjust() const
/*N*/ {
/*N*/   if(IsContourTextFrame())
/*?*/       return SDRTEXTHORZADJUST_BLOCK;
/*N*/
/*N*/   const SfxItemSet& rSet = GetItemSet();
/*N*/   SdrTextHorzAdjust eRet = ((SdrTextHorzAdjustItem&)(rSet.Get(SDRATTR_TEXT_HORZADJUST))).GetValue();
/*N*/
/*N*/   if(eRet == SDRTEXTHORZADJUST_BLOCK)
/*N*/   {
/*N*/       SdrTextAniKind eAniKind = ((SdrTextAniKindItem&)(rSet.Get(SDRATTR_TEXT_ANIKIND))).GetValue();
/*N*/
/*N*/       if(eAniKind == SDRTEXTANI_SCROLL || eAniKind == SDRTEXTANI_ALTERNATE || eAniKind == SDRTEXTANI_SLIDE)
/*N*/       {
/*?*/           SdrTextAniDirection eDirection = ((SdrTextAniDirectionItem&)(rSet.Get(SDRATTR_TEXT_ANIDIRECTION))).GetValue();
/*?*/
/*?*/           if(eDirection == SDRTEXTANI_LEFT || eDirection == SDRTEXTANI_RIGHT)
/*?*/           {
/*?*/               eRet = SDRTEXTHORZADJUST_LEFT;
/*?*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   return eRet;
/*N*/ } // defaults: BLOCK fuer Textrahmen, CENTER fuer beschriftete Grafikobjekte

/*N*/ SdrTextVertAdjust SdrTextObj::GetTextVerticalAdjust() const
/*N*/ {
/*N*/   if(IsContourTextFrame())
/*?*/       return SDRTEXTVERTADJUST_TOP;
/*N*/
/*N*/   // #103516# Take care for vertical text animation here
/*N*/   const SfxItemSet& rSet = GetItemSet();
/*N*/   SdrTextVertAdjust eRet = ((SdrTextVertAdjustItem&)(rSet.Get(SDRATTR_TEXT_VERTADJUST))).GetValue();
/*N*/
/*N*/   // #103516# Take care for vertical text animation here
/*N*/   if(eRet == SDRTEXTVERTADJUST_BLOCK)
/*N*/   {
/*N*/       SdrTextAniKind eAniKind = ((SdrTextAniKindItem&)(rSet.Get(SDRATTR_TEXT_ANIKIND))).GetValue();
/*N*/
/*N*/       if(eAniKind == SDRTEXTANI_SCROLL || eAniKind == SDRTEXTANI_ALTERNATE || eAniKind == SDRTEXTANI_SLIDE)
/*N*/       {
/*N*/           SdrTextAniDirection eDirection = ((SdrTextAniDirectionItem&)(rSet.Get(SDRATTR_TEXT_ANIDIRECTION))).GetValue();
/*N*/
/*N*/           if(eDirection == SDRTEXTANI_LEFT || eDirection == SDRTEXTANI_RIGHT)
/*N*/           {
/*N*/               eRet = SDRTEXTVERTADJUST_TOP;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   return eRet;
/*N*/ } // defaults: TOP fuer Textrahmen, CENTER fuer beschriftete Grafikobjekte

/*N*/ void SdrTextObj::ImpJustifyRect(Rectangle& rRect) const
/*N*/ {
/*N*/   if (!rRect.IsEmpty()) {
/*N*/       rRect.Justify();
/*N*/       if (rRect.Left()==rRect.Right()) rRect.Right()++;
/*N*/       if (rRect.Top()==rRect.Bottom()) rRect.Bottom()++;
/*N*/   }
/*N*/ }

/*N*/ void SdrTextObj::ImpCheckShear()
/*N*/ {
/*N*/   if (bNoShear && aGeo.nShearWink!=0) {
/*N*/       aGeo.nShearWink=0;
/*N*/       aGeo.nTan=0;
/*N*/   }
/*N*/ }


/*N*/ void SdrTextObj::SetPage(SdrPage* pNewPage)
/*N*/ {
/*N*/   bool bRemove=pNewPage==NULL && pPage!=NULL;
/*N*/   bool bInsert=pNewPage!=NULL && pPage==NULL;
/*N*/   bool bLinked=IsLinkedText();
/*N*/
/*N*/   if (bLinked && bRemove) {
/*?*/       ImpLinkAbmeldung();
/*N*/   }
/*N*/
/*N*/   SdrAttrObj::SetPage(pNewPage);
/*N*/
/*N*/   if (bLinked && bInsert) {
/*?*/       ImpLinkAnmeldung();
/*N*/   }
/*N*/ }

/*N*/ void SdrTextObj::SetModel(SdrModel* pNewModel)
/*N*/ {
/*N*/   const SfxItemSet& rSet = GetItemSet();
/*N*/   SdrModel* pOldModel=pModel;
/*N*/   BOOL bLinked=IsLinkedText();
/*N*/   BOOL bChg=pNewModel!=pModel;
/*N*/   BOOL bHgtSet = rSet.GetItemState(EE_CHAR_FONTHEIGHT, TRUE) == SFX_ITEM_SET;
/*N*/   if (bLinked && bChg) {
/*?*/       ImpLinkAbmeldung();
/*N*/   }
/*N*/
/*N*/   SdrAttrObj::SetModel(pNewModel);
/*N*/
/*N*/   if (bChg && pOutlinerParaObject!=NULL && pOldModel!=NULL && pNewModel!=NULL) {
/*?*/       SetTextSizeDirty();
/*?*/       // und nun dem OutlinerParaObject einen neuen Pool verpassen
/*?*/       // !!! Hier muss noch DefTab und RefDevice der beiden Models
/*?*/       // !!! verglichen werden und dann ggf. AutoGrow zuschlagen !!!
/*?*/       // !!! fehlende Implementation !!!
/*?*/       ULONG nOldFontHgt=pOldModel->GetDefaultFontHeight();
/*?*/       ULONG nNewFontHgt=pNewModel->GetDefaultFontHeight();
/*?*/       BOOL bDefHgtChanged=nNewFontHgt!=nOldFontHgt;
/*?*/       BOOL bSetHgtItem=bDefHgtChanged && !bHgtSet;
/*?*/       if (bSetHgtItem) { // #32665#
/*?*/           // zunaechst das HeightItem festklopfen, damit
/*?*/           // 1. Es eben bestehen bleibt und
/*?*/           // 2. DoStretchChars vom richtigen Wert ausgeht
/*?*/           SetItem(SvxFontHeightItem(nOldFontHgt));
/*?*/       }
/*?*/       // erst jetzt den Outliner holen, etc. damit obiges SetAttr auch wirkt
/*?*/       SdrOutliner& rOutliner=ImpGetDrawOutliner();
/*?*/       rOutliner.SetText(*pOutlinerParaObject);
/*?*/       delete pOutlinerParaObject;
/*?*/       pOutlinerParaObject=NULL;
/*?*/       SetOutlinerParaObject(rOutliner.CreateParaObject()); // #34494#
/*?*/       pOutlinerParaObject->ClearPortionInfo();
/*?*/       bPortionInfoChecked=FALSE;
/*?*/       rOutliner.Clear();
/*?*/       //ImpSetTextStyleSheetListeners();
/*N*/   }

/*N*/   if (bLinked && bChg) {
/*?*/       ImpLinkAnmeldung();
/*N*/   }
/*N*/ }

/*N*/ bool SdrTextObj::NbcSetEckenradius(long nRad)
/*N*/ {
/*N*/   SetItem(SdrEckenradiusItem(nRad));
/*N*/   return TRUE;
/*N*/ }

/*N*/ bool SdrTextObj::NbcSetAutoGrowHeight(bool bAuto)
/*N*/ {
/*N*/   if(bTextFrame)
/*N*/   {
/*N*/       SetItem(SdrTextAutoGrowHeightItem(bAuto));
/*N*/       return TRUE;
/*N*/   }
/*N*/   return FALSE;
/*N*/ }

/*N*/ bool SdrTextObj::NbcSetMinTextFrameHeight(long nHgt)
/*N*/ {
/*N*/   if(bTextFrame)
/*N*/   {
/*N*/       SetItem(SdrTextMinFrameHeightItem(nHgt));
/*N*/       return TRUE;
/*N*/   }
/*?*/   return FALSE;
/*N*/ }



/*N*/ bool SdrTextObj::NbcSetMinTextFrameWidth(long nWdt)
/*N*/ {
/*N*/   if(bTextFrame)
/*N*/   {
/*N*/       SetItem(SdrTextMinFrameWidthItem(nWdt));
/*N*/       return TRUE;
/*N*/   }
/*N*/   return FALSE;
/*N*/ }




/*N*/ void SdrTextObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
/*N*/ {
/*N*/   rRect=aRect;
/*N*/ }

/*N*/ void SdrTextObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const
/*N*/ {
/*N*/   long nLeftDist=GetTextLeftDistance();
/*N*/   long nRightDist=GetTextRightDistance();
/*N*/   long nUpperDist=GetTextUpperDistance();
/*N*/   long nLowerDist=GetTextLowerDistance();
/*N*/   Rectangle aAnkRect(aRect); // Rect innerhalb dem geankert wird
/*N*/   bool bFrame=IsTextFrame();
/*N*/   if (!bFrame) {
/*N*/       TakeUnrotatedSnapRect(aAnkRect);
/*N*/   }
/*N*/   Point aRotateRef(aAnkRect.TopLeft());
/*N*/   aAnkRect.Left()+=nLeftDist;
/*N*/   aAnkRect.Top()+=nUpperDist;
/*N*/   aAnkRect.Right()-=nRightDist;
/*N*/   aAnkRect.Bottom()-=nLowerDist;
/*N*/
/*N*/   // #108816#
/*N*/   // Since sizes may be bigger than the object bounds it is necessary to
/*N*/   // justify the rect now.
/*N*/   ImpJustifyRect(aAnkRect);
/*N*/
/*N*/   if (bFrame) {
/*N*/       // !!! hier noch etwas verfeinern !!!
/*N*/       if (aAnkRect.GetWidth()<2) aAnkRect.Right()=aAnkRect.Left()+1;   // Mindestgroesse 2
/*N*/       if (aAnkRect.GetHeight()<2) aAnkRect.Bottom()=aAnkRect.Top()+1;  // Mindestgroesse 2
/*N*/   }
/*N*/   if (aGeo.nDrehWink!=0) {
/*N*/       Point aTmpPt(aAnkRect.TopLeft());
/*N*/       RotatePoint(aTmpPt,aRotateRef,aGeo.nSin,aGeo.nCos);
/*N*/       aTmpPt-=aAnkRect.TopLeft();
/*N*/       aAnkRect.Move(aTmpPt.X(),aTmpPt.Y());
/*N*/   }
/*N*/   rAnchorRect=aAnkRect;
/*N*/ }

/*N*/ void SdrTextObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect,
/*N*/                              Rectangle* pAnchorRect ) const
/*N*/ {
/*N*/   Rectangle aAnkRect; // Rect innerhalb dem geankert wird
/*N*/   TakeTextAnchorRect(aAnkRect);
/*N*/   SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
/*N*/   SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
/*N*/   SdrTextAniKind      eAniKind=GetTextAniKind();
/*N*/   SdrTextAniDirection eAniDirection=GetTextAniDirection();
/*N*/
/*N*/   SdrFitToSizeType eFit=GetFitToSize();
/*N*/   bool bFitToSize=(eFit==SDRTEXTFIT_PROPORTIONAL || eFit==SDRTEXTFIT_ALLLINES);
/*N*/   bool bContourFrame=IsContourTextFrame();
/*N*/
/*N*/   bool bFrame=IsTextFrame();
/*N*/   ULONG nStat0=rOutliner.GetControlWord();
/*N*/   Size aNullSize;
/*N*/   if (!bContourFrame)
/*N*/   {
/*N*/       rOutliner.SetControlWord(nStat0|EE_CNTRL_AUTOPAGESIZE);
/*N*/       rOutliner.SetMinAutoPaperSize(aNullSize);
/*N*/       rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
/*N*/   }
/*N*/
/*N*/   if (!bFitToSize && !bContourFrame)
/*N*/   {
/*N*/       long nAnkWdt=aAnkRect.GetWidth();
/*N*/       long nAnkHgt=aAnkRect.GetHeight();
/*N*/       if (bFrame)
/*N*/       {
/*N*/           long nWdt=nAnkWdt;
/*N*/           long nHgt=nAnkHgt;
/*N*/
/*N*/           if ( eAniKind==SDRTEXTANI_SCROLL || eAniKind==SDRTEXTANI_ALTERNATE || eAniKind==SDRTEXTANI_SLIDE )
/*N*/           {
/*?*/               // Grenzenlose Papiergroesse fuer Laufschrift
/*?*/               if (eAniDirection==SDRTEXTANI_LEFT || eAniDirection==SDRTEXTANI_RIGHT) nWdt=1000000;
/*?*/               if (eAniDirection==SDRTEXTANI_UP || eAniDirection==SDRTEXTANI_DOWN) nHgt=1000000;
/*N*/           }
/*N*/           rOutliner.SetMaxAutoPaperSize(Size(nWdt,nHgt));
/*N*/       }
/*N*/
/*N*/       // #103516# New try with _BLOCK for hor and ver after completely
/*N*/       // supporting full width for vertical text.
/*N*/       if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
/*N*/       {
/*N*/           rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
/*N*/       }
/*N*/
/*N*/       if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
/*N*/       {
/*N*/           rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
/*N*/       }
/*N*/   }
/*N*/
/*N*/   rOutliner.SetPaperSize(aNullSize);
/*N*/
/*N*/   // Text in den Outliner stecken - ggf. den aus dem EditOutliner
/*N*/   OutlinerParaObject* pPara=pOutlinerParaObject;
/*N*/   if (pPara)
/*N*/   {
/*N*/       BOOL bHitTest = FALSE;
/*N*/       if( pModel )
/*N*/           bHitTest = &pModel->GetHitTestOutliner() == &rOutliner;
/*N*/
/*N*/       const SdrTextObj* pTestObj = rOutliner.GetTextObj();
/*N*/       if( !pTestObj || !bHitTest || pTestObj != this ||
/*N*/           pTestObj->GetOutlinerParaObject() != pOutlinerParaObject )
/*N*/       {
/*N*/           if( bHitTest )
/*N*/               rOutliner.SetTextObj( this );
/*N*/
/*N*/           rOutliner.SetUpdateMode(TRUE);
/*N*/           rOutliner.SetText(*pPara);
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       rOutliner.SetTextObj( NULL );
/*N*/   }
/*N*/
/*N*/   rOutliner.SetUpdateMode(TRUE);
/*N*/   rOutliner.SetControlWord(nStat0);
/*N*/
/*N*/   if (!bPortionInfoChecked)
/*N*/   {
/*N*/       // Optimierung: ggf. BigTextObject erzeugen
/*N*/       ((SdrTextObj*)this)->bPortionInfoChecked=TRUE;
/*N*/       if (pOutlinerParaObject!=NULL && rOutliner.ShouldCreateBigTextObject())
/*?*/           ((SdrTextObj*)this)->pOutlinerParaObject=rOutliner.CreateParaObject();
/*N*/   }
/*N*/
/*N*/   Point aTextPos(aAnkRect.TopLeft());
/*N*/   Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() hat etwas Toleranz drauf, oder?
/*N*/
/*N*/   // #106653#
/*N*/   // For draw objects containing text correct hor/ver alignment if text is bigger
/*N*/   // than the object itself. Without that correction, the text would always be
/*N*/   // formatted to the left edge (or top edge when vertical) of the draw object.
/*N*/   if(!IsTextFrame())
/*N*/   {
/*N*/       if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting())
/*N*/       {
/*N*/           // #110129#
/*N*/           // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
/*N*/           // else the alignment is wanted.
/*N*/           if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
/*N*/           {
/*N*/               eHAdj = SDRTEXTHORZADJUST_CENTER;
/*N*/           }
/*N*/       }
/*N*/
/*N*/       if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting())
/*N*/       {
/*N*/           // #110129#
/*N*/           // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
/*N*/           // else the alignment is wanted.
/*N*/           if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
/*N*/           {
/*N*/               eVAdj = SDRTEXTVERTADJUST_CENTER;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT)
/*N*/   {
/*N*/       long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width();
/*N*/       if (eHAdj==SDRTEXTHORZADJUST_CENTER)
/*N*/           aTextPos.X()+=nFreeWdt/2;
/*N*/       if (eHAdj==SDRTEXTHORZADJUST_RIGHT)
/*N*/           aTextPos.X()+=nFreeWdt;
/*N*/   }
/*N*/   if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
/*N*/   {
/*N*/       long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
/*N*/       if (eVAdj==SDRTEXTVERTADJUST_CENTER)
/*N*/           aTextPos.Y()+=nFreeHgt/2;
/*N*/       if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
/*N*/           aTextPos.Y()+=nFreeHgt;
/*N*/   }
/*N*/   if (aGeo.nDrehWink!=0)
/*N*/       RotatePoint(aTextPos,aAnkRect.TopLeft(),aGeo.nSin,aGeo.nCos);
/*N*/
/*N*/   if (pAnchorRect)
/*N*/       *pAnchorRect=aAnkRect;
/*N*/
/*N*/   // rTextRect ist bei ContourFrame in einigen Faellen nicht korrekt
/*N*/   rTextRect=Rectangle(aTextPos,aTextSiz);
/*N*/   if (bContourFrame)
/*?*/       rTextRect=aAnkRect;
/*N*/ }

// Geht z.Zt. nur wenn das Obj schon wenigstens einmal gepaintet wurde
// Denn dann ist der MtfAnimator initiallisiert

/*N*/ void SdrTextObj::ImpAddTextToBoundRect()
/*N*/ {
/*N*/   if (pOutlinerParaObject!=NULL) {
/*N*/       if (IsContourTextFrame()) return;
/*N*/       if (IsFontwork()) {
/*N*/           if (pModel!=NULL) {
/*N*/               VirtualDevice aVD;
/*N*/               ExtOutputDevice aXOut(&aVD);
/*N*/               SdrOutliner& rOutl=ImpGetDrawOutliner();
/*N*/               rOutl.SetUpdateMode(TRUE);
/*N*/               ImpTextPortionHandler aTPHandler(rOutl,*this);
/*N*/
/*N*/               aXOut.SetTextAttr(GetItemSet());
/*N*/
/*N*/               aTPHandler.DrawTextToPath(aXOut,FALSE);
/*N*/               if (pFormTextBoundRect==NULL) pFormTextBoundRect=new Rectangle;
/*N*/               *pFormTextBoundRect=aTPHandler.GetFormTextBoundRect();
/*N*/               aOutRect.Union(*pFormTextBoundRect);
/*N*/           }
/*N*/       } else { // Ansonsten Text im Zeichenobjekt zentriert
/*N*/           if (pFormTextBoundRect!=NULL) {
/*?*/               delete pFormTextBoundRect;
/*?*/               pFormTextBoundRect=NULL;
/*N*/           }
/*N*/           bool bCheckText=TRUE;
/*N*/           if (bTextFrame) {
/*N*/               bCheckText=GetTextLeftDistance ()<0 ||
/*N*/                          GetTextRightDistance()<0 ||
/*N*/                          GetTextUpperDistance()<0 ||
/*N*/                          GetTextLowerDistance()<0 ||
/*N*/                          (GetEckenradius()>0 && aGeo.nDrehWink!=0);
/*N*/           }
/*N*/           if (bCheckText) {
/*N*/               SdrOutliner& rOutliner=ImpGetDrawOutliner();
/*N*/               Rectangle aTextRect;
/*N*/               Rectangle aAnchorRect;
/*N*/               TakeTextRect(rOutliner,aTextRect,&aAnchorRect); // EditText ignorieren!
/*N*/               SdrFitToSizeType eFit=GetFitToSize();
/*N*/               bool bFitToSize=(eFit==SDRTEXTFIT_PROPORTIONAL || eFit==SDRTEXTFIT_ALLLINES);
/*N*/               if (bFitToSize) aTextRect=aAnchorRect;
/*N*/               rOutliner.Clear();
/*N*/               if (aGeo.nDrehWink!=0) {
/*N*/                   Polygon aPol(aTextRect);
/*N*/                   if (aGeo.nDrehWink!=0) RotatePoly(aPol,aTextRect.TopLeft(),aGeo.nSin,aGeo.nCos);
/*N*/                   aOutRect.Union(aPol.GetBoundRect());
/*N*/               } else {
/*N*/                   aOutRect.Union(aTextRect);
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ SdrObject* SdrTextObj::CheckHit(const Point& rPnt, USHORT nTol, const SetOfByte* pVisiLayer) const
/*N*/ {
/*N*/   if (!bTextFrame && pOutlinerParaObject==NULL) return NULL;
/*N*/   if (pVisiLayer!=NULL && !pVisiLayer->IsSet(nLayerId)) return NULL;
/*N*/   INT32 nMyTol=nTol;
/*N*/   bool bFontwork=IsFontwork();
/*N*/   SdrFitToSizeType eFit=GetFitToSize();
/*N*/   bool bFitToSize=(eFit==SDRTEXTFIT_PROPORTIONAL || eFit==SDRTEXTFIT_ALLLINES);
/*N*/   Rectangle aR(aRect);
/*N*/   Rectangle aLclAnchor(aR);
/*N*/   Rectangle aTextRect(aR);
/*N*/   SdrOutliner* pOutliner = NULL;
/*N*/   pOutliner = &pModel->GetHitTestOutliner();
/*N*/
/*N*/   if (bFontwork) {
/*?*/       if (pFormTextBoundRect!=NULL) aR=*pFormTextBoundRect;
/*?*/       else aR=GetBoundRect();
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       TakeTextRect( *pOutliner, aTextRect, &aLclAnchor ); // EditText nicht mehr ignorieren! TRUE); // EditText ignorieren!
/*N*/
/*N*/       if (bFitToSize)
/*?*/           aR=aLclAnchor;
/*N*/       else
/*N*/           aR=aTextRect;
/*N*/   }
/*N*/   if (aR.GetWidth()-1>short(nTol) && aR.GetHeight()-1>short(nTol)) nMyTol=0; // Keine Toleranz noetig hier
/*N*/   if (nMyTol!=0) {
/*?*/       aR.Left  ()-=nMyTol;
/*?*/       aR.Top   ()-=nMyTol;
/*?*/       aR.Right ()+=nMyTol;
/*?*/       aR.Bottom()+=nMyTol;
/*N*/   }
/*N*/   bool bRet=FALSE;
/*N*/
/*N*/   if(bFontwork)
/*N*/   {
/*N*/       bRet = aR.IsInside(rPnt);
/*N*/
/*N*/       // #105130# Include aRect here in measurements to be able to hit a
/*N*/       // fontwork object on its border
/*N*/       if(!bRet)
/*N*/       {
/*N*/           const Rectangle aSnapRect = GetSnapRect();
/*N*/
/*N*/           if( (rPnt.X() >= aSnapRect.Left() - nTol && rPnt.X() <= aSnapRect.Left() + nTol)
/*N*/            || (rPnt.X() >= aSnapRect.Right() - nTol && rPnt.X() <= aSnapRect.Right() + nTol)
/*N*/            || (rPnt.Y() >= aSnapRect.Top() - nTol && rPnt.Y() <= aSnapRect.Top() + nTol)
/*N*/            || (rPnt.Y() >= aSnapRect.Bottom() - nTol && rPnt.Y() <= aSnapRect.Bottom() + nTol))
/*N*/           {
/*N*/               bRet = TRUE;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       if (aGeo.nDrehWink!=0) {
/*N*/           Polygon aPol(aR);
/*N*/           RotatePoly(aPol,aR.TopLeft(),aGeo.nSin,aGeo.nCos);
/*N*/           bRet=IsPointInsidePoly(aPol,rPnt);
/*N*/       } else {
/*N*/           bRet=aR.IsInside(rPnt);
/*N*/       }
/*N*/       if (bRet) { // und nun noch checken, ob wirklich Buchstaben getroffen sind
/*N*/           // Featurewunsch zur 4.0
/*N*/           // Zunaechst meine Dok-Koordinaten in EE-Dok-Koordinaten umwandeln.
/*N*/           Point aPt(rPnt); aPt-=aR.TopLeft();
/*N*/           if (bFitToSize) { // #38214#: FitToSize berueksichtigen
/*?*/               Fraction aX(aTextRect.GetWidth()-1,aLclAnchor.GetWidth()-1);
/*?*/               Fraction aY(aTextRect.GetHeight()-1,aLclAnchor.GetHeight()-1);
/*?*/               ResizePoint(aPt,Point(),aX,aY);
/*N*/           }
/*N*/           if (aGeo.nDrehWink!=0) RotatePoint(aPt,Point(),-aGeo.nSin,aGeo.nCos); // -sin fuer Unrotate
/*N*/           // Und nun im EE-Dok auf Buchstabensuche gehen
/*N*/           long nHitTol = 2000;
/*N*/           OutputDevice* pRef = pOutliner->GetRefDevice();
/*N*/           if( pRef )
/*N*/               nHitTol = pRef->LogicToLogic( nHitTol, MAP_100TH_MM, pRef->GetMapMode().GetMapUnit() );
/*N*/
/*N*/           bRet = pOutliner->IsTextPos( aPt, (sal_uInt16)nHitTol );
/*N*/       }
/*N*/   }
/*N*/
/*N*/   return bRet ? (SdrObject*)this : NULL;
/*N*/ }



/*N*/ void SdrTextObj::operator=(const SdrObject& rObj)
/*N*/ {
/*N*/   SdrAttrObj::operator=(rObj);
/*N*/   const SdrTextObj* pText=PTR_CAST(SdrTextObj,&rObj);
/*N*/   if (pText!=NULL) {
/*N*/       aRect     =pText->aRect;
/*N*/       aGeo      =pText->aGeo;
/*N*/       eTextKind =pText->eTextKind;
/*N*/       bTextFrame=pText->bTextFrame;
/*N*/       aTextSize=pText->aTextSize;
/*N*/       bTextSizeDirty=pText->bTextSizeDirty;
/*N*/
/*N*/       // #101776# Not all of the necessary parameters were copied yet.
/*N*/       bNoShear = pText->bNoShear;
/*N*/       bNoMirror = pText->bNoMirror;
/*N*/
/*N*/       if (pOutlinerParaObject!=NULL) delete pOutlinerParaObject;
/*N*/       if (pText->HasText()) {
/*N*/           pOutlinerParaObject=pText->pOutlinerParaObject->Clone();
/*N*/       } else {
/*N*/           pOutlinerParaObject=NULL;
/*N*/       }
/*N*/       ImpSetTextStyleSheetListeners();
/*N*/   }
/*N*/ }


/*N*/ void SdrTextObj::TakeContour(XPolyPolygon& rPoly) const
/*N*/ {
/*N*/   SdrAttrObj::TakeContour(rPoly);
/*N*/
/*N*/   // #80328# using Clone()-Paint() strategy inside TakeContour() leaves a destroyed
/*N*/   // SdrObject as pointer in DrawOutliner. Set *this again in fetching the outliner
/*N*/   // in every case
/*N*/   SdrOutliner& rOutliner=ImpGetDrawOutliner();
/*N*/
/*N*/   // und nun noch ggf. das BoundRect des Textes dazu
/*N*/   if (pOutlinerParaObject!=NULL && !IsFontwork() && !IsContourTextFrame()) {
/*?*/       Rectangle aLclAnchor;
/*?*/       Rectangle aR;
/*?*/       TakeTextRect(rOutliner,aR,&aLclAnchor);
/*?*/       rOutliner.Clear();
/*?*/       SdrFitToSizeType eFit=GetFitToSize();
/*?*/       bool bFitToSize=(eFit==SDRTEXTFIT_PROPORTIONAL || eFit==SDRTEXTFIT_ALLLINES);
/*?*/       if (bFitToSize) aR=aLclAnchor;
/*?*/       Polygon aPol(aR);
/*?*/       if (aGeo.nDrehWink!=0) RotatePoly(aPol,aR.TopLeft(),aGeo.nSin,aGeo.nCos);
/*?*/       rPoly.Insert(XPolygon(aPol));
/*N*/   }
/*N*/ }


/*N*/ void SdrTextObj::RecalcSnapRect()
/*N*/ {
/*N*/   if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) {
/*N*/       Polygon aPol(aRect);
/*N*/       if (aGeo.nShearWink!=0) ShearPoly(aPol,aRect.TopLeft(),aGeo.nTan);
/*N*/       if (aGeo.nDrehWink!=0) RotatePoly(aPol,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
/*N*/       maSnapRect=aPol.GetBoundRect();
/*N*/   } else {
/*N*/       maSnapRect=aRect;
/*N*/   }
/*N*/ }



/*N*/ void SdrTextObj::ImpCheckMasterCachable()
/*N*/ {
/*N*/   bNotMasterCachable=FALSE;
/*N*/   if (!bNotVisibleAsMaster && pOutlinerParaObject!=NULL && pOutlinerParaObject->IsEditDoc()) {
/*N*/       const EditTextObject& rText=pOutlinerParaObject->GetTextObject();
/*N*/       bNotMasterCachable=rText.HasField(SvxPageField::StaticType());
/*N*/   }
/*N*/ }

// #101029#: Extracted from ImpGetDrawOutliner()
/*N*/ void SdrTextObj::ImpInitDrawOutliner( SdrOutliner& rOutl ) const
/*N*/ {
/*N*/   rOutl.SetUpdateMode(FALSE);
/*N*/   USHORT nOutlinerMode = OUTLINERMODE_OUTLINEOBJECT;
/*N*/   if ( !IsOutlText() )
/*N*/       nOutlinerMode = OUTLINERMODE_TEXTOBJECT;
/*N*/   rOutl.Init( nOutlinerMode );
/*N*/
/*N*/   rOutl.SetGlobalCharStretching(100,100);
/*N*/   ULONG nStat=rOutl.GetControlWord();
/*N*/   nStat&=~(EE_CNTRL_STRETCHING|EE_CNTRL_AUTOPAGESIZE);
/*N*/   rOutl.SetControlWord(nStat);
/*N*/   Size aNullSize;
/*N*/   Size aMaxSize(100000,100000);
/*N*/   rOutl.SetMinAutoPaperSize(aNullSize);
/*N*/   rOutl.SetMaxAutoPaperSize(aMaxSize);
/*N*/   rOutl.SetPaperSize(aMaxSize);
/*N*/   rOutl.ClearPolygon();
/*N*/ }

/*N*/ SdrOutliner& SdrTextObj::ImpGetDrawOutliner() const
/*N*/ {
/*N*/   SdrOutliner& rOutl=pModel->GetDrawOutliner(this);
/*N*/
/*N*/     // #101029#: Code extracted to ImpInitDrawOutliner()
/*N*/     ImpInitDrawOutliner( rOutl );
/*N*/
/*N*/   return rOutl;
/*N*/ }

// #101029#: Extracted from Paint()

/*N*/ OutlinerParaObject* SdrTextObj::GetOutlinerParaObject() const
/*N*/ {
/*N*/   return pOutlinerParaObject;
/*N*/ }

/*N*/ void SdrTextObj::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
/*N*/ {
/*N*/   if( pModel )
/*N*/   {
/*N*/       // Update HitTestOutliner
/*N*/       const SdrTextObj* pTestObj = pModel->GetHitTestOutliner().GetTextObj();
/*N*/       if( pTestObj && pTestObj->GetOutlinerParaObject() == pOutlinerParaObject )
/*?*/           pModel->GetHitTestOutliner().SetTextObj( NULL );
/*N*/   }
/*N*/
/*N*/   if (pOutlinerParaObject!=NULL) {
/*N*/       delete pOutlinerParaObject;
/*N*/       pOutlinerParaObject=NULL;
/*N*/   }
/*N*/   pOutlinerParaObject=pTextObject;
/*N*/
/*N*/   if( pOutlinerParaObject )
/*N*/   {
/*N*/       ImpForceItemSet();
/*N*/       mpObjectItemSet->Put( SvxWritingModeItem( pOutlinerParaObject->IsVertical() ? ::com::sun::star::text::WritingMode_TB_RL : ::com::sun::star::text::WritingMode_LR_TB ) );
/*N*/   }
/*N*/
/*N*/   SetTextSizeDirty();
/*N*/   bPortionInfoChecked=FALSE;
/*N*/   if (IsTextFrame() && (IsAutoGrowHeight() || IsAutoGrowWidth())) { // Textrahmen anpassen!
/*N*/       NbcAdjustTextFrameWidthAndHeight();
/*N*/   }
/*N*/   if (!IsTextFrame()) {
/*N*/       // Das SnapRect behaelt seine Groesse bei
/*N*/       bBoundRectDirty=TRUE;
/*N*/       SetRectsDirty(TRUE);
/*N*/   }
/*N*/   ImpSetTextStyleSheetListeners();
/*N*/   ImpCheckMasterCachable();
/*N*/ }

/*N*/ void SdrTextObj::NbcReformatText()
/*N*/ {
/*N*/   if (pOutlinerParaObject!=NULL) {
/*N*/       bPortionInfoChecked=FALSE;
/*N*/       pOutlinerParaObject->ClearPortionInfo();
/*N*/       if (bTextFrame) {
/*N*/           NbcAdjustTextFrameWidthAndHeight();
/*N*/       } else {
/*N*/           // Das SnapRect behaelt seine Groesse bei
/*N*/           bBoundRectDirty=TRUE;
/*N*/           SetRectsDirty(TRUE);
/*N*/       }
/*N*/       SetTextSizeDirty();
/*N*/   }
/*N*/ }

/*N*/ void SdrTextObj::ReformatText()
/*N*/ {
/*N*/   if (pOutlinerParaObject!=NULL) {
/*N*/       Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetBoundRect();
/*N*/       SendRepaintBroadcast();
/*N*/       NbcReformatText();
/*N*/       SetChanged();
/*N*/       SendRepaintBroadcast();
/*N*/       if (GetBoundRect()!=aBoundRect0) {
/*N*/           SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ void SdrTextObj::SaveGeoData(SdrObjGeoData& rGeo) const
/*N*/ {
/*N*/   SdrAttrObj::SaveGeoData(rGeo);
/*N*/   SdrTextObjGeoData& rTGeo=(SdrTextObjGeoData&)rGeo;
/*N*/   rTGeo.aRect  =aRect;
/*N*/   rTGeo.aGeo   =aGeo;
/*N*/ }

/*N*/ void SdrTextObj::RestGeoData(const SdrObjGeoData& rGeo)
/*N*/ { // RectsDirty wird von SdrObject gerufen
/*N*/   SdrAttrObj::RestGeoData(rGeo);
/*N*/   SdrTextObjGeoData& rTGeo=(SdrTextObjGeoData&)rGeo;
/*N*/   aRect  =rTGeo.aRect;
/*N*/   aGeo   =rTGeo.aGeo;
/*N*/   SetTextSizeDirty();
/*N*/ }

////////////////////////////////////////////////////////////////////////////////////////////////////
// I/O
////////////////////////////////////////////////////////////////////////////////////////////////////

/*N*/ void SdrTextObj::ReadData(const SdrObjIOHeader& rHead, SvStream& rIn)
/*N*/ {
/*N*/   if (rIn.GetError()!=0) return;
/*N*/   if (pOutlinerParaObject!=NULL) {
/*?*/       delete pOutlinerParaObject;
/*?*/       pOutlinerParaObject=NULL;
/*N*/   }
/*N*/
/*N*/   SdrAttrObj::ReadData(rHead,rIn);
/*N*/   SdrDownCompat aCompat(rIn,STREAM_READ); // Fuer Abwaertskompatibilitaet (Lesen neuer Daten mit altem Code)
/*N*/ #ifdef DBG_UTIL
/*N*/   aCompat.SetID("SdrTextObj");
/*N*/ #endif
/*N*/   BYTE nTmp;
/*N*/   rIn>>nTmp;
/*N*/   eTextKind=SdrObjKind(nTmp);
/*N*/   rIn>>aRect;
/*N*/   INT32 n32;
/*N*/   rIn>>n32; aGeo.nDrehWink=n32;
/*N*/   rIn>>n32; aGeo.nShearWink=n32;
/*N*/   aGeo.RecalcSinCos();
/*N*/   aGeo.RecalcTan();
/*N*/   //rIn>>aText;
/*N*/   if (rHead.GetVersion()<=5 && IsOutlText()) { // Das war bis zu diesem Zeitpunkt nicht gespeichert
/*?*/       NbcSetAutoGrowHeight(FALSE);
/*N*/   }
/*N*/
/*N*/   BOOL bOutlinerParaObjectValid=FALSE;
/*N*/   rIn>>bOutlinerParaObjectValid;
/*N*/   if (bOutlinerParaObjectValid)
/*N*/   {
/*N*/       SfxItemPool* pOutlPool=pModel!=NULL ? &pModel->GetItemPool() : NULL;
/*N*/       if (rHead.GetVersion()>=11) {
/*N*/           SdrDownCompat aTextCompat(rIn,STREAM_READ); // ab V11 eingepackt
/*N*/ #ifdef DBG_UTIL
/*N*/           aTextCompat.SetID("SdrTextObj(OutlinerParaObject)");
/*N*/ #endif
/*N*/           pOutlinerParaObject=OutlinerParaObject::Create(rIn,pOutlPool);
/*N*/       } else {
/*N*/           pOutlinerParaObject=OutlinerParaObject::Create(rIn,pOutlPool);
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if( pOutlinerParaObject )
/*N*/   {
/*N*/       if( pOutlinerParaObject->GetOutlinerMode() == OUTLINERMODE_DONTKNOW )
/*N*/       {
/*N*/           if( eTextKind == OBJ_TITLETEXT )
/*N*/               pOutlinerParaObject->SetOutlinerMode( OUTLINERMODE_TITLEOBJECT );
/*N*/           else if( eTextKind == OBJ_OUTLINETEXT )
/*N*/               pOutlinerParaObject->SetOutlinerMode( OUTLINERMODE_OUTLINEOBJECT );
/*N*/           else
/*N*/               pOutlinerParaObject->SetOutlinerMode( OUTLINERMODE_TEXTOBJECT );
/*N*/       }
/*N*/
/*N*/       if( pOutlinerParaObject->IsVertical() )
/*N*/       {
/*?*/           ImpForceItemSet();
/*?*/           mpObjectItemSet->Put( SvxWritingModeItem( ::com::sun::star::text::WritingMode_TB_RL ) );
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (rHead.GetVersion()>=10) {
/*N*/       // Ab FileVersion 10 wird das TextBoundRect gestreamt
/*N*/       BOOL bFormTextBoundRectValid=FALSE;
/*N*/       rIn>>bFormTextBoundRectValid;
/*N*/       if (bFormTextBoundRectValid) {
/*N*/           if (pFormTextBoundRect==NULL) pFormTextBoundRect=new Rectangle;
/*N*/           rIn>>*pFormTextBoundRect;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if(rHead.GetVersion() < 12 && !bTextFrame)
/*N*/   {
/*N*/       mpObjectItemSet->Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER));
/*N*/       mpObjectItemSet->Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
/*N*/       mpObjectItemSet->Put(SvxAdjustItem(SVX_ADJUST_CENTER));
/*N*/   }
/*N*/
/*N*/   if (bTextFrame && pOutlinerParaObject!=NULL)
/*N*/       NbcAdjustTextFrameWidthAndHeight();
/*N*/
/*N*/   if ( pOutlinerParaObject &&
/*N*/        pOutlinerParaObject->GetTextObject().GetVersion() < 500 &&
/*N*/        !pOutlinerParaObject->IsEditDoc() )
/*N*/   {
/*N*/       pOutlinerParaObject->MergeParaAttribs( GetItemSet() );
/*N*/   }
/*N*/
/*N*/   // #84529# correct gradient rotation for 5.2 and earlier
/*N*/   if(aGeo.nDrehWink != 0 && rHead.GetVersion() <= 16)
/*N*/   {
/*N*/       XFillStyle eStyle = ((const XFillStyleItem&)GetItem(XATTR_FILLSTYLE)).GetValue();
/*N*/       if(XFILL_GRADIENT == eStyle)
/*N*/       {
/*N*/           XFillGradientItem aItem = (XFillGradientItem&)GetItem(XATTR_FILLGRADIENT);
/*N*/           XGradient aGradient = aItem.GetValue();
/*N*/
/*N*/           // calc new angle. aGeo.nDrehWink is 1/100th degree, aGradient.GetAngle()
/*N*/           // is 1/10th degree. Match this.
/*N*/           sal_Int32 nNewAngle = ((aGeo.nDrehWink + (aGradient.GetAngle() * 10)) + 5) / 10;
/*N*/
/*N*/           while(nNewAngle < 0)
/*?*/               nNewAngle += 3600;
/*N*/
/*N*/           while(nNewAngle >= 3600)
/*N*/               nNewAngle -= 3600;
/*N*/
/*N*/           // create new item and set
/*N*/           aGradient.SetAngle(nNewAngle);
/*N*/           aItem.SetValue(aGradient);
/*N*/           SetItem(aItem);
/*N*/       }
/*N*/   }
/*N*/
/*N*/   ImpSetTextStyleSheetListeners();
/*N*/   SetTextSizeDirty();
/*N*/   ImpCheckMasterCachable();
/*N*/ }



/*N*/ SdrFitToSizeType SdrTextObj::GetFitToSize() const
/*N*/ {
/*N*/   SdrFitToSizeType eType = SDRTEXTFIT_NONE;
/*N*/
/*N*/   if(!IsAutoGrowWidth())
/*N*/       eType = ((SdrTextFitToSizeTypeItem&)(GetItem(SDRATTR_TEXT_FITTOSIZE))).GetValue();
/*N*/
/*N*/   return eType;
/*N*/ }

/*N*/ void SdrTextObj::ForceOutlinerParaObject()
/*N*/ {
/*N*/   if( pOutlinerParaObject == NULL )
/*N*/   {
/*?*/       USHORT nOutlMode = OUTLINERMODE_TEXTOBJECT;
/*?*/       if( IsTextFrame() && eTextKind == OBJ_OUTLINETEXT )
/*?*/           nOutlMode = OUTLINERMODE_OUTLINEOBJECT;
/*?*/
/*?*/       Outliner* pOutliner = SdrMakeOutliner( nOutlMode, pModel );
/*?*/       if( pOutliner )
/*?*/       {
/*?*/           Outliner& aDrawOutliner = pModel->GetDrawOutliner();
/*?*/           pOutliner->SetCalcFieldValueHdl( aDrawOutliner.GetCalcFieldValueHdl() );
/*?*/
/*?*/           pOutliner->SetStyleSheet( 0, GetStyleSheet());
/*?*/           OutlinerParaObject* pLclOutlinerParaObject = pOutliner->CreateParaObject();
/*?*/           SetOutlinerParaObject( pLclOutlinerParaObject );
/*?*/
/*?*/           delete pOutliner;
/*?*/       }
/*N*/   }
/*N*/ }

/*N*/ BOOL SdrTextObj::IsVerticalWriting() const
/*N*/ {
/*N*/   // #89459#
/*N*/   if(pOutlinerParaObject)
/*N*/       return pOutlinerParaObject->IsVertical();
/*N*/   return FALSE;
/*N*/ }

/*N*/ void SdrTextObj::SetVerticalWriting( BOOL bVertical )
/*N*/ {
/*N*/   ForceOutlinerParaObject();
/*N*/
/*N*/   DBG_ASSERT( pOutlinerParaObject, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );
/*N*/   if( pOutlinerParaObject )
/*N*/   {
/*N*/       if(pOutlinerParaObject->IsVertical() != bVertical)
/*N*/       {
/*?*/           // get item settings
/*?*/           const SfxItemSet& rSet = GetItemSet();
/*?*/           sal_Bool bAutoGrowWidth = ((SdrTextAutoGrowWidthItem&)rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH)).GetValue();
/*?*/           sal_Bool bAutoGrowHeight = ((SdrTextAutoGrowHeightItem&)rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT)).GetValue();
/*?*/
/*?*/           // #103516# Also exchange hor/ver adjust items
/*?*/           SdrTextHorzAdjust eHorz = ((SdrTextHorzAdjustItem&)(rSet.Get(SDRATTR_TEXT_HORZADJUST))).GetValue();
/*?*/           SdrTextVertAdjust eVert = ((SdrTextVertAdjustItem&)(rSet.Get(SDRATTR_TEXT_VERTADJUST))).GetValue();
/*?*/
/*?*/           // rescue object size
/*?*/           Rectangle aObjectRect = GetSnapRect();
/*?*/
/*?*/           // prepare ItemSet to set exchanged width and height items
/*?*/           SfxItemSet aNewSet(*rSet.GetPool(),
/*?*/               SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
/*?*/               // #103516# Expanded item ranges to also support hor and ver adjust.
/*?*/               SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST,
/*?*/               SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST,
/*?*/               0, 0);
/*?*/
/*?*/           aNewSet.Put(rSet);
/*?*/           aNewSet.Put(SdrTextAutoGrowWidthItem(bAutoGrowHeight));
/*?*/           aNewSet.Put(SdrTextAutoGrowHeightItem(bAutoGrowWidth));
/*?*/
/*?*/           // #103516# Exchange horz and vert adjusts
/*?*/           switch(eVert)
/*?*/           {
/*?*/               case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
/*?*/               case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
/*?*/               case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
/*?*/               case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
/*?*/           }
/*?*/           switch(eHorz)
/*?*/           {
/*?*/               case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
/*?*/               case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
/*?*/               case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break;
/*?*/               case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break;
/*?*/           }
/*?*/
/*?*/           SetItemSet(aNewSet);
/*?*/
/*?*/           // set ParaObject orientation accordingly
/*?*/           pOutlinerParaObject->SetVertical(bVertical);
/*?*/
/*?*/           // restore object size
/*?*/           SetSnapRect(aObjectRect);
/*N*/       }
/*N*/   }
/*N*/ }

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// transformation interface for StarOfficeAPI. This implements support for
// homogen 3x3 matrices containing the transformation of the SdrObject. At the
// moment it contains a shearX, rotation and translation, but for setting all linear
// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
//
////////////////////////////////////////////////////////////////////////////////////////////////////
// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
// with the base geometry and returns TRUE. Otherwise it returns FALSE.
/*N*/ BOOL SdrTextObj::TRGetBaseGeometry(Matrix3D& rMat, XPolyPolygon& /*rPolyPolygon*/) const
/*N*/ {
/*N*/   // get turn and shear
/*N*/   double fRotate = (aGeo.nDrehWink / 100.0) * F_PI180;
/*N*/   double fShear = (aGeo.nShearWink / 100.0) * F_PI180;
/*N*/
/*N*/   // get aRect, this is the unrotated snaprect
/*N*/   Rectangle aRectangle(aRect);
/*N*/
/*N*/   // fill other values
/*N*/   Vector2D aScale((double)aRectangle.GetWidth(), (double)aRectangle.GetHeight());
/*N*/   Vector2D aTranslate((double)aRectangle.Left(), (double)aRectangle.Top());
/*N*/
/*N*/   // position maybe relative to anchorpos, convert
/*N*/   if( pModel->IsWriter() )
/*N*/   {
/*N*/       if(GetAnchorPos().X() != 0 || GetAnchorPos().Y() != 0)
/*N*/           aTranslate -= Vector2D(GetAnchorPos().X(), GetAnchorPos().Y());
/*N*/   }
/*N*/
/*N*/   // force MapUnit to 100th mm
/*N*/   SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
/*N*/   if(eMapUnit != SFX_MAPUNIT_100TH_MM)
/*N*/   {
/*N*/       switch(eMapUnit)
/*N*/       {
/*N*/           case SFX_MAPUNIT_TWIP :
/*N*/           {
/*N*/               // position
/*N*/               // #104018#
/*N*/               aTranslate.X() = ImplTwipsToMM(aTranslate.X());
/*N*/               aTranslate.Y() = ImplTwipsToMM(aTranslate.Y());
/*N*/
/*N*/               // size
/*N*/               // #104018#
/*N*/               aScale.X() = ImplTwipsToMM(aScale.X());
/*N*/               aScale.Y() = ImplTwipsToMM(aScale.Y());
/*N*/
/*N*/               break;
/*N*/           }
/*N*/           default:
/*N*/           {
/*N*/               OSL_FAIL("TRGetBaseGeometry: Missing unit translation to 100th mm!");
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   // build matrix
/*N*/   rMat.Identity();
/*N*/   if(aScale.X() != 1.0 || aScale.Y() != 1.0)
/*N*/       rMat.Scale(aScale.X(), aScale.Y());
/*N*/   if(fShear != 0.0)
/*N*/       rMat.ShearX(tan(fShear));
/*N*/   if(fRotate != 0.0)
/*N*/       rMat.Rotate(fRotate);
/*N*/   if(aTranslate.X() != 0.0 || aTranslate.Y() != 0.0)
/*N*/       rMat.Translate(aTranslate.X(), aTranslate.Y());
/*N*/
/*N*/   return FALSE;
/*N*/ }

// sets the base geometry of the object using infos contained in the homogen 3x3 matrix.
// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
// to use (0,0) as upper left and will be scaled to the given size in the matrix.
/*N*/ void SdrTextObj::TRSetBaseGeometry(const Matrix3D& rMat, const XPolyPolygon& /*rPolyPolygon*/)
/*N*/ {
/*N*/   // break up matrix
/*N*/   Vector2D aScale, aTranslate;
/*N*/   double fShear, fRotate;
/*N*/   rMat.DecomposeAndCorrect(aScale, fShear, fRotate, aTranslate);
/*N*/
/*N*/   // reset object shear and rotations
/*N*/   aGeo.nDrehWink = 0;
/*N*/   aGeo.RecalcSinCos();
/*N*/   aGeo.nShearWink = 0;
/*N*/   aGeo.RecalcTan();
/*N*/
/*N*/   // force metric to pool metric
/*N*/   SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
/*N*/   if(eMapUnit != SFX_MAPUNIT_100TH_MM)
/*N*/   {
/*N*/       switch(eMapUnit)
/*N*/       {
/*N*/           case SFX_MAPUNIT_TWIP :
/*N*/           {
/*N*/               // position
/*N*/               // #104018#
/*N*/               aTranslate.X() = ImplMMToTwips(aTranslate.X());
/*N*/               aTranslate.Y() = ImplMMToTwips(aTranslate.Y());
/*N*/
/*N*/               // size
/*N*/               // #104018#
/*N*/               aScale.X() = ImplMMToTwips(aScale.X());
/*N*/               aScale.Y() = ImplMMToTwips(aScale.Y());
/*N*/
/*N*/               break;
/*N*/           }
/*N*/           default:
/*N*/           {
/*N*/               OSL_FAIL("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   // if anchor is used, make position relative to it
/*N*/   if( pModel->IsWriter() )
/*N*/   {
/*N*/       if(GetAnchorPos().X() != 0 || GetAnchorPos().Y() != 0)
/*N*/           aTranslate += Vector2D(GetAnchorPos().X(), GetAnchorPos().Y());
/*N*/   }
/*N*/
/*N*/   // build and set BaseRect (use scale)
/*N*/   Point aPoint = Point();
/*N*/   Size  aSize(FRound(aScale.X()), FRound(aScale.Y()));
/*N*/   Rectangle aBaseRect(aPoint, aSize);
/*N*/   SetSnapRect(aBaseRect);
/*N*/
/*N*/   // shear?
/*N*/   if(fShear != 0.0)
/*N*/   {
/*N*/       GeoStat aGeoStat;
/*N*/       aGeoStat.nShearWink = FRound((atan(fShear) / F_PI180) * 100.0);
/*N*/       aGeoStat.RecalcTan();
/*N*/       Shear(Point(), aGeoStat.nShearWink, aGeoStat.nTan, FALSE);
/*N*/   }
/*N*/
/*N*/   // rotation?
/*N*/   if(fRotate != 0.0)
/*N*/   {
/*N*/       GeoStat aGeoStat;
/*N*/       aGeoStat.nDrehWink = FRound((fRotate / F_PI180) * 100.0);
/*N*/       aGeoStat.RecalcSinCos();
/*N*/       Rotate(Point(), aGeoStat.nDrehWink, aGeoStat.nSin, aGeoStat.nCos);
/*N*/   }
/*N*/
/*N*/   // translate?
/*N*/   if(aTranslate.X() != 0.0 || aTranslate.Y() != 0.0)
/*N*/   {
/*N*/       Move(Size(
/*N*/           (sal_Int32)FRound(aTranslate.X()),
/*N*/           (sal_Int32)FRound(aTranslate.Y())));
/*N*/   }
/*N*/ }


/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Konzept des TextObjekts:
// ~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute/Varianten:
// - BOOL Textrahmen / beschriftetes Zeichenobjekt
// - BOOL FontWork                 (wenn nicht Textrahmen und nicht ContourTextFrame)
// - BOOL ContourTextFrame         (wenn nicht Textrahmen und nicht Fontwork)
// - long Drehwinkel               (wenn nicht FontWork)
// - long Textrahmenabstaende      (wenn nicht FontWork)
// - BOOL FitToSize                (wenn nicht FontWork)
// - BOOL AutoGrowingWidth/Height  (wenn nicht FitToSize und nicht FontWork)
// - long Min/MaxFrameWidth/Height (wenn AutoGrowingWidth/Height)
// - enum Horizontale Textverankerung Links,Mitte,Rechts,Block,Stretch(ni)
// - enum Vertikale Textverankerung Oben,Mitte,Unten,Block,Stretch(ni)
// - enum Laufschrift              (wenn nicht FontWork)
//
// Jedes abgeleitete Objekt ist entweder ein Textrahmen (bTextFrame=TRUE)
// oder ein beschriftetes Zeichenobjekt (bTextFrame=FALSE).
//
// Defaultverankerung von Textrahmen:
//   SDRTEXTHORZADJUST_BLOCK, SDRTEXTVERTADJUST_TOP
//   = statische Pooldefaults
// Defaultverankerung von beschrifteten Zeichenobjekten:
//   SDRTEXTHORZADJUST_CENTER, SDRTEXTVERTADJUST_CENTER
//   durch harte Attributierung von SdrAttrObj
//
// Jedes vom SdrTextObj abgeleitete Objekt muss ein "UnrotatedSnapRect"
// (->TakeUnrotatedSnapRect()) liefern (Drehreferenz ist TopLeft dieses
// Rechtecks (aGeo.nDrehWink)), welches die Grundlage der Textverankerung
// bildet. Von diesem werden dann ringsum die Textrahmenabstaende abgezogen;
// das Ergebnis ist der Ankerbereich (->TakeTextAnchorRect()). Innerhalb
// dieses Bereichs wird dann in Abhaengigkeit von der horizontalen und
// vertikalen Ausrichtung (SdrTextVertAdjust,SdrTextHorzAdjust) der Ankerpunkt
// sowie der Ausgabebereich bestimmt. Bei beschrifteten Grafikobjekten kann
// der Ausgabebereich durchaus groesser als der Ankerbereich werden, bei
// Textrahmen ist er stets kleiner oder gleich (ausser bei negativen Textrahmen-
// abstaenden).
//
// FitToSize hat Prioritaet vor Textverankerung und AutoGrowHeight/Width. Der
// Ausgabebereich ist bei FitToSize immer genau der Ankerbereich. Weiterhin
// gibt es bei FitToSize keinen automatischen Zeilenumbruch.
//
// ContourTextFrame:
// - long Drehwinkel
// - long Textrahmenabstaende         spaeter vielleicht
// - BOOL FitToSize                   spaeter vielleicht
// - BOOL AutoGrowingWidth/Height     viel spaeter vielleicht
// - long Min/MaxFrameWidth/Height    viel spaeter vielleicht
// - enum Horizontale Textverankerung spaeter vielleicht, erstmal Links, Absatz zentr.
// - enum Vertikale Textverankerung   spaeter vielleicht, erstmal oben
// - enum Laufschrift                 spaeter vielleicht (evtl. sogar mit korrektem Clipping)
//
// Bei Aenderungen zu beachten:
// - Paint
// - HitTest
// - RecalcBoundRect
// - ConvertToPoly
// - Edit
// - Drucken,Speichern, Paint in Nachbarview waerend Edit
// - ModelChanged (z.B. durch NachbarView oder Lineale) waerend Edit
// - FillColorChanged waerend Edit
// - uvm...
//
/////////////////////////////////////////////////////////////////////////////////////////////////

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
