/* -*- 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.
 *
 ************************************************************************/
#define ITEMID_DOUBLE           0
#define ITEMID_CHARTTEXTORDER   SCHATTR_TEXT_ORDER
#define ITEMID_CHARTTEXTORIENT  SCHATTR_TEXT_ORIENT
#define ITEMID_CHARTLEGENDPOS   SCHATTR_LEGEND_POS
#define ITEMID_CHARTDATADESCR   SCHATTR_DATADESCR_DESCR


#include <bf_svx/svdopath.hxx>




#include <bf_svx/eeitem.hxx>
#ifndef _ZFORLIST_HXX //autogen
#ifndef _ZFORLIST_DECLARE_TABLE
#define _ZFORLIST_DECLARE_TABLE
#endif
#include <bf_svtools/zforlist.hxx>
#endif
#include <rtl/math.hxx>
#include <bf_svx/xlnclit.hxx>

#include <bf_svx/xlnwtit.hxx>
#include "schattr.hxx"

#define ITEMID_FONT        EE_CHAR_FONTINFO
#define ITEMID_COLOR       EE_CHAR_COLOR
#define ITEMID_FONTHEIGHT  EE_CHAR_FONTHEIGHT

#include <bf_svx/fontitem.hxx>
#include <bf_svx/fhgtitem.hxx>
#include <bf_svx/svxids.hrc>

#include "arrayhelper.hxx"
#include "float.h"
#include "chaxis.hxx"
#include "pairs.hxx"
#include "glob.hrc"
#include "axisobj.hxx"
#include "globfunc.hxx"
#include    <algorithm>
#include    <limits>
namespace binfilter {

/*N*/ void ChartAxis::SetDefaults()
/*N*/ {
/*N*/   Font aLatinFont( OutputDevice::GetDefaultFont( DEFAULTFONT_LATIN_SPREADSHEET, mpModel->GetLanguage( EE_CHAR_LANGUAGE ), DEFAULTFONT_FLAGS_ONLYONE ) );
/*N*/   SvxFontItem aSvxFontItem( aLatinFont.GetFamily(), aLatinFont.GetName(), aLatinFont.GetStyleName(), aLatinFont.GetPitch(),
/*N*/                             aLatinFont.GetCharSet(), EE_CHAR_FONTINFO );
/*N*/
/*N*/   Font aCJKFont( OutputDevice::GetDefaultFont( DEFAULTFONT_CJK_SPREADSHEET, mpModel->GetLanguage( EE_CHAR_LANGUAGE_CJK ), DEFAULTFONT_FLAGS_ONLYONE ) );
/*N*/   SvxFontItem aSvxFontItemCJK( aCJKFont.GetFamily(), aCJKFont.GetName(), aCJKFont.GetStyleName(), aCJKFont.GetPitch(),
/*N*/                                aCJKFont.GetCharSet(), EE_CHAR_FONTINFO_CJK );
/*N*/
/*N*/   Font aCTLFont( OutputDevice::GetDefaultFont( DEFAULTFONT_CTL_SPREADSHEET, mpModel->GetLanguage( EE_CHAR_LANGUAGE_CTL ), DEFAULTFONT_FLAGS_ONLYONE ) );
/*N*/   SvxFontItem aSvxFontItemCTL( aCTLFont.GetFamily(), aCTLFont.GetName(), aCTLFont.GetStyleName(), aCTLFont.GetPitch(),
/*N*/                                aCTLFont.GetCharSet(), EE_CHAR_FONTINFO_CTL );
/*N*/
/*N*/   //  Attention!  If the size of the three fonts below is changed from 7pt to
/*N*/   //  some other value, change also the font scaling in globfunc.cxx:ItemsToFont.
/*N*/   mpAxisAttr->Put(aSvxFontItem);
/*N*/   mpAxisAttr->Put(SvxFontHeightItem( 247, 100, EE_CHAR_FONTHEIGHT )); // 7pt
/*N*/   mpAxisAttr->Put(aSvxFontItemCJK);
/*N*/   mpAxisAttr->Put(SvxFontHeightItem( 247, 100, EE_CHAR_FONTHEIGHT_CJK )); // 7pt
/*N*/   mpAxisAttr->Put(aSvxFontItemCTL);
/*N*/   mpAxisAttr->Put(SvxFontHeightItem( 247, 100, EE_CHAR_FONTHEIGHT_CTL )); // 7pt
/*N*/
/*N*/     // the font color has 'automatic' as default that should not be overwritten
/*N*/ //    mpAxisAttr->Put(SvxColorItem(RGBColor(COL_BLACK)));
/*N*/   mpAxisAttr->ClearItem( ITEMID_COLOR );
/*N*/   mpAxisAttr->Put(XLineStyleItem(XLINE_SOLID));
/*N*/   mpAxisAttr->Put(XLineWidthItem(0));
/*N*/   mpAxisAttr->Put(XLineColorItem( String(), RGBColor(COL_BLACK)));
/*N*/   mpAxisAttr->Put(SvxChartTextOrientItem(CHTXTORIENT_AUTOMATIC));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_TEXT_OVERLAP,FALSE));
/*N*/
/*N*/   mpAxisAttr->Put(SvxChartTextOrderItem(CHTXTORDER_SIDEBYSIDE));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MIN, TRUE));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(0.0, SCHATTR_AXIS_MIN));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MAX, TRUE));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(0.0, SCHATTR_AXIS_MAX));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN, TRUE));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_MAIN));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP, TRUE));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_HELP));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM, FALSE));
/*N*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN, (mnId==CHART_AXIS_Y)?FALSE:TRUE));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(0.0, SCHATTR_AXIS_ORIGIN));
/*N*/   mpAxisAttr->Put(SfxInt32Item(SCHATTR_AXISTYPE, mnId));
/*N*/   mpAxisAttr->Put(SfxInt32Item(SCHATTR_AXIS_TICKS, CHAXIS_MARK_OUTER));
/*N*/   ShowAxis(TRUE);
/*N*/   ShowDescr(TRUE);
/*N*/
/*N*/ }
/*N*/ void ChartAxis::SetAttributes(const SfxItemSet &rAttr)
/*N*/ {
/*N*/   mpAxisAttr->Put(rAttr);
/*N*/
/*N*/   //Erst immer Auto-attr holen, damit evtl. berechnete Werte nicht überschrieben werden.
/*N*/   ReadAutoAttr();
/*N*/   ReadAttr();
/*N*/ };
/*N*/ void ChartAxis::SetAttributes(SfxItemSet *pSet)
/*N*/ {
/*N*/   if(pSet)
/*N*/       SetAttributes(*pSet);
/*N*/ };
/*N*/ ChartAxis::~ChartAxis()
/*N*/ {
/*N*/ 	delete [] mpTotal;
/*N*/ 	delete [] mpColStack;
/*N*/   delete mpAxisAttr;
/*N*/   mpAxisAttr=NULL;
/*N*/   mpModel=NULL;
/*N*/ 	delete mpTextAttr;
/*N*/ }

/*N*/ ChartAxis::ChartAxis(ChartModel* pModel,long nId,long nUId)
/*N*/   : mbInnerPos(FALSE)
/*N*/   , mnInnerPos(-1)
/*N*/   , mbColText(FALSE)
/*N*/   , mbCenterText(FALSE)
/*N*/   , mnMaxTextWidth(-1)
/*N*/   , mnAlternateId(0)
/*N*/   , mbAlternativIdUsed(FALSE)
/*N*/   , mbPercentCol(TRUE)
/*N*/   , mpTotal(NULL)
/*N*/   , mnTotalSize(0)
/*N*/   , mbTotalActual(FALSE)
/*N*/   , mbTotalAlloc(FALSE)
/*N*/   , mpColStack(NULL)
/*N*/   , mbColStackOK(FALSE)
/*N*/   , mnUId(nUId)
/*N*/   , mbShowDescr(FALSE)
/*N*/   , mpNumFormatter(NULL)
/*N*/   , mpAxisList(NULL)
/*N*/   , mpAxisObj(NULL)
/*N*/   , mpGridAttr(NULL)
/*N*/   , mpTextAttr(NULL)
/*N*/   , mnTicks(CHAXIS_MARK_OUTER)
/*N*/   , mnHelpTicks(0)
/*N*/   , mnTickLen(150)
/*N*/   , mnHelpTickLen(100)
/*N*/   , mbSecondary(FALSE)
/*N*/   , mnId(nId)
/*N*/   , mbFlippedXY(FALSE)
/*N*/   , mnPosition(0)
/*N*/   , mbRadial(FALSE)
/*N*/   , maArea(0,0,0,0)
/*N*/   , mbPercent(FALSE)
/*N*/   , mpAxisAttr(NULL)
/*N*/   , mpModel(pModel)
/*N*/   , mfMin(0.0)
/*N*/   , mfMax(0.0)
/*N*/   , mfStep(0.0)
/*N*/   , mfStepHelp(0.0)
/*N*/   , mfOrigin(0.0)
/*N*/   , mbAutoMin(FALSE)
/*N*/   , mbAutoMax(FALSE)
/*N*/   , mbAutoOrigin(FALSE)
/*N*/   , mbAutoStep(FALSE)
/*N*/   , mbAutoStepHelp(FALSE)
/*N*/   , mbLogarithm(FALSE)
/*N*/   , meTextOrient( CHTXTORIENT_AUTOMATIC )
/*N*/ {
/*N*/   mpAxisAttr=new SfxItemSet(mpModel->GetPool(),nAxisWhichPairs);
/*N*/   SetDefaults();  //attribute fuellen
/*N*/   ReadAutoAttr(); //automatik? aus ItemSet holen
/*N*/   ReadAttr();     //evtl. defaults aus Itemset uebernehmen (etwas Overhead, aber sicher)
/*N*/ }

/*N*/ long ChartAxis::GetUpper(double fData,BOOL bConstrained)
/*N*/ {
/*N*/   long nData;
/*N*/   if(fData < mfOrigin)
/*?*/       nData = GetPos(mfOrigin);
/*N*/   else
/*N*/       nData = GetPos(fData);
/*N*/
/*N*/   if(!bConstrained)
/*?*/       return nData;
/*N*/
/*N*/   if(IsVertical())
/*N*/       return Max(maRefArea.Top(),nData);
/*N*/   else
/*N*/       return Min(maRefArea.Right(),nData);
/*N*/ }
/*N*/ long ChartAxis::GetLower(double fData,BOOL bConstrained)
/*N*/ {
/*N*/   long nData;
/*N*/
/*N*/   if(fData > mfOrigin)
/*N*/       nData = GetPos(mfOrigin);
/*N*/   else
/*N*/       nData = GetPos(fData);
/*N*/
/*N*/   if(!bConstrained)
/*?*/       return nData;
/*N*/
/*N*/   if(IsVertical())
/*N*/       return Min(maRefArea.Bottom(),nData);
/*N*/   else
/*N*/       return Max(maRefArea.Left(),nData);
/*N*/ }
/*N*/ Pair ChartAxis::Stack(double fData,BOOL bConstrained)
/*N*/ {
/*N*/   double fTop,fBottom;
/*N*/
/*N*/   if (fData < 0.0)//mfOrigin
/*N*/   {
/*?*/       fTop = mfDataBottom;
/*?*/           mfDataBottom += fData;
/*?*/       fBottom = mfDataBottom;
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/         if( fData == DBL_MIN )
/*N*/             fData = 0;
/*N*/       fBottom = mfDataTop;
/*N*/           mfDataTop += fData;
/*N*/       fTop = mfDataTop;
/*N*/   }
/*N*/
/*N*/   if(bConstrained)
/*N*/   {
/*N*/       if(IsVertical())
/*N*/           return Pair(Max(maRefArea.Top(),GetPos(fTop))
/*N*/                     , Min(maRefArea.Bottom(),GetPos(fBottom)) );
/*N*/       else
/*N*/           return Pair(Max(maRefArea.Left(),GetPos(fBottom))
/*N*/                      ,Min(maRefArea.Right(),GetPos(fTop))     );
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       return Pair(GetPos(fTop),GetPos(fBottom));
/*N*/   }
/*N*/ }
/*N*/ BOOL ChartAxis::IsVertical()
/*N*/ {
/*N*/   return( (mnId==CHART_AXIS_Y && !mbFlippedXY)
/*N*/         ||(mnId==CHART_AXIS_X && mbFlippedXY));
/*N*/ }


/*N*/ void ChartAxis::ResizeTotal(long nSize)
/*N*/ {
/*N*/   if(nSize && !mbTotalAlloc)
/*N*/   {
/*N*/       if(nSize!=mnTotalSize)
/*N*/       {
/*N*/ 			delete [] mpTotal;
/*N*/           mnTotalSize = nSize;
/*N*/ 			mpTotal = ArrayHelper<double>::create_long_size(mnTotalSize);
                if(!mpTotal)
                    mnTotalSize=0;
/*N*/       }
/*N*/
            if(mpTotal)
            {
/*N*/ 		    while(nSize--)
/*N*/ 			    mpTotal[nSize]=0.0;
            }
/*N*/   }
/*N*/   mbTotalAlloc=TRUE;
/*N*/ };
/*N*/ double ChartAxis::Data2Percent(double fData,long nCol,long nRow)
/*N*/ {
/*N*/   double fTotal=GetTotal( mbPercentCol ? nCol : nRow);
/*N*/
/*N*/   return fTotal ? ( (fabs(fData) / fTotal) * 100.0 ) : DBL_MIN;
/*N*/ }
/*N*/ double ChartAxis::GetTotal(long n)
/*N*/ {
/*N*/   if(!mbTotalActual)
/*N*/       CreateTotal();
/*N*/
        if( mpTotal && n>=0 && n<mnTotalSize )
/*N*/ 	    return mpTotal[n];
        return 10.0;
/*N*/ }
/*N*/ void ChartAxis::CreateTotal()
/*N*/ {
/*N*/   if(mbTotalActual)
/*?*/       return ;
/*N*/
/*N*/   double fData;
/*N*/
/*N*/   long nColCnt=mpModel->GetColCount();
/*N*/   long nRowCnt=mpModel->GetRowCount();
/*N*/
/*N*/
/*N*/   if(mbPercentCol) //Prozent auf Datenreihe beziehen!
/*N*/   {
/*N*/       ResizeTotal(nColCnt); //Array anlegen und auf 0.0 setzen
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       ResizeTotal(nRowCnt); //Array anlegen und auf 0.0 setzen
/*N*/   }
/*N*/
/*N*/
/*N*/   long nId,nCol;
/*N*/   for(long nRow=0;nRow<nRowCnt;nRow++)
/*N*/   {
/*N*/       nId=((const SfxInt32Item &)(mpModel->GetDataRowAttr(nRow).Get(SCHATTR_AXIS))).GetValue();
/*N*/ 		if(nId==mnUId && mpTotal)
/*N*/       {
/*N*/           for(nCol=0;nCol<nColCnt;nCol++)
/*N*/           {
/*N*/               fData=mpModel->GetData(nCol,nRow);
/*N*/               mpTotal[ mbPercentCol ? nCol : nRow] += fabs(fData);
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   mbTotalActual=TRUE; //einmal und nie wieder (während eines BuildChart zumindest)
/*N*/ };

/*N*/ BOOL ChartAxis::IsOriginInRange() const
/*N*/ {
/*N*/   return  ((mfMin <= mfOrigin) && (mfOrigin <= mfMax));
/*N*/ }

// Stapeln der Werte je Col (für Liniencharts)
/*N*/ void ChartAxis::InitColStacking(long nColCnt)
/*N*/ {
/*N*/ 	delete [] mpColStack;
/*N*/ 	mpColStack = ArrayHelper<double>::create_long_size(nColCnt);
        if(mpColStack)
        {
/*N*/ 	    while(nColCnt--)
/*N*/ 		    mpColStack[nColCnt]=0.0;//mfOrigin ????;
        }
/*N*/ }
//Stapeln der Werte je Column (Stapeln bei LinienCharts)
/*N*/ double ChartAxis::StackColData(double fData,long nCol,long nColCnt)
/*N*/ {
/*N*/   if(!mbColStackOK)
/*N*/       InitColStacking(nColCnt);//falls noch nicht geschehen
/*N*/   mbColStackOK=TRUE;//wird bei Initialise auf FALSE gesetzt
/*N*/
        if(mpColStack)
        {
/*N*/ 	    mpColStack[nCol]+=fData;
/*N*/ 	    return mpColStack[nCol];
        }
        return fData;
/*N*/ }
//Dies Funktion wird u.A. von Initialise gerufen (sehr früh im Buildvorgang)
//Attribute innerer Schleifen (CretaeMarks, etc.) können hier in Variablen
//gewandelt werden
/*N*/ void ChartAxis::ReadAttr()
/*N*/ {
/*N*/
/*N*/   //Art der Markierungen (innen/aussen)
/*N*/   mnTicks     = ((const SfxInt32Item&)mpAxisAttr->Get(SCHATTR_AXIS_TICKS)).GetValue();
/*N*/   mnHelpTicks = ((const SfxInt32Item&)mpAxisAttr->Get(SCHATTR_AXIS_HELPTICKS)).GetValue();
/*N*/
/*N*/   long nFak = IsVertical() ? -1 : 1;
/*N*/   if(mbSecondary)
/*N*/       nFak*=-1;
/*N*/
/*N*/   long nHelpFak=nFak;
/*N*/
/*N*/   mnTickLen=nFak*150;
/*N*/   mnHelpTickLen=nHelpFak*100;
/*N*/
/*N*/   // WICHTIG! Diese Methode darf keine Member, die Automatisch sind, ueberschreiben!
/*N*/   if (!mbAutoMin)
/*?*/       if ((mbLogarithm && (((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_MIN)).GetValue() != 0.0)) || !mbLogarithm)
/*?*/       mfMin   =((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_MIN)).GetValue();
/*N*/   if (!mbAutoMax)
/*?*/       mfMax   =((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_MAX)).GetValue();
/*N*/   if (!mbAutoOrigin)
/*N*/       mfOrigin=((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_ORIGIN)).GetValue();
/*N*/   if(!mbAutoStep)
/*?*/       mfStep  =((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_STEP_MAIN)).GetValue();
/*N*/   if(!mbAutoStepHelp)
/*?*/       mfStepHelp=((const SvxDoubleItem&) mpAxisAttr->Get(SCHATTR_AXIS_STEP_HELP)).GetValue();
/*N*/
/*N*/ }

/*N*/ void ChartAxis::ReadAutoAttr() //OK
/*N*/ {
/*N*/   mbLogarithm    = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_LOGARITHM)).GetValue();
/*N*/   mbAutoStep     = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_AUTO_STEP_MAIN)).GetValue();
/*N*/   mbAutoStepHelp = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_AUTO_STEP_HELP)).GetValue();
/*N*/   mbAutoMin      = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_AUTO_MIN)).GetValue();
/*N*/   mbAutoMax      = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_AUTO_MAX)).GetValue();
/*N*/   mbAutoOrigin   = ((const SfxBoolItem&) mpAxisAttr->Get(SCHATTR_AXIS_AUTO_ORIGIN)).GetValue();
/*N*/ }

//ToDo: dies Fkt. ueberfluessig machen

/* ************************************************************************
|*
|* Minimum und Maximum berechnen, Wertebereich
|*
|* ToDo: Dies Methode muss komplett auf Verbundcharts umgestellt werden,
    Damit faellt meStackMode weg, es muss fuer jede Reihe geprueft werden,
    wie diese gezeichnet werden soll!
\*********************************************************************** */
/*N*/ inline double ChartAxis::GetRowError(long nRow)
/*N*/ {
/*N*/    switch((SvxChartKindError)((const SfxInt32Item &)mpModel->GetDataRowAttr(nRow).Get(SCHATTR_STAT_KIND_ERROR)).GetValue())
/*N*/   {
/*N*/       case CHERROR_VARIANT :
/*N*/           return mpModel->GetVariantY(nRow);
/*N*/           break;
/*N*/
/*N*/       case CHERROR_SIGMA :
/*N*/           return mpModel->GetSigmaY(nRow);
/*N*/           break;
/*N*/
/*N*/       case CHERROR_BIGERROR :
/*N*/           return mpModel->GetBigErrorY(nRow,
/*N*/               ((const SvxDoubleItem &)mpModel->GetDataRowAttr(nRow).Get(SCHATTR_STAT_BIGERROR)).GetValue());
/*N*/           break;
/*N*/
/*N*/       default :
/*N*/         break;
/*N*/   }
/*N*/    return 0.0;
/*N*/ }
/*N*/ inline BOOL ChartAxis::IsDataOnAxis(long nRow)
/*N*/ {
/*N*/   return(mnUId == ((const SfxInt32Item &)mpModel->GetDataRowAttr(nRow)
/*N*/       .Get(SCHATTR_AXIS)).GetValue()) ;
/*N*/ }

/*N*/ BOOL ChartAxis::GetMinMaxFromData()
/*N*/ {
/*N*/   BOOL bOK=FALSE;
/*N*/
/*N*/   long   nColCnt = mpModel->GetColCount();
/*N*/   long   nRowCnt = mpModel->GetRowCount();
/*N*/   long   nCol,nRow;
/*N*/
/*N*/   BOOL bInitialise=TRUE; //statt dem nCol=0&&nRow=0-Unsinn, damit ungültige Daten berücksichtigt werden
/*N*/
/*N*/   double fMin = 0.0;
/*N*/   double fMax = 0.0;
/*N*/
/*N*/   //Verbundchart Typ 2, letzte Reihe ist Linie, nach switch(meStackMode)
/*N*/   //folgt dann die beruecksichtigung dieser Linie
/*N*/   long nLines = Min((long)mpModel->GetNumLinesColChart(),(long)(nRowCnt-1));;//#50212#
/*N*/
/*N*/   if(mpModel->ChartStyle() == CHSTYLE_2D_LINE_STACKEDCOLUMN)
/*N*/       nRowCnt-=nLines;
/*N*/
/*N*/   switch (meStackMode)
/*N*/   {
/*N*/       //Min = Min(0,Summe aller negativen Daten)
/*N*/       //Max = Max(0,Summe aller positiven Daten)
/*N*/       case CHSTACK_MINMAX:
/*N*/           for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/           {
/*N*/               double fMinTotal = 0.0;
/*N*/               double fMaxTotal = 0.0;
/*N*/
/*N*/               for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/               {
/*N*/
/*N*/                   if(IsDataOnAxis(nRow))
/*N*/                   {
/*N*/                       bOK=TRUE;
/*N*/
/*N*/                       double fData = GetData(nCol, nRow);//mpModel->GetData(nCol, nRow, mbPercent);
/*N*/
/*N*/                       if (fData != DBL_MIN)
/*N*/                       {
/*N*/                           if (fData < 0.0)
/*N*/                               fMinTotal += fData;
/*N*/                           else if (fData > 0.0)
/*N*/                               fMaxTotal += fData;
/*N*/                       }
/*N*/                   }
/*N*/               }
/*N*/
/*N*/               if (nCol == 0) //nicht gut, aber hier kann man sowas machen, irgendne Reihe hat Daten!
/*N*/               {
/*N*/                   fMin = fMinTotal;
/*N*/                   fMax = fMaxTotal;
/*N*/               }
/*N*/               else
/*N*/               {
/*N*/                   if (fMin > fMinTotal)
/*N*/                       fMin = fMinTotal;
/*N*/                   if (fMax < fMaxTotal)
/*N*/                       fMax = fMaxTotal;
/*N*/               }
/*N*/           }
/*N*/           break;
/*N*/
/*N*/       //Min = Min(0,Min(Daten))
/*N*/       //Max = Max(0,Summe aller Daten)
/*N*/       case CHSTACK_OVERLAP:
/*N*/           for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/           {
/*N*/               double fTotal = 0.0;
/*N*/
/*N*/               for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/               {
/*N*/                   if(IsDataOnAxis(nRow))
/*N*/                   {
/*N*/                       bOK=TRUE;
/*N*/
/*N*/                       double rTemp = GetData(nCol, nRow);//mpModel->GetData(nCol, nRow, mbPercent);
/*N*/
/*N*/                       if (rTemp != DBL_MIN)
/*N*/                       {
/*N*/                           if(fMin > rTemp)
/*N*/                              fMin = rTemp;
/*N*/                           fTotal += rTemp;
/*N*/                       }
/*N*/                   }
/*N*/               }
/*N*/
/*N*/               if(fMax < fTotal)
/*N*/                  fMax = fTotal;
/*N*/           }
/*N*/           break;
/*N*/
/*N*/       default:
/*N*/           if (mpModel->IsXYChart ())
/*N*/           {
/*N*/               if(mnId == CHART_AXIS_X)
/*N*/               {
/*N*/                   // here: x axis values are in row 0, so just iterate over col
/*N*/                   for( nCol = 0; nCol < nColCnt; nCol++ )
/*N*/                   {
/*N*/                       double fData = GetData( nCol, 0 );
/*N*/
/*N*/                       if (fData != DBL_MIN)
/*N*/                       {
/*N*/                           if (nCol == 0)    //naja, so eigentlich nicht.... aber die X-Achse sollte eh vollständig sein
/*N*/                           {
/*N*/                               fMin = fData;
/*N*/                               fMax = fData;
/*N*/                           }
/*N*/                           else
/*N*/                           {
/*N*/                               if( (fMin > fData)
/*N*/                               && (!mbLogarithm || fData > 0.0) )
/*N*/                                   fMin = fData;
/*N*/
/*N*/                               if (fMax < fData)
/*N*/                                   fMax = fData;
/*N*/                           }
/*N*/                       }
/*N*/                   }
/*N*/               }
/*N*/               else // y axis
/*N*/               {
/*N*/                   // #69912# use x axis range for determining the auto values for y axis
/*N*/                   ChartAxis* pXAxis = mpModel->GetAxisByUID( CHART_AXIS_PRIMARY_X );
/*N*/                   double fXMin = pXAxis->GetMin();
/*N*/                   double fXMax = pXAxis->GetMax();
/*N*/
/*N*/                   // set min and max to 0/1 resp. in case the x range is empty
/*N*/                   fMin = 0.0;
/*N*/                   fMax = 1.0;
/*N*/
/*N*/                   for (nRow = 1; nRow < nRowCnt; nRow++)
/*N*/                   {
/*N*/                       const SfxItemSet& rDataRowAttr = mpModel->GetDataRowAttr(nRow);
/*N*/                       if(mnUId == ((const SfxInt32Item &)rDataRowAttr.Get(SCHATTR_AXIS)).GetValue())
/*N*/                       {
/*N*/                           bOK=TRUE;
/*N*/
/*N*/                           double fDiffUp   = 0.0;
/*N*/                           double fDiffDown = 0.0;
/*N*/                           fDiffUp=fDiffDown=GetRowError(nRow); // rm1
/*N*/
/*N*/                           for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/                           {
/*N*/                               // #69912#
/*N*/                               double xVal = GetData( nCol, 0 );
/*N*/                               if( fXMin <= xVal && xVal <= fXMax )
/*N*/                               {
/*N*/                                   double fData    = GetData( nCol, nRow );
/*N*/
/*N*/                                   if (fData != DBL_MIN)
/*N*/                                   {
/*N*/                                       double fDataMin = fData;
/*N*/                                       double fDataMax = fData;
/*N*/
/*N*/                                       const SfxItemSet * pDataPointItemSet = mpModel->GetRawDataPointAttr (nCol,nRow);
/*N*/                                       BOOL bDataPointItemSetValid = (pDataPointItemSet!=NULL);
/*N*/
/*N*/                                         const SfxPoolItem * pItem = sch::GetItem(
/*N*/                                             SCHATTR_STAT_KIND_ERROR,
/*N*/                                             rDataRowAttr,
/*N*/                                             *pDataPointItemSet, bDataPointItemSetValid );
/*N*/
/*N*/                                         DBG_ASSERT( pItem != NULL, "Invalid Itemset" );
/*N*/                                         if( pItem != NULL )
/*N*/                                         {
/*N*/                                             switch (static_cast<SvxChartKindError>(
/*N*/                                                         static_cast<const SfxInt32Item&>( *pItem ).GetValue ()))
/*N*/                                             {
/*?*/                                                 case CHERROR_PERCENT :
/*?*/                                                     fDiffUp   =
/*?*/                                                         fDiffDown = fData * static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                           SCHATTR_STAT_PERCENT,
/*?*/                                                             rDataRowAttr,
/*?*/                                                             *pDataPointItemSet, bDataPointItemSetValid)).GetValue ()
/*?*/                                                       / 100.0;
/*?*/                                                     break;
/*?*/
/*?*/                                                 case CHERROR_CONST :
/*?*/                                                     fDiffUp   = fData + static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                           SCHATTR_STAT_CONSTPLUS,
/*?*/                                                             rDataRowAttr,
/*?*/                                                             *pDataPointItemSet, bDataPointItemSetValid)).GetValue ();
/*?*/                                                     fDiffDown = fData + static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                           SCHATTR_STAT_CONSTMINUS,
/*?*/                                                             rDataRowAttr,
/*?*/                                                             *pDataPointItemSet, bDataPointItemSetValid)).GetValue ();
/*N*/                                                     break;
/*N*/
/*N*/                                                 default :
/*N*/                                                     ;
/*N*/                                             }
/*N*/                                         }
/*N*/
/*N*/                                         pItem = sch::GetItem(
/*N*/                                             SCHATTR_STAT_INDICATE,
/*N*/                                             rDataRowAttr,
/*N*/                                             *pDataPointItemSet, bDataPointItemSetValid );
/*N*/
/*N*/                                         DBG_ASSERT( pItem != NULL, "Invalid Itemset" );
/*N*/                                         if( pItem != NULL )
/*N*/                                         {
/*N*/                                             switch (static_cast<SvxChartIndicate>(
/*N*/                                                         static_cast<const SfxInt32Item&>( *pItem ).GetValue ()))
/*N*/                                             {
/*N*/                                                 case CHINDICATE_BOTH :
/*?*/                                                     fDataMin -= fDiffDown;
/*?*/                                                     fDataMax += fDiffUp;
/*?*/                                                     break;
/*?*/
/*?*/                                                 case CHINDICATE_UP :
/*?*/                                                     fDataMax += fDiffUp;
/*?*/                                                     break;
/*?*/
/*?*/                                                 case CHINDICATE_DOWN :
/*?*/                                                     fDataMin -= fDiffDown;
/*?*/                                                     break;
/*N*/
/*N*/                                                 case CHINDICATE_NONE :
/*N*/                                                 default :
/*N*/                                                     ;
/*N*/                                             }
/*N*/                                         }
/*N*/
/*N*/                                       if(bInitialise)
/*N*/                                       {
/*N*/                                           bInitialise=FALSE;
/*N*/                                           fMin = fDataMin;
/*N*/                                           fMax = fDataMax;
/*N*/                                       }
/*N*/                                       else
/*N*/                                       {
/*N*/                                           if ( (fMin > fDataMin)
/*N*/                                                && (!mbLogarithm || fDataMin > 0.0) )
/*N*/                                               fMin = fDataMin;
/*N*/
/*N*/                                           if (fMax < fDataMax)
/*N*/                                               fMax = fDataMax;
/*N*/                                       }
/*N*/                                   }
/*N*/                               }
/*N*/                           }
/*N*/                       }
/*N*/                   }
/*N*/               }
/*N*/           }
/*N*/           else // ! XY-Chart ... Hier landen auch die StockCharts
/*N*/           {
/*N*/               for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/               {
/*N*/                   const SfxItemSet& rDataRowAttr = mpModel->GetDataRowAttr(nRow);
/*N*/                   if(mnUId == ((const SfxInt32Item &)rDataRowAttr.Get(SCHATTR_AXIS)).GetValue())
/*N*/                   {
/*N*/                       bOK=TRUE;
/*N*/
/*N*/                       double fDiffUp   = 0.0;
/*N*/                       double fDiffDown = 0.0;
/*N*/
/*N*/                       fDiffUp=fDiffDown=GetRowError(nRow);//rm3
/*N*/
/*N*/                       for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/                       {
/*N*/                           double fData    = GetData(nCol, nRow);
/*N*/
/*N*/                           if (fData != DBL_MIN)
/*N*/                           {
/*N*/                               double fDataMin = fData;
/*N*/                               double fDataMax = fData;
/*N*/
/*N*/                               const SfxItemSet * pDataPointItemSet = mpModel->GetRawDataPointAttr (nCol,nRow);
/*N*/                               BOOL bDataPointItemSetValid = (pDataPointItemSet!=NULL);
/*N*/
/*N*/                                 const SfxPoolItem * pItem = sch::GetItem(
/*N*/                                     SCHATTR_STAT_KIND_ERROR,
/*N*/                                     rDataRowAttr,
/*N*/                                     *pDataPointItemSet, bDataPointItemSetValid);
/*N*/
/*N*/                                 DBG_ASSERT( pItem != NULL, "Invalid Itemset" );
/*N*/                                 if( pItem != NULL )
/*N*/                                 {
/*N*/                                     switch (static_cast<SvxChartKindError>(
/*N*/                                                 static_cast<const SfxInt32Item&>( *pItem ).GetValue ()))
/*N*/                                     {
/*?*/                                         case CHERROR_PERCENT :
/*?*/                                             fDiffUp   =
/*?*/                                                 fDiffDown = fData * static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                   SCHATTR_STAT_PERCENT,
/*?*/                                                     rDataRowAttr,
/*?*/                                                     *pDataPointItemSet, bDataPointItemSetValid)).GetValue ()
/*?*/                                               / 100.0;
/*?*/                                             break;
/*?*/
/*?*/                                         case CHERROR_CONST :
/*?*/                                             fDiffUp   = fData + static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                   SCHATTR_STAT_CONSTPLUS,
/*?*/                                                     rDataRowAttr,
/*?*/                                                     *pDataPointItemSet, bDataPointItemSetValid)).GetValue ();
/*?*/                                             fDiffDown = fData + static_cast<const SvxDoubleItem&>(*sch::GetItem(
/*?*/                                                   SCHATTR_STAT_CONSTMINUS,
/*?*/                                                     rDataRowAttr,
/*?*/                                                     *pDataPointItemSet, bDataPointItemSetValid)).GetValue ();
/*?*/                                             break;
/*N*/
/*N*/                                         default :
/*N*/                                             ;
/*N*/                                     }
/*N*/                                 }
/*N*/
/*N*/                                 DBG_ASSERT( pItem != NULL, "Invalid Itemset" );
/*N*/                                 pItem = sch::GetItem(
/*N*/                                     SCHATTR_STAT_INDICATE,
/*N*/                                     rDataRowAttr,
/*N*/                                     *pDataPointItemSet, bDataPointItemSetValid );
/*N*/
/*N*/                                 if( pItem != NULL )
/*N*/                                 {
/*N*/                                     switch (static_cast<SvxChartIndicate>(
/*N*/                                                 static_cast<const SfxInt32Item&>( *pItem ).GetValue ()))
/*N*/                                     {
/*?*/                                         case CHINDICATE_BOTH :
/*?*/                                             fDataMin -= fDiffDown;
/*?*/                                             fDataMax += fDiffUp;
/*?*/                                             break;
/*?*/
/*?*/                                         case CHINDICATE_UP :
/*?*/                                             fDataMax += fDiffUp;
/*?*/                                             break;
/*?*/
/*?*/                                         case CHINDICATE_DOWN :
/*?*/                                             fDataMin -= fDiffDown;
/*?*/                                             break;
/*N*/
/*N*/                                         case CHINDICATE_NONE :
/*N*/                                         default :
/*N*/                                             ;
/*N*/                                     }
/*N*/                                 }
/*N*/
/*N*/                               if(bInitialise)
/*N*/                               {
/*N*/                                   bInitialise=FALSE;
/*N*/                                   fMin = fDataMin;
/*N*/                                   fMax = fDataMax;
/*N*/                               }
/*N*/                               else
/*N*/                               {
/*N*/                                   if ((fMin > fDataMin)
/*N*/                                   && (!mbLogarithm ||(fDataMin > 0.0)))
/*N*/                                       fMin = fDataMin;
/*N*/                                   if (fMax < fDataMax)
/*N*/                                       fMax = fDataMax;
/*N*/                               }
/*N*/                           }
/*N*/                       }
/*N*/                   }
/*N*/               }
/*N*/           }
/*N*/
/*N*/       break;
/*N*/   }//switch meStackMode
/*N*/
/*N*/   if (mbPercent)
/*N*/   {
/*N*/       fMin = 0.0;
/*N*/       if (fMax > 100.0)
/*N*/           fMax = 100.0;
/*N*/   }
/*N*/
/*N*/     if( mbAutoMin )
/*N*/         mfMin = fMin;
/*N*/
/*N*/     if( mbAutoMax )
/*N*/         mfMax = fMax;
/*N*/
/*N*/   return bOK;
/*N*/ }

//Ab jetzt wird die Achse gebaut, die meisten Werte  können nicht mehr geändert werden,
//da wir uns im BuildChart (genauer: zumeist in Create<n>DBackplanes) befinden.
//allerdings wird die Area noch verändert. Davn unabhängige Werte, z.B. Items können
//in Variablen gebuffert werden
/*N*/ void ChartAxis::Initialise(const Rectangle &rRect,BOOL bFlippedXY
/*N*/                          ,long eStackmode,BOOL bPercent
/*N*/                          ,BOOL bRadial,BOOL bPercentCol)
/*N*/
/*N*/ {
/*N*/   mnMaxTextWidth=-1;
/*N*/   mbInnerPos=FALSE;
/*N*/   mbAlternativIdUsed=FALSE;
/*N*/   mbTextOverlap= ((const SfxBoolItem&)mpAxisAttr->Get(SCHATTR_TEXT_OVERLAP)).GetValue();
/*N*/   mbPercentCol=bPercentCol;
/*N*/   mbPercent=bPercent;
/*N*/   maArea=rRect;
/*N*/   mbFlippedXY=bFlippedXY;
/*N*/   meStackMode=eStackmode;
/*N*/   mbRadial=bRadial;
/*N*/   mbShowDescr=HasDescription();
/*N*/
/*N*/   mbColStackOK=FALSE;     //noch nix gestapelt, noch nicht initialisiert
/*N*/   mbTotalActual=FALSE; //anzahl cols/daten könnten verändert sein!
/*N*/   mbTotalAlloc =FALSE; //anzahl cols/daten könnten verändert sein!
/*N*/
/*N*/   mpMainGridList=NULL;
/*N*/   mpHelpGridList=NULL;
/*N*/   mpAxisList=NULL;
/*N*/
/*N*/   //Atribute auslesen, etwas Overhead, ToDo: optimieren
/*N*/   ReadAutoAttr();
/*N*/   ReadAttr();
/*N*/   // #84601# set Min/Max etc. at the local item set!
/*N*/   if( mpAxisAttr )
/*N*/       GetMembersAsAttr( *mpAxisAttr );
/*N*/ };

/*N*/ void ChartAxis::GetMembersAsAttr(SfxItemSet& rSet) const
/*N*/ {
/*N*/   rSet.Put(SfxUInt32Item(SID_ATTR_NUMBERFORMAT_VALUE,((ChartAxis*)this)->GetNumFormat()));
/*N*/   rSet.Put(SvxDoubleItem(mfMin        , SCHATTR_AXIS_MIN));
/*N*/   rSet.Put(SvxDoubleItem(mfMax        , SCHATTR_AXIS_MAX));
/*N*/   rSet.Put(SvxDoubleItem(mfStep       , SCHATTR_AXIS_STEP_MAIN));
/*N*/   rSet.Put(SvxDoubleItem(mfStepHelp   , SCHATTR_AXIS_STEP_HELP));
/*N*/   rSet.Put(SvxDoubleItem(mfOrigin     , SCHATTR_AXIS_ORIGIN));
/*N*/ }

/*N*/ void ChartAxis::CalcMinMaxValue()
/*N*/ {
/*N*/
/*N*/   if (mbAutoMin || mbAutoMax) //Dann alle Werte generieren
/*N*/   {
/*N*/       if(!GetMinMaxFromData() && mnAlternateId && /*#63904#:*/(IsVisible()||HasDescription()))
/*N*/       {
/*?*/           long tmp=mnUId;
/*?*/           mnUId=mnAlternateId;
/*?*/           GetMinMaxFromData();
/*?*/           mbAlternativIdUsed=TRUE;
/*?*/           mnUId=tmp;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (mfMin > mfMax) //ToDo: Korrektur, sollte aber ueberfluessig sein
/*N*/   {
/*?*/       double fTemp = mfMin;
/*?*/       mfMin=mfMax;
/*?*/       mfMax=fTemp;
/*N*/   }
/*N*/
/*N*/   ReadAttr();    //Alle nicht-automatischen Wertze werden jetzt geholt
/*N*/
/*N*/   if ((mfMin != DBL_MIN) || (mfMax != DBL_MIN))
/*N*/   {
/*N*/       if (mfMin > mfMax) //noch ne Korrektur, diese ist aber noetig!
/*N*/       {
/*?*/             if( mbAutoMax )
/*?*/                 mfMax = mfMin;
/*?*/             else if( mbAutoMin )
/*?*/                 mfMin = mfMax;
/*?*/             else
/*?*/             {
/*?*/                 OSL_FAIL( "Minimum is greater than Maximum" );
/*?*/                 double fTemp = mfMin;
/*?*/
/*?*/                 mfMin = mfMax;
/*?*/                 mfMax = fTemp;
/*?*/             }
/*N*/       }
/*N*/
/*N*/       if (mbLogarithm)
/*N*/       {
/*?*/           if (mbAutoMin)
/*?*/           {
/*?*/               if (mfMin > 1.0)
/*?*/               {
/*?*/                   double fVal = 1.0;
/*?*/
/*?*/                   while (fVal < mfMin)
/*?*/                       fVal *= 10.0;
/*?*/
/*?*/                   if (fVal > mfMin) fVal /= 10.0;
/*?*/                   mfMin = fVal;
/*?*/               }
/*?*/               else if (mfMin > 0.0)
/*?*/                    {
/*?*/                        double fVal = 1.0;
/*?*/
/*?*/                        while (fVal > mfMin)
/*?*/                            fVal /= 10.0;
/*?*/
/*?*/                        mfMin = fVal;
/*?*/                    }
/*?*/                    else mfMin = 1.0;
/*?*/           }
/*?*/
/*?*/           if (mbAutoMax)
/*?*/           {
/*?*/               if (mfMax > 1.0)
/*?*/               {
/*?*/                   double fVal = 1.0;
/*?*/
/*?*/                   while (fVal < mfMax)
/*?*/                       fVal *= 10.0;
/*?*/
/*?*/                   mfMax = fVal;
/*?*/               }
/*?*/               else if (mfMax > 0.0)
/*?*/                    {
/*?*/                        double fVal = 1.0;
/*?*/
/*?*/                        while (fVal > mfMax)
/*?*/                            fVal /= 10.0;
/*?*/
/*?*/                        if (fVal < mfMax) fVal *= 10.0;
/*?*/                        mfMax = fVal;
/*?*/                    }
/*?*/                    else mfMax = 1.0;
/*?*/           }
/*?*/
/*?*/           if (mfMax - mfMin == 0.0) mfMax = mfMin * 10.0;
/*?*/           if (mfOrigin != mfMin) mfOrigin = mfMin;
/*?*/       }
/*N*/       else
/*N*/       {
/*N*/           if ((!mpModel->IsNegativeChart() && (mfMin < 0.0)) ||
/*N*/               (mbAutoMin && (mfMin > 0.0))) mfMin = SizeBounds (mfMin, mfMax, FALSE);
/*N*/           if (mbAutoMax && (mfMax < 0.0)) mfMax = SizeBounds (mfMin, mfMax, TRUE);
/*N*/
/*N*/           if (mfMax - mfMin == 0.0) mfMax = mfMin + 1.0;
/*N*/
/*N*/           if (mbAutoOrigin)
/*N*/           {
/*N*/               mfOrigin = 0.0;
/*N*/               if (mfOrigin < mfMin) mfOrigin = mfMin;
/*N*/               else if (mfOrigin > mfMax) mfOrigin = mfMax;
/*N*/           }
/*N*/           else
/*N*/           {
/*N*/               if (mfOrigin < mfMin) mfMin = mfOrigin;
/*N*/               if (mfOrigin > mfMax) mfMax = mfOrigin;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/* ************************************************************************
|*
|* Faktor fuer Koordinaten-Multiplikation berechnen
|* abart der globalen Funktion mit den ChartAxis-Membervariablen
|*
\*********************************************************************** */
/*N*/ void ChartAxis::LoadMemberCompat(SvStream& rIn)
/*N*/ {
/*N*/   rIn >> mfMin;
/*N*/   rIn >> mfMax;
/*N*/   rIn >> mfStep;
/*N*/   rIn >> mfStepHelp;
/*N*/   rIn >> mfOrigin;
/*N*/
/*N*/
/*N*/   mpAxisAttr->Put(SvxDoubleItem(mfMin     , SCHATTR_AXIS_MIN));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(mfMax     , SCHATTR_AXIS_MAX));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(mfStep        , SCHATTR_AXIS_STEP_MAIN));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(mfStepHelp    , SCHATTR_AXIS_STEP_HELP));
/*N*/   mpAxisAttr->Put(SvxDoubleItem(mfOrigin      , SCHATTR_AXIS_ORIGIN));
/*N*/
/*N*/   CHART_TRACE2( "ChartAxis::LoadMemberCompat min=%lf, max=%lf", mfMin, mfMax );
/*N*/   CHART_TRACE3( "... step=%lf, help=%lf, origin=%lf", mfStep, mfStepHelp, mfOrigin );
/*N*/ }

/*N*/ void ChartAxis::StoreMemberCompat(SvStream& rOut) const
/*N*/ {
/*N*/   rOut << mfMin;
/*N*/   rOut << mfMax;
/*N*/   rOut << mfStep;
/*N*/   rOut << mfStepHelp;
/*N*/   rOut << mfOrigin;
/*N*/ }
//ToDo: nLen ist maArea.Width(),Height, oder das ganze bei NetChart /2 (vermutlich)
/*N*/ long ChartAxis::GetLength() const
/*N*/ {
/*N*/   if(mbRadial)//&& Achse=Y (ist aber immer so bei NetCharts)
/*N*/       return maArea.GetHeight () / 2;
/*N*/
/*N*/   switch(mnId)
/*N*/   {
/*N*/       case CHART_AXIS_X:
/*N*/           return mbFlippedXY ? maArea.GetHeight() : maArea.GetWidth();
/*N*/           break;
/*N*/       case CHART_AXIS_Y:
/*N*/           return mbFlippedXY ? maArea.GetWidth() : maArea.GetHeight();
/*N*/           break;
/*N*/       case CHART_AXIS_Z:
/*N*/           return (maArea.GetWidth() * 4) / 6; //ToDo: Das hier ist doch quark... kein Flipped?:;
/*N*/           break;
/*N*/   }
/*?*/   OSL_FAIL("ChartAxis::GetLenght() implementation error - ZAxis failure");
/*?*/   return maArea.GetWidth();
/*N*/ }




/**
    @descr  Calculate the size of the bounding box of a text string.  The size
            is measured with respect to the coordinate axes.

    @param  rTextAttr   Attributes of the font to use.
    @param  aString     The "typical" description.

    @return Returns the size of the bounding box of the text.
*/
/*N*/ Size  ChartAxis::CalcDescriptionSize  (const SfxItemSet * rTextAttr,
/*N*/                                       const String & aString)
/*N*/ {
/*N*/   //  Get output device, store old page size and set paper size to
/*N*/   //  maximal size to inhibit line breaks.
/*N*/   Outliner    *   pOutliner = mpModel->GetOutliner();
/*N*/   pOutliner->SetUpdateMode (FALSE);
/*N*/   Size    aOldPaperSize (pOutliner->GetPaperSize());
/*N*/   pOutliner->SetPaperSize (Size (100000,100000)); //  Maximal paper size ?
/*N*/
/*N*/   //  Save first paragraphs attributes, switch off hyphenation, and
/*N*/   //  set the font attributes.
/*N*/   SfxItemSet aOldAttr (pOutliner->GetParaAttribs(0));
/*N*/   SfxItemSet aNewAttr (aOldAttr);
/*N*/   aNewAttr.Put (SfxBoolItem(EE_PARA_HYPHENATE, FALSE));
/*N*/   aNewAttr.Put (*rTextAttr);
/*N*/   mpModel->SetTextAttributes (aNewAttr);
/*N*/
/*N*/     // synchronize item with member
/*N*/   meTextOrient = ((const SvxChartTextOrientItem&)
/*N*/       mpAxisAttr->Get(SCHATTR_TEXT_ORIENT)).GetValue();
/*N*/     //    Determine the size of the texts bounding box.
/*N*/   if ( meTextOrient != CHTXTORIENT_STACKED)
/*N*/       pOutliner->SetText(aString, pOutliner->GetParagraph (0));
/*N*/   pOutliner->SetUpdateMode (TRUE);
/*N*/   Size aSize = pOutliner->CalcTextSize();
/*N*/     // remove content and attributes
/*N*/     pOutliner->Clear();
/*N*/   pOutliner->SetUpdateMode (FALSE);
/*N*/
/*N*/   //  Restore the old font and old paper size.
/*N*/   mpModel->SetTextAttributes (aOldAttr);
/*N*/   pOutliner->SetPaperSize (aOldPaperSize);
/*N*/   pOutliner->SetUpdateMode (TRUE);
/*N*/
/*N*/   return (aSize);
/*N*/ }




/**
    @descr  Calculate the expected size of a "typical" description.  The size
            is measured along the axis.  The axis orientation is taken into
            account.
    @precond CalcMinMaxValue() has to have been called already.

    @param  rAttr   Attributes of the font to use.

    @return Returns the size of the text projected onto the axis.
*/
/*N*/ long int  ChartAxis::CalcTypicalDescriptionSize   (const SfxItemSet * rAttr)
/*N*/ {
/*N*/   String      aString;
/*N*/   Color   *   pDummy = NULL;
/*N*/   Size        aSize,
/*N*/               aMaxSize;
/*N*/
/*N*/   //  As typical text we use the minimum and maximum and some randomly
/*N*/   //  chose value in between.  This relies on a previous call to
/*N*/   //  CalcMinMaxValue().
/*N*/   mpNumFormatter->GetOutputString (mfMin, GetNumFormat(), aString, &pDummy);
/*N*/   aMaxSize = CalcDescriptionSize (rAttr, aString);
/*N*/
/*N*/   mpNumFormatter->GetOutputString (mfMax, GetNumFormat(), aString, &pDummy);
/*N*/   aSize = CalcDescriptionSize (rAttr, aString);
/*N*/   if (aSize.Width() > aMaxSize.Width())
/*N*/       aMaxSize.Width() = aSize.Width();
/*N*/   if (aSize.Height() > aMaxSize.Height())
/*?*/       aMaxSize.Height() = aSize.Height();
/*N*/
/*N*/   double  fPos = 0.53,    //  Arbitrary position between mfMin and mfMax.
/*N*/           fValue = (1-fPos) * mfMin + fPos * mfMax;
/*N*/   mpNumFormatter->GetOutputString (fValue, GetNumFormat(), aString, &pDummy);
/*N*/   aSize = CalcDescriptionSize (rAttr, aString);
/*N*/   if (aSize.Width() > aMaxSize.Width())
/*N*/       aMaxSize.Width() = aSize.Width();
/*N*/   if (aSize.Height() > aMaxSize.Height())
/*?*/       aMaxSize.Height() = aSize.Height();
/*N*/
/*N*/   //  Select the right coordinate and return it.
/*N*/   if (IsVertical())
/*N*/       return (aMaxSize.Height());
/*N*/   else
/*N*/       return (aMaxSize.Width());
/*N*/ }


/**
    @descr  Calculate the intervall delimited by mfMin and mfMax for which
            tick marks are drawn, its origin (mfOrigin), which is either zero
            if inside the intervall or mfMin or mfMax otherwise.  The
            distance between two adjacent tick marks of the main grid is
            stored into mfStep and the distance for the help grid into
            mfStepHelp.
*/
/*N*/ void  ChartAxis::CalcValueSteps   (void)
/*N*/ {
/*N*/   long nLen=GetLength();
/*N*/
/*N*/   ReadAutoAttr(); //mbAuto* aus mpAxisAttr lesen
/*N*/
/*N*/   CalcMinMaxValue(); //Min und Max bestimmen
/*N*/
/*N*/   if (mfMax == DBL_MIN)
/*N*/   {
/*N*/       mfMax       =
/*N*/       mfOrigin    =
/*N*/       mfMin       =
/*N*/       mfStep      =
/*N*/       mfStepHelp  =  0.0;
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       double  fRange = mfMax-mfMin,
/*N*/               fApproximateDescriptionSize
/*N*/                   = 2.5 * CalcTypicalDescriptionSize(mpAxisAttr);
/*N*/                   //  former value: (mpModel->GetLineHeight(*mpAxisAttr) * 3)
/*N*/       long    nMaxSteps = (long int)(nLen / fApproximateDescriptionSize);
/*N*/
/*N*/       if (mbLogarithm)
/*N*/       {
/*N*/           if (mbAutoStep)
/*N*/               mfStep = 10.0;
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           if (mbAutoStep)
/*N*/           {
/*N*/               //  Find smallest power of 10 lower than or equal to fRange,
/*N*/               //  that scales fFactor into the interval [1,10].
/*N*/               double  fFactor = pow ((double)10, floor (log10 (fRange)));
/*N*/               fRange /= fFactor;
/*N*/
/*N*/               //  Calculate mfStep so that the number of divisions (nSteps)
/*N*/               //  is 'not much' higher than nMaxSteps.  The value of nSteps
/*N*/               //  is increased succesively to multiples of 2*10^k, 4*10^k,
/*N*/               //  5*10^k, and 10*10^k, with k>=0.
/*N*/               long nSteps = 1;
/*N*/               mfStep = 10.0;
/*N*/               if (nSteps < nMaxSteps)
/*N*/               {
/*N*/                   short nDepth = 0;
/*N*/
/*N*/                   do
/*N*/                   {
/*N*/                       if (nDepth % 4 == 2) mfStep = mfStep * 4.0 / 5.0;
/*N*/                       else mfStep /= 2.0;
/*N*/
/*N*/                       nSteps = (long)(fRange / mfStep);
/*N*/                       nDepth++;
/*N*/                   }
/*N*/                   while (nSteps < nMaxSteps);
/*N*/               }
/*N*/               else
/*N*/               {
/*N*/                   if (mfStep > fRange)
/*N*/                   {
/*N*/                       short  nDepth = 0;
/*N*/                       double fStep  = mfStep;
/*N*/
/*N*/                       do
/*N*/                       {
/*N*/                           if (nDepth % 4 == 2) fStep = fStep * 4.0 / 5.0;
/*N*/                           else fStep /= 2.0;
/*N*/
/*N*/                           if (fStep >= fRange) mfStep = fStep;
/*N*/
/*N*/                           nDepth++;
/*N*/                       }
/*N*/                       while (fStep > fRange);
/*N*/                   }
/*N*/               }
/*N*/               mfStep *= fFactor;
/*N*/
/*N*/               //  Special treatment for dates and times.
/*N*/               short int   nNumberFormat = mpNumFormatter->GetType (
/*N*/                   GetNumFormat());
/*N*/               BOOL        bIsDate = (nNumberFormat & NUMBERFORMAT_DATE) != 0;
/*N*/               BOOL        bIsTime = (nNumberFormat & NUMBERFORMAT_TIME) != 0;
/*N*/               //  At the moment the only special case is this:
/*N*/               //  Dates without time are spaced whole days apart.
/*N*/               if (bIsDate && ! bIsTime)
/*N*/               {
/*N*/                   mfStep = ceil(mfStep);
/*N*/                   if (mfStep < 1)
/*N*/                       mfStep = 1;
/*N*/               }
/*N*/           }
/*N*/
/*N*/             //    Make sure that the step width is positive and not equal to
/*N*/             //    zero.
/*N*/           if ((mfStep<0) || (mfMin+mfStep==mfMin) || (mfMax+mfStep==mfMax))
/*N*/           {
/*N*/               OSL_FAIL( "Decrement of <= 0.0 not allowed" );
/*N*/               mfStep = 1.0;             // to prevent loop
/*N*/           }
/*N*/
/*N*/           if (mbAutoMin)
/*N*/           {
/*N*/               double fMin = 0.0;
/*N*/
/*N*/               //  Adjust mfMin to the largest value that is lower than or
/*N*/               //  equal to its current value and is an integer multiple of
/*N*/               //  mfSteps away of fMin.
/*N*/               if (fMin > mfMin)
/*N*/                   mfMin = fMin - mfStep * ceil((fMin - mfMin) / mfStep);
/*N*/               else if (fMin < mfMin)
/*N*/                   mfMin = fMin + mfStep * floor((mfMin - fMin) / mfStep);
/*N*/
/*N*/               if ((mfMin >= 0.0) && (mfMin < mfOrigin))
/*N*/                   mfOrigin = mfMin;
/*N*/           }
/*N*/
/*N*/           if (mbAutoMax)
/*N*/           {
/*N*/               double fMax = 0.0;
/*N*/
/*N*/               //  Adjust mfMax to the smallest value that is higher than or
/*N*/               //  equal to its current value and is an integer multiple of
/*N*/               //  mfSteps away of fMax.
/*N*/               if (fMax < mfMax)
/*N*/                   mfMax = fMax + mfStep * ceil((mfMax - fMax) / mfStep);
/*N*/               else if (fMax > mfMax)
/*N*/                   mfMax = fMax - mfStep * floor ((fMax - mfMax) / mfStep);
/*N*/
/*N*/               if ((mfMax <= 0.0) && (mfMax > mfOrigin))
/*N*/                   mfOrigin = mfMax;
/*N*/           }
/*N*/       }
/*N*/
/*N*/       if(mbAutoStepHelp)
/*N*/       {
/*N*/           mfStepHelp = mbLogarithm ? (mfStep / 10) : (mfStep / 2);
/*N*/       }
/*N*/       VerifySteps();
/*N*/   }
/*N*/
/*N*/ }


/*N*/ void ChartAxis::VerifySteps()
/*N*/ {
/*N*/   //#38835# Sicherheitsueberpruefung der Werte, es werden beide Achsen gleichbehandelt
/*N*/   //Es sollte nur mit Double gerechnet werden da bei Fehlern der Bereich nicht reicht
/*N*/   //(deshalb double nVarName,
/*N*/   //ToDo: GetLenght benutzen! Wir kennen ja in dieser Klasse mittlerweile die Laenge
/*N*/
/*N*/   double fRange=(mfMax - mfMin);
/*N*/
/*N*/   double nLimit=Max(maArea.GetWidth(),maArea.GetHeight());
/*N*/
/*N*/   if(nLimit < 0.0)
/*N*/   {
/*?*/       OSL_FAIL( "negative value for nLimit, check maArea!" );
/*?*/       nLimit=1.0;
/*N*/   }
/*N*/   nLimit=nLimit/100.0; //Minimum 1 mm Abstand
/*N*/
/*N*/   if(nLimit && !mbLogarithm)
/*N*/   {
/*N*/       if(mfStep!=0.0 )
/*N*/       {
/*N*/           double fSteps=fRange/mfStep;
/*N*/           while(fSteps>nLimit)
/*N*/           {
/*?*/               mfStep*=10;
/*?*/               fSteps=fRange / mfStep;
/*N*/           }
/*N*/       }
/*N*/       nLimit*=10; //Min fuer Hilfsticks: 0,1 mm bzw. 10 Hilfsticks immer moeglich
/*N*/
/*N*/       if(mfStepHelp!=0.0)
/*N*/       {
/*N*/           double fSteps=fRange/mfStepHelp;
/*N*/           while(fSteps>nLimit)
/*N*/           {
/*?*/               mfStepHelp*=10;
/*?*/               fSteps=fRange/mfStepHelp;
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ long ChartAxis::GetPos(double fData)
/*N*/ {
/*N*/   switch(mnId)
/*N*/   {
/*N*/       case CHART_AXIS_X:
/*N*/           if(mbFlippedXY)
/*N*/               return maRefArea.Bottom() - (long)(CalcFact(fData) * maRefArea.GetHeight());
/*N*/           else
/*N*/               return maRefArea.Left()   + (long)(CalcFact(fData) * maRefArea.GetWidth());
/*N*/
/*N*/       case CHART_AXIS_Y:
/*N*/           if(!mbFlippedXY)
/*N*/               return maRefArea.Bottom() - (long)(CalcFact(fData) * maRefArea.GetHeight());
/*N*/           else
/*N*/               return maRefArea.Left() +   (long)(CalcFact(fData) * maRefArea.GetWidth());
/*N*/
/*N*/       case CHART_AXIS_Z:
/*?*/           OSL_FAIL("ChartAxis - no z pos");
/*N*/   }
/*N*/   return 0;
/*N*/ }
/*N*/ BOOL ChartAxis::SetArea(const Rectangle &rRect)
/*N*/ {
/*N*/   BOOL bRet=TRUE;
/*N*/   if(rRect==maRefArea)
/*N*/       bRet=FALSE;
/*N*/   maRefArea=rRect;
/*N*/
/*N*/   SetPosition(mbSecondary ? CHAXIS_POS_B :CHAXIS_POS_A);
/*N*/
/*N*/ #ifdef DBG_UTIL
/*N*/   if(maArea!=maRefArea)
/*N*/       OSL_TRACE("ChartAxis:: maArea!=maRefArea!!!");
/*N*/ #endif
/*N*/   return bRet;
/*N*/ }



/* ************************************************************************
|*
|* Liefert die maximale Werte-Text-Gr”áe
|*
\*********************************************************************** */
/*N*/ Size ChartAxis::CalcMaxTextSize()
/*N*/ {
/*N*/   return CalcMaxTextSize(((const SvxChartTextOrientItem&)mpAxisAttr->Get(SCHATTR_TEXT_ORIENT)).GetValue());
/*N*/ }

/*N*/ Size ChartAxis::CalcMaxTextSize(SvxChartTextOrient eOrient)
/*N*/ {
/*N*/   meTextOrient = eOrient;
/*N*/   maMaxTextSize=Size(0,0);
/*N*/
/*N*/   if(!mbShowDescr)
/*N*/       return maMaxTextSize;
/*N*/
/*N*/   BOOL bStepIsValid = mbLogarithm ? (mfStep > 1.0) : (mfStep > 0.0);
/*N*/
/*N*/   if( mfMin != mfMax && bStepIsValid )
/*N*/   {
/*N*/       OutputDevice *pOut = mpModel->GetOutliner()->GetRefDevice();
/*N*/       Font aNewFont;
/*N*/       ItemsToFont(*mpAxisAttr,aNewFont);
/*N*/       Font aOldFont(pOut->GetFont());
/*N*/       pOut->SetFont(aNewFont);
/*N*/
/*N*/       double fAct = mfMin;
/*N*/
/*N*/         if( ::rtl::math::isInf( mfMax ) || ::rtl::math::isInf( mfMin ))
/*N*/         {
/*N*/             OSL_FAIL( "maximum or minumum is infinity" );
/*N*/         }
/*N*/         else
/*N*/         {
/*N*/             while (fAct <= mfMax)
/*N*/             {
/*N*/                 String aNumStr;
/*N*/                 Color* pDummy = NULL;
/*N*/
/*N*/                 if(mbColText)
/*N*/                 {
/*N*/                     long nCol = long(fAct);
/*N*/                     if(nCol<mpModel->GetColCount())
/*N*/                         aNumStr=mpModel->ColText(nCol);
/*N*/                 }
/*N*/                 else
/*N*/                 {
/*N*/                     mpNumFormatter->GetOutputString(mbPercent ? fAct / 100.0: fAct,
/*N*/                                                     GetNumFormat(), aNumStr, &pDummy);
/*N*/                 }
/*N*/
/*N*/                 Size aSize;
/*N*/                 if (meTextOrient == CHTXTORIENT_STACKED)
/*N*/                 {
/*?*/                     aSize.Width() = pOut->GetTextWidth( ::binfilter::StackString( aNumStr ));
/*?*/                     aSize.Height() = pOut->GetTextHeight();
/*N*/                 }
/*N*/                 else
/*N*/                 {
/*N*/                     aSize.Width() = pOut->GetTextWidth( aNumStr );
/*N*/                     aSize.Height() = pOut->GetTextHeight();
/*N*/                 }
/*N*/
/*N*/                 aSize.Height() += TEXTHEIGHT_OFS;
/*N*/                 aSize.Width () = (aSize.Width () * 6) / 5;
/*N*/
/*N*/                 if (aSize.Width() > maMaxTextSize.Width())
/*N*/                     maMaxTextSize.Width() = aSize.Width();
/*N*/                 if (aSize.Height() > maMaxTextSize.Height())
/*N*/                     maMaxTextSize.Height() = aSize.Height();
/*N*/
/*N*/                 IncValue(fAct, mfStep, mbLogarithm);
/*N*/             }
/*N*/             maMaxTextSize = GetRotatedTextSize( maMaxTextSize,
/*N*/                                 GetTextRotation( *mpAxisAttr, meTextOrient ));
/*N*/         }
/*N*/
/*N*/       //Evtl. muss hier noch ein Umbruch eingeplant werden!
/*N*/
/*N*/       pOut->SetFont(aOldFont);
/*N*/   }
/*N*/   RecalcTextPos();
/*N*/   return maMaxTextSize;
/*N*/ }

/*N*/ void ChartAxis::RecalcTextPos()
/*N*/ {
/*N*/   //Textabstand:
/*N*/   long nExtra = -100; //+1mm
/*N*/   if((mbSecondary && IsVertical()) || (!mbSecondary && !IsVertical()))
/*N*/       nExtra=100;
/*N*/
/*N*/   if(mnTicks&CHAXIS_MARK_OUTER)
/*N*/   {
/*N*/       mnTextPos = mnPos + nExtra + mnTickLen; //LONGMARKS;
/*N*/   }
/*N*/   else
/*N*/   {
/*?*/       mnTextPos = mnPos + nExtra;
/*?*/
/*?*/       if(mnHelpTicks&CHAXIS_MARK_OUTER)
/*?*/           mnTextPos +=mnHelpTickLen;
/*N*/   }
/*N*/ }

/*N*/ void ChartAxis::SetPosition(long nPos)
/*N*/ {
/*N*/   mbSecondary=(BOOL)(nPos==CHAXIS_POS_B);
/*N*/
/*N*/   if(nPos<0)
/*N*/   {
/*N*/       if(IsVertical())
/*N*/       {
/*N*/           if(mbSecondary)
/*N*/               mnPos=maRefArea.Right();
/*N*/           else
/*N*/               mnPos=maRefArea.Left();
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           if(mbSecondary)
/*N*/               mnPos=maRefArea.Top();
/*N*/           else
/*N*/               mnPos=maRefArea.Bottom();
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       mnPos=nPos;
/*N*/   }
/*N*/
/*N*/   RecalcTextPos();
/*N*/ }

//Wenn Ticks nach innen und/oder nach aussen gerichtet sind, wird ein SdrObject returned,
//sollen in keine Richtung Ticks gezeichnet werden, gbts den Nullpointer zurück
/*N*/ SdrObject *ChartAxis::CreateMarks(long nPosition,long nLen,long nWhichTicks)
/*N*/ {
/*N*/   XPolygon saLine(2);
/*N*/
/*N*/   long nLen2=(nWhichTicks&CHAXIS_MARK_INNER) ? nLen : 0;
/*N*/
/*N*/   if(!(nWhichTicks&CHAXIS_MARK_OUTER))
/*N*/       nLen=0;
/*N*/
/*N*/   if(!nLen && !nLen2)
/*N*/       return NULL;
/*N*/
/*N*/   if(IsVertical())
/*N*/   {
/*N*/       saLine[0].X() = mnPos + nLen;
/*N*/       saLine[1].X() = mnPos - nLen2;
/*N*/       saLine[0].Y() = saLine[1].Y() = nPosition;
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       saLine[0].Y() = mnPos + nLen;
/*N*/       saLine[1].Y() = mnPos - nLen2;
/*N*/       saLine[0].X() = saLine[1].X() = nPosition;
/*N*/   }
/*N*/
/*N*/   return SetObjectAttr (new SdrPathObj(OBJ_PLIN,saLine),CHOBJID_LINE,TRUE,TRUE,mpAxisAttr);
/*N*/ }
/*N*/ void ChartAxis::CreateMarkDescr(double fData,long nPosition)
/*N*/ {
/*N*/   String aNumStr;
/*N*/   Color* pTextColor = NULL;
/*N*/
/*N*/   if(mbColText)
/*N*/   {
/*N*/       long nCol = long(fData);
/*N*/       long nColCnt=mpModel->GetColCount();
/*N*/       if(IsVertical())
/*N*/           nCol=nColCnt-nCol; //andere Reihenfolge wegen Bildschirmkoordinaten
/*N*/
/*N*/       if(nCol<nColCnt && nCol>=0)
/*N*/           CreateMarkDescr(mpModel->ColText(nCol) ,nPosition, pTextColor);
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       mpNumFormatter->GetOutputString(mbPercent ? fData/100.0:fData,GetNumFormat()
/*N*/           ,aNumStr,&pTextColor);
/*N*/       CreateMarkDescr(aNumStr, nPosition, pTextColor);
/*N*/   }
/*N*/
/*N*/ }

// BM #60999# new parameter pTextColor, if using red text for negative numbers
/*N*/ void ChartAxis::CreateMarkDescr(const String& rString, long nPosition, Color *pTextColor)
/*N*/ {
/*N*/   SvxColorItem* pOldTextColor = NULL;
/*N*/
/*N*/   if(!mpTextAttr)
/*N*/   {
/*?*/       OSL_FAIL("ChartAxis: description uninitialised!!!!");
/*?*/       CreateTextAttr();
/*N*/   }
/*N*/
/*N*/   if( pTextColor )
/*N*/   {
/*?*/       pOldTextColor = (SvxColorItem*)mpTextAttr->GetItem( EE_CHAR_COLOR );
/*?*/       mpTextAttr->Put(SvxColorItem( *pTextColor ));
/*N*/   }
/*N*/
/*N*/   //Bei z.B. Barcharts ist der Text verschoben (sozusagen unter der Hilfsmarkierung)
/*N*/   long nTextOffset=0;
/*N*/   if(!mbCenterText && mbColText)
/*N*/       nTextOffset+=GetDescrWidth()/2;
/*N*/
/*N*/   ChartAdjust eAdj;
/*N*/   SdrRectObj *pText=NULL;
/*N*/   if(IsVertical())
/*N*/   {
/*N*/       Point aPos(mnTextPos,nPosition+nTextOffset);
/*N*/       if(mbStepValue)
/*N*/       {
/*?*/           if(mbValueDown)
/*?*/           {
/*?*/               if(mbSecondary)
/*?*/                   aPos.X() += maMaxTextSize.Width();
/*?*/               else
/*?*/                   aPos.X() -= maMaxTextSize.Width();
/*?*/           }
/*?*/           mbValueDown = !mbValueDown;
/*N*/       }
/*N*/       eAdj = mbSecondary ? CHADJUST_CENTER_LEFT : CHADJUST_CENTER_RIGHT;
/*N*/       pText=mpModel->CreateTextObj(CHOBJID_TEXT,aPos,rString,*mpTextAttr,FALSE,eAdj,mnMaxTextWidth);
/*N*/   }
/*N*/   else //horizontal
/*N*/   {
/*N*/       Point aPos(nPosition+nTextOffset,mnTextPos);
/*N*/       if (mbStepValue)
/*N*/       {
/*?*/           if(mbValueDown)
/*?*/           {
/*?*/               if(mbSecondary)
/*?*/                   aPos.Y() -= maMaxTextSize.Height();
/*?*/               else
/*?*/                   aPos.Y() += maMaxTextSize.Height();
/*?*/           }
/*?*/           mbValueDown = !mbValueDown;
/*N*/       }
/*N*/       eAdj = mbSecondary ? CHADJUST_BOTTOM_CENTER : CHADJUST_TOP_CENTER;
/*N*/       pText=mpModel->CreateTextObj(CHOBJID_TEXT,aPos,rString,*mpTextAttr,FALSE,eAdj,mnMaxTextWidth);
/*N*/   }
/*N*/
/*N*/   if( pOldTextColor )
/*N*/   {
/*?*/       mpTextAttr->Put(*pOldTextColor);
/*N*/   }
/*N*/
/*N*/   CreateMarkDescr(pText,nPosition);
/*N*/ }
/*N*/ void ChartAxis::CreateMarkDescr(SdrRectObj *pTextObj,long nPosition)
/*N*/ {
/*N*/   if(pTextObj && mpAxisList )
/*N*/   {
/*N*/       Rectangle aTextBoundRect(pTextObj->GetBoundRect());
/*N*/       Rectangle aIntersect1(maRectA);
/*N*/       Rectangle aIntersect2(maRectB);
/*N*/
/*N*/       if(!mbTextOverlap && ! (aIntersect1.Intersection(aTextBoundRect).IsEmpty() &&
/*N*/             aIntersect2.Intersection(aTextBoundRect).IsEmpty()) )
/*N*/       {
/*?*/           delete pTextObj;
/*?*/           pTextObj=NULL;
/*N*/       }
/*N*/
/*N*/       if (pTextObj)
/*N*/       {
/*N*/           SdrObject *pObj=CreateMarks(nPosition,mnTickLen,mnTicks);
/*N*/           SdrObjList* pList = mpAxisList;
/*N*/           if(pObj)
/*N*/             {
/*N*/                 pObj->SetMarkProtect( TRUE );
/*N*/               pList->NbcInsertObject(pObj);
/*N*/             }
/*N*/
/*N*/             pTextObj->SetMarkProtect( TRUE );
/*N*/           pList->NbcInsertObject(pTextObj);
/*N*/           maRectA = maRectB;
/*N*/           maRectB = aTextBoundRect;
/*N*/           return; //fertig -> Abbruch (die Marks muessen zuerst, dann die Texte)
/*N*/       }
/*N*/   }
/*N*/   //kein Textobjekt oder der Text würde überlappen
/*?*/   SdrObject *pObj=CreateMarks(nPosition,mnTickLen,mnTicks);
/*?*/   if(pObj && mpAxisList)
/*?*/       mpAxisList->NbcInsertObject(pObj);
/*N*/ }
/*N*/ void ChartAxis::InsertMark(long nPos,long nLen,long nWhichTicks)
/*N*/ {
/*N*/   SdrObject *pObj=CreateMarks(nPos,nLen,nWhichTicks);
/*N*/   if(pObj && mpAxisList)
/*N*/       mpAxisList->NbcInsertObject(pObj);
/*N*/ }


//Ähnlich zu SubtractDescrSize, jedoch wird der Umbruch sowie Änderungen am Rect bei
//sehr langen spaltenunterschriften berücksichtigt.
/*N*/ void ChartAxis::SubtractDescrSize_X(Rectangle& rRect,const Rectangle& rOldRect)
/*N*/ {
/*N*/   long nDescrWidth=GetDescrWidth();
/*N*/   mnMaxTextWidth = (long) (nDescrWidth * 0.8);
/*N*/
/*N*/   //Breite des ersten und letzten Textes der Achse, war mal ChartModel::nWidthOfFirst(Last)XAxisText
/*N*/   //A() = erster, B()=letzter
/*N*/   Pair aFirstAndLastTextWidth;
/*N*/
/*N*/   Size aPageSize(mpModel->GetPage(0)->GetSize());
/*N*/
/*N*/   //unschön, SID_TEXTBREAK sollte ein SCHATTR_... werden!
/*N*/   BOOL bTextBreak=mpModel->GetFormatXAxisTextInMultipleLinesIfNecessary();
/*N*/   if(!bTextBreak)  // Dann wird kein Umbruch erzeugt.
/*N*/      mnMaxTextWidth = -1;
/*N*/
/*N*/   meTextOrient = ((const SvxChartTextOrientItem&)
/*N*/       mpAxisAttr->Get(SCHATTR_TEXT_ORIENT)).GetValue();
/*N*/
/*N*/   BOOL bStepDescr;
/*N*/
/*N*/   // FG: Falls die X-Achsenbeschriftung aus Zahlen besteht, wird dies beruecksichtigt.
/*N*/   UINT32  nNumberFormatXAxisDescr  = GetNumFormat();//0;
/*N*/
/*N*/   // FG: Jetzt wird der Rand des Charts so eingestellt, dass die Beschriftung der X-Achse
/*N*/   //     garantiert nicht aus dme Chart heraus oder ins Diagramm hineinlaeuft. Hier
/*N*/   //     muessen alle Faelle der Textausrichtung beruecksichtigt werden.
/*N*/   //     Hier wird erstmal die maximale Textgroesse und die Textgroesse der ersten und letzten Spalte
/*N*/   //     berechnet (letzteres wird in CalcMaxDescrSize versteckt durchgezogen)
/*N*/
/*N*/
/*N*/   if (HasDescription())//#47500#
/*N*/   {
/*N*/       if (IsVertical())
/*N*/       {
/*N*/           // FG: hier wird erstmal die urspruengliche Textgroesse berechnet, sie wird abhaengig
/*N*/           //     vom Ergebnis nachkorrigiert. Die Textbreite ab der umgebrochen wird darf nichts
/*N*/           //     mit der Spaltenbreite zu tun haben falls der Text links neben dem Chart steht
/*N*/           //     und von links nach rechts laeuft.
/*N*/           maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, mbPercent, mnUId, -1, &aFirstAndLastTextWidth );
/*N*/           // FG: Falls man den Text umbrechen darf, so muss nur noch beachtet werden, in welche
/*N*/           //     Richtung der Text verlaufen soll (senkrecht, waagrecht) und ob die Groesse der
/*N*/           //     Beschriftung das restliche Chart zu klein machen wird. Die groesste Beschriftung
/*N*/           //     darf nicht mehr als 25% der Breite oder Hoehe einnehmen, je nach Ausrichtung des
/*N*/           //     Textes.
/*N*/           if  (bTextBreak)
/*N*/           {
/*N*/               if (   (meTextOrient == CHTXTORIENT_BOTTOMTOP)
/*N*/                   || (meTextOrient == CHTXTORIENT_TOPBOTTOM)
/*N*/                   || (meTextOrient == CHTXTORIENT_STACKED))
/*N*/               {
/*?*/                   if ((aPageSize.Height() / 4) < maMaxTextSize.Width())
/*?*/                   {
/*?*/                       mnMaxTextWidth = aPageSize.Height() / 4;
/*?*/                       maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*?*/                                                           mnUId, mnMaxTextWidth,
/*?*/                                                           &aFirstAndLastTextWidth );
/*?*/                   }
/*?*/                   // FG: sonst kann die erste Berechnung beibehalten werden.
/*?*/               }
/*N*/               else
/*N*/               {
/*N*/                   if ((aPageSize.Width() / 4) < maMaxTextSize.Width()) // waagrechte Ausrichtung
/*N*/                   {
/*N*/                       // FG. Dann ist also der Platz fuer die Beschriftung groesser als 1/4 des Charts
/*N*/                       mnMaxTextWidth = aPageSize.Width() / 4;
/*N*/                   }
/*?*/                   maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*N*/                                                               mnUId, mnMaxTextWidth,
/*N*/                                                               &aFirstAndLastTextWidth );
/*N*/               }
/*N*/           }
/*N*/           else  // FG: Falls der Umbruch nicht erlaubt ist, der Text aber breiter als 1/3 des Charts wird,
/*N*/           {     //     wird trotzdem umgebrochen. Dann muss dei maximale Hoehe und Breite der groessten
/*N*/                 //     uns insbesondere der 1. und letzten Beschriftung neu berechnet werden.
/*N*/                 //     Das laesst sich sicher besser machen als nochmal ueber die gesamte Liste von Texten
/*N*/                 //     zu iterieren.
/*?*/               if (   (   (meTextOrient == CHTXTORIENT_BOTTOMTOP)
/*?*/                       || (meTextOrient == CHTXTORIENT_TOPBOTTOM)
/*?*/                       || (meTextOrient == CHTXTORIENT_STACKED)  )
/*?*/                    && ((aPageSize.Height() / 3) < maMaxTextSize.Width()))
/*?*/               {
/*?*/                   // FG. Dann ist also der Platz fuer die Beschriftung groesser als 1/4 des Charts
/*?*/                   mnMaxTextWidth = aPageSize.Height() / 3;
/*?*/                   maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*?*/                                                      mnUId, mnMaxTextWidth,
/*?*/                                                      &aFirstAndLastTextWidth );
/*?*/               }
/*?*/           }
/*N*/       }
/*N*/       else  // FG: Der Text steht also unter dem Chart.
/*N*/       {
/*N*/           // FG: Fuer den Fall dass die Beschriftung nicht unter jeden Datenpunkt gesetzt
/*N*/           //     wird, weil zu viele Daten vorhanden sind, eignet sich eine vertikale
/*N*/           //     Textausrichtung besser (im Falle dass die Ausrichtung automatisch
/*N*/           //     erfolgen soll.
/*N*/           maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*N*/                                              mnUId, mnMaxTextWidth,
/*N*/                                              &aFirstAndLastTextWidth );
/*N*/
/*N*/           if (   (meTextOrient == CHTXTORIENT_BOTTOMTOP)
/*N*/               || (meTextOrient == CHTXTORIENT_TOPBOTTOM)
/*N*/               || (meTextOrient == CHTXTORIENT_STACKED))
/*N*/           {
/*?*/               if ((aPageSize.Width() / 2) < maMaxTextSize.Height())
/*?*/               {
/*?*/                   mnMaxTextWidth = aPageSize.Height() / 2;
/*?*/                   maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*?*/                                                      mnUId, mnMaxTextWidth,
/*?*/                                                      &aFirstAndLastTextWidth );
/*?*/               }
/*?*/               if (  ( (aPageSize.Width() / 4) < maMaxTextSize.Height()) &&
/*?*/                  (bTextBreak))
/*?*/               {
/*?*/                   mnMaxTextWidth = aPageSize.Height() / 4;
/*?*/                   maMaxTextSize = mpModel->CalcMaxDescrSize( FALSE, meTextOrient, nNumberFormatXAxisDescr,
/*?*/                                                      mnUId, mnMaxTextWidth,
/*?*/                                                      &aFirstAndLastTextWidth);
/*?*/               }
/*?*/           }
/*N*/       }
/*N*/
/*N*/
/*N*/       SvxChartTextOrder eDescrOrder;
/*N*/
/*N*/       eDescrOrder = ((const SvxChartTextOrderItem&) mpAxisAttr->Get(SCHATTR_TEXT_ORDER)).GetValue();

        // FG: Hier wird nur abgefragt, ob die Beschriftung der X-Achse (der Datenachse)
        //     so erfolgen soll, dass Text abwechselnd hoch-tief gesetzt werden, oder nicht.
/*N*/       long nMaxWidth = IsVertical() ? maMaxTextSize.Height() : maMaxTextSize.Width();
/*N*/       BOOL bHelp = (nMaxWidth > nDescrWidth * 8.1 / 10);
/*N*/       bStepDescr =  ( bHelp &&
/*N*/                          (eDescrOrder == CHTXTORDER_AUTO) &&
/*N*/                          (meTextOrient == CHTXTORIENT_STANDARD)) ||
/*N*/                          (eDescrOrder == CHTXTORDER_UPDOWN) ||
/*N*/                          (eDescrOrder == CHTXTORDER_DOWNUP);

        // FG: Hier wird aufgrund der Beschriftung der obere und der untere Rand nachgeregelt.
        //     und zwar nur hier.

//BEGIN_RECT_CHANGES

/*N*/       if (IsVertical())
/*N*/       {
/*N*/           if (! bTextBreak)
/*N*/           {
/*N*/               if (   (meTextOrient == CHTXTORIENT_BOTTOMTOP)
/*N*/                   || (meTextOrient == CHTXTORIENT_TOPBOTTOM)
/*N*/                   || (meTextOrient == CHTXTORIENT_STACKED))
/*N*/               {
/*N*/                   // FG: In diesem Fall muss man nachregeln, der Text wird ohne Umruch formatiert
/*?*/                   if ((rRect.Bottom() - rOldRect.Bottom()) < (aFirstAndLastTextWidth.B() / 2))
/*?*/                   {
/*?*/                       rRect.Bottom() -= aFirstAndLastTextWidth.B() / 2;
/*?*/                   }
/*?*/                   if ((rRect.Top() - rOldRect.Top()) < (aFirstAndLastTextWidth.A() / 2))
/*?*/                   {
/*?*/                       rRect.Top() -= aFirstAndLastTextWidth.A() / 2;
/*?*/                   }
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           // FG: Der Text steht unter dem Chart, egal ob er von links nach rechts oder von oben nach
/*N*/           //     unten verlaeuft aMaxDescrSize muss vorher richtig berechnet worden sein.
/*N*/           if(mbSecondary)
/*?*/              rRect.Top() += maMaxTextSize.Height() + mnTickLen + 100;
/*?*/           else
/*N*/              rRect.Bottom() -= maMaxTextSize.Height() + mnTickLen + 100;
/*N*/       }
/*N*/
/*N*/       if (bStepDescr)  // FG: Dann erfolgt die Beschriftung hoch- und tief abwechselnd (wie in der Dialogbox)
/*N*/       {
/*N*/               // dann hat man mehr Platz pro Zeile (eigentlich 2 mal soviel) aber der Platz zwischen den
/*N*/               // Beschriftungen steht auch noch zur Verfuegung (jeweils 0,2 * nDescrWidth)
//          mnMaxTextWidth = 2 * mnMaxTextWidth + 0,4 * nDescrWidth;
/*?*/           //cmc: I thought I'd leave ^^^ in for posterity, behold the , vs . :-)
/*?*/           mnMaxTextWidth = 2 * mnMaxTextWidth + 0;
/*?*/               // Man braucht auch 2 mal soviel Platz in unten am Chart.
/*?*/           if(mbSecondary)
/*?*/               rRect.Top() += maMaxTextSize.Height() + mnTickLen;
/*?*/           else
/*?*/               rRect.Bottom() -= maMaxTextSize.Height() + mnTickLen;
/*N*/       }
/*N*/   }
/*N*/       // FG (14.2.97): Hier wird der linke Rand nachgeregelt, und zwar je nach Diagrammtyp unterschiedlich.
/*N*/   if (mpModel->IsDescriptionCenteredUnderDataPoint())
/*N*/   {
/*N*/           // Nun jetzt weiss ich dass die Beschriftung zentriert unter einem Datenpunkt steht.
/*N*/           // jetzt muss der linke Rand nachgeregelt werden: Genau die Haelfte des
/*N*/           // Spaltentextes mit Nummer 0 muss nach links noch Platz sein.
/*N*/       if (IsVertical())
/*N*/       {
/*N*/           if ((rRect.Left() - rOldRect.Left()) < maMaxTextSize.Width())
/*N*/           {
/*N*/               rRect.Left()    += maMaxTextSize.Width();
/*N*/           }
/*N*/           // FG: Ein Nachregeln des rechten Randes ist nicht noetig, da die Beschriftung
/*N*/           //     nie rechts neben dem Chart stehen kann.
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           if(! (     (meTextOrient == CHTXTORIENT_BOTTOMTOP)
/*N*/                   || (meTextOrient == CHTXTORIENT_TOPBOTTOM)
/*N*/                   || (meTextOrient == CHTXTORIENT_STACKED)) )
/*N*/           {
/*N*/               if ((rRect.Left() - rOldRect.Left()) < (aFirstAndLastTextWidth.A() / 2))
/*N*/               {
/*N*/                   rRect.Left() += aFirstAndLastTextWidth.A() / 2;
/*N*/               }
/*N*/               if (mpModel->InitialSize().Width() - rRect.Right() < (aFirstAndLastTextWidth.B() / 2))
/*N*/               {
/*N*/                   rRect.Right() -= aFirstAndLastTextWidth.B() / 2;
/*N*/               }
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       // FG: Im anderen Fall wird gerade so umgebrochen, dass kein zusaetzlicher Rand gelassen werden muss.
/*N*/       //     Es sei denn im Dialog wurde eingestellt, dass man keinen Umbruch wollte.
/*N*/       if (!bTextBreak)
/*N*/       {
/*?*/           if ((rRect.Left() - rOldRect.Left()) < (aFirstAndLastTextWidth.A() / 2))
/*?*/           {
/*?*/               rRect.Left() += aFirstAndLastTextWidth.A() / 2;
/*?*/           }
/*?*/           if (mpModel->InitialSize().Width() - rRect.Right() < (aFirstAndLastTextWidth.B() / 2))
/*?*/           {
/*?*/               rRect.Right() -= aFirstAndLastTextWidth.B() / 2;
/*?*/           }
/*N*/       }
/*N*/   }
//END RECT_CHANGES ********************************************************************
/*N*/ }




/*N*/ void ChartAxis::SubtractDescrSize(Rectangle& rRect)
/*N*/ {
/*N*/   if(!mbShowDescr)
/*N*/       return;

/*N*/   long nLong = (mnTicks&CHAXIS_MARK_OUTER) ? 150 : (mnHelpTicks&CHAXIS_MARK_OUTER) ? 100 : 0;

/*N*/   if(mbSecondary)
/*N*/   {
/*?*/       if(!IsVertical())
/*?*/       {
/*?*/           rRect.Top() += mbStepValue
/*?*/                                 ? maMaxTextSize.Height() * 2
/*?*/                                 : maMaxTextSize.Height();
/*?*/           rRect.Top() += nLong;
/*?*/       }
/*?*/       else
/*?*/       {
/*?*/           rRect.Right() -= mbStepValue
/*?*/                               ? maMaxTextSize.Width() * 2
/*?*/                               : maMaxTextSize.Width();
/*?*/           rRect.Right() -= nLong;
/*?*/       }
/*?*/   }
/*N*/   else
/*N*/   {
/*N*/       if(!IsVertical())
/*N*/       {
/*N*/           rRect.Bottom() -= mbStepValue
/*N*/                                 ? maMaxTextSize.Height() * 2
/*N*/                                 : maMaxTextSize.Height();
/*N*/           rRect.Bottom() -= nLong;
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           rRect.Left() += mbStepValue
/*N*/                               ? maMaxTextSize.Width() * 2
/*N*/                               : maMaxTextSize.Width();
/*N*/           rRect.Left() += nLong;
/*N*/       }
/*N*/   }
/*N*/ }
//Bisher nur Y-Achse:
/*N*/ void ChartAxis::InitDescr()
/*N*/ {
/*N*/   InitDescr(meTextOrient,mnMaxTextWidth);
/*N*/ }
/*N*/ void ChartAxis::InitDescr(SvxChartTextOrient &rValueOrient,long nMaxTextWidth)
/*N*/ {
/*N*/   mnMaxTextWidth=nMaxTextWidth;//-1;
/*N*/
/*N*/   BOOL bAutoValue = (rValueOrient == CHTXTORIENT_AUTOMATIC);
/*N*/
/*N*/   if(!mbShowDescr)
/*N*/       return;
/*N*/
/*N*/   if (bAutoValue)
/*N*/       rValueOrient = CHTXTORIENT_STANDARD;

/*N*/   SvxChartTextOrder eValueOrder = ((const SvxChartTextOrderItem&)mpAxisAttr->Get(SCHATTR_TEXT_ORDER)).GetValue();
/*N*/
/*N*/   mbStepValue = (eValueOrder != CHTXTORDER_SIDEBYSIDE);
/*N*/   mbValueDown = (eValueOrder == CHTXTORDER_DOWNUP);
/*N*/
/*N*/   meTextOrient = rValueOrient;
/*N*/
/*N*/   CreateTextAttr();
/*N*/ }
/*N*/ void ChartAxis::InitDescr_X()
/*N*/ {
/*N*/   if(!mbShowDescr)
/*N*/       return;
/*N*/
/*N*/   SvxChartTextOrder eValueOrder;

    // FG: Einfachere Abfrage ob die Ausrichtung vom Programm vorgegeben wird oder vom Benutzer
/*N*/   eValueOrder = ((const SvxChartTextOrderItem&)mpAxisAttr->Get(SCHATTR_TEXT_ORDER)).GetValue();

    // FG: Hier wird nur abgefragt, ob die Beschriftung der X-Achse (der Datenachse)
    //     so erfolgen soll, dass Text abwechselnd hoch-tief gesetzt werden, oder nicht.
/*N*/   long nMaxWidth = IsVertical() ? maMaxTextSize.Height() : maMaxTextSize.Width();
/*N*/   BOOL bHelp= (nMaxWidth > GetDescrWidth() * 8.1 / 10);
/*N*/   mbStepValue = (bHelp &&
/*N*/                 (eValueOrder == CHTXTORDER_AUTO) &&
/*N*/                 (meTextOrient == CHTXTORIENT_STANDARD)) ||
/*N*/                 (eValueOrder == CHTXTORDER_UPDOWN) ||
/*N*/                 (eValueOrder == CHTXTORDER_DOWNUP);
/*N*/
/*N*/
/*N*/   mbValueDown = (eValueOrder == CHTXTORDER_DOWNUP);

/*N*/   CreateTextAttr();
/*N*/ }




/*N*/ void ChartAxis::CreateTextAttr()
/*N*/ {
/*N*/   if(!mpTextAttr)
/*N*/       mpTextAttr=new SfxItemSet((const SfxItemSet &)*mpAxisAttr);
/*N*/   else
/*N*/       mpTextAttr->Put(*mpAxisAttr); //Update
/*N*/
/*N*/   mpTextAttr->Put(SvxChartTextOrientItem(meTextOrient));
/*N*/   mpTextAttr->Put(XLineStyleItem(XLINE_NONE));
/*N*/   mpTextAttr->Put(XLineWidthItem(0));
/*N*/ }

/*N*/ void ChartAxis::CreateAxis(SdrObjList& rList,long nChObjId)
/*N*/ {
/*N*/   if(IsVisible() || HasDescription())
/*N*/   {
/*N*/       mpAxisObj = new SchAxisObj( mpModel );
/*N*/       SetObjectAttr( mpAxisObj, USHORT(nChObjId), TRUE, TRUE, 0 );
/*N*/       SetAxisList( mpAxisObj->GetSubList() );
/*N*/
/*N*/       rList.NbcInsertObject( mpAxisObj, CONTAINER_APPEND );
/*N*/
/*N*/       if( IsVisible())
/*N*/           CreateAxis();
/*N*/   }
/*N*/ }

/*N*/ void ChartAxis::CreateAxis(const long nPos,BOOL bBorderAxis,BOOL bInnerAxis)
/*N*/ {
/*N*/   //Position der X-Achse.... aber nicht der Ticks
/*N*/   //(nicht ganz verständlich bei XY-Diagrammen)
/*N*/   //was ist mit bShow?Descr ?
/*N*/   mnInnerPos=nPos;
/*N*/
/*N*/   long nPos1 = 0;
/*N*/   if(bBorderAxis)
/*N*/       nPos1=CreateAxis();
/*N*/   else
/*N*/   {
/*N*/       mbInnerPos=TRUE; //ungenutzt.... evtl. wegen SetArea(){...SetPosition()...}
/*N*/       SetPosition(nPos);
/*N*/   }
/*N*/   mnInnerPos=nPos;
/*N*/
/*N*/   if(bInnerAxis &&(!bBorderAxis || nPos1!=nPos)) //nur eine Achse oder 2 Achsen an versch. Positionen
/*N*/   {
/*N*/
/*N*/       XPolygon aLine(2);
/*N*/       if (IsVertical())
/*N*/       {
/*N*/           aLine[0].X() = aLine[1].X() = nPos;
/*N*/           aLine[0].Y() = maRefArea.Bottom();
/*N*/           aLine[1].Y() = maRefArea.Top();
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           aLine[0].Y() = aLine[1].Y() = nPos;
/*N*/           aLine[0].X() = maRefArea.Left();
/*N*/           aLine[1].X() = maRefArea.Right();
/*N*/       }
/*N*/       if (mpAxisList)
/*N*/           mpAxisList->NbcInsertObject(SetObjectAttr (new SdrPathObj(OBJ_PLIN, aLine),
/*N*/           CHOBJID_LINE, TRUE, TRUE,mpAxisAttr));
/*N*/   }
/*N*/ }

/*N*/ long ChartAxis::CreateAxis()
/*N*/ {
/*N*/   XPolygon aLine(2);
/*N*/   long nPos;
/*N*/
/*N*/   if (IsVertical())
/*N*/   {
/*N*/       if(mbSecondary)
/*N*/       {
/*?*/           aLine[0].X() = aLine[1].X() = maRefArea.Right();
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           aLine[0].X() = aLine[1].X() = maRefArea.Left();
/*N*/       }
/*N*/       aLine[0].Y() = maRefArea.Bottom();
/*N*/       aLine[1].Y() = maRefArea.Top();
/*N*/       nPos=aLine[0].X();
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       if(mbSecondary)
/*N*/       {
/*?*/           aLine[0].Y() = aLine[1].Y() = maRefArea.Top();
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           aLine[0].Y() = aLine[1].Y() = maRefArea.Bottom();
/*N*/       }
/*N*/       aLine[0].X() = maRefArea.Left();
/*N*/       aLine[1].X() = maRefArea.Right();
/*N*/       nPos=aLine[0].Y();
/*N*/   }
/*N*/
/*N*/   if (mpAxisList && IsVisible())
/*N*/       mpAxisList->NbcInsertObject(SetObjectAttr (new SdrPathObj(OBJ_PLIN, aLine),
/*N*/       CHOBJID_LINE, TRUE, TRUE,mpAxisAttr));
/*N*/
/*N*/   return nPos;
/*N*/
/*N*/ }
/*N*/ void ChartAxis::SetMainGrid(SdrObjList* pList,SfxItemSet*pAttr)
/*N*/ {
/*N*/   mpMainGridList=pList;
/*N*/   mpMainGridAttr=pAttr;
/*N*/   switch(mnId)
/*N*/   {
/*N*/       case CHART_AXIS_X:
/*N*/           mnIdMainGrid=CHOBJID_DIAGRAM_Y_GRID_MAIN;
/*N*/           break;
/*N*/       case CHART_AXIS_Y:
/*N*/           mnIdMainGrid=CHOBJID_DIAGRAM_X_GRID_MAIN;
/*N*/           break;
/*N*/       case CHART_AXIS_Z:
/*?*/           mnIdMainGrid=CHOBJID_DIAGRAM_Z_GRID_MAIN;
/*?*/           break;
/*N*/   }
/*N*/ }
/*N*/ void ChartAxis::SetHelpGrid(SdrObjList* pList,SfxItemSet*pAttr)
/*N*/ {
/*N*/   mpHelpGridList=pList;
/*N*/   mpHelpGridAttr=pAttr;
/*N*/   switch(mnId)
/*N*/   {
/*N*/       case CHART_AXIS_X:
/*N*/           mnIdHelpGrid=CHOBJID_DIAGRAM_Y_GRID_HELP;
/*N*/           break;
/*N*/       case CHART_AXIS_Y:
/*N*/           mnIdHelpGrid=CHOBJID_DIAGRAM_X_GRID_HELP;
/*N*/           break;
/*N*/       case CHART_AXIS_Z:
/*?*/           mnIdHelpGrid=CHOBJID_DIAGRAM_Z_GRID_HELP;
/*?*/           break;
/*N*/   }
/*N*/ }
/*N*/
/*N*/ void ChartAxis::GridLine(XPolygon& aLine,long nPos)
/*N*/ {
/*N*/   if(IsVertical())
/*N*/   {
/*N*/       aLine[0].Y() = aLine[1].Y() = nPos;
/*N*/       aLine[0].X() = maRefArea.Left();
/*N*/       aLine[1].X() = maRefArea.Right();
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       aLine[0].X() = aLine[1].X() = nPos;
/*N*/       aLine[0].Y() = maRefArea.Bottom();
/*N*/       aLine[1].Y() = maRefArea.Top();
/*N*/   }
/*N*/ }

/*N*/ void ChartAxis::ShowDescr(BOOL b)
/*N*/ {
/*N*/     mbShowDescr=b;
/*N*/     mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_SHOWDESCR,b));
/*N*/ }

/*N*/ void ChartAxis::ShowAxis(BOOL b)
/*N*/ {
/*N*/     mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_SHOWAXIS,b));
/*N*/ }

/*N*/ void ChartAxis::DrawGrids()
/*N*/ {
/*N*/   XPolygon aLine(2);
/*N*/   long nPos;
/*N*/
/*N*/   if(!mpMainGridList && !mpHelpGridList && !mpAxisList)
/*N*/       return ; //nothing to do
/*N*/
/*N*/
/*N*/   // if the x-axis has no numbers as description, the meaning of main and help ticks might
/*N*/   // be interpreted the other way round
/*N*/   long   nTicksBack       =mnTicks;
/*N*/   long   nHelpTicksBack   =mnHelpTicks;
/*N*/   long   nTickLenBack     =mnTickLen;
/*N*/   long   nHelpTickLenBack =mnHelpTickLen;
/*N*/
/*N*/   // ...Back is for storing original values
/*N*/   double fMinBack  = mfMin;
/*N*/   double fMaxBack  = mfMax;
/*N*/   double fStepBack     = mfStep;
/*N*/   double fStepHelpBack= mfStepHelp;
/*N*/   BOOL   bLogarithmBack = mbLogarithm;
/*N*/
/*N*/   if(mbColText) //... da hier modifiziert werden kann, aber die Werte nicht
/*N*/   {             //in den Attrset sollen (also nicht persistent). In wie weit das nötig ist, ist ne andere Frage...
/*N*/       mfMin=0;
/*N*/       mfStep=1;
/*N*/       mbLogarithm = FALSE;
/*N*/       mfMax=mpModel->GetColCount();
/*N*/       if(mbCenterText && mfMax>1.0)
/*N*/       {
/*?*/           mfMax-=1;
/*?*/
/*?*/           //Die Markierungen sind bei Linien und Area-Charts verschoben
/*?*/           //=> dies entspricht gewissermassem dem Swap von Help und MainTicks
/*?*/           mnTicks=0;//nHelpTicksBack; //HelpTicks bzw. innen/aussen noch nicht per GUI zugänglich, daher fixe Werte
/*?*/           mnHelpTicks=CHAXIS_MARK_OUTER;//nTicksBack;
/*?*/           mnHelpTickLen=nTickLenBack;
/*?*/           mnTickLen=nHelpTickLenBack;
/*?*/
/*?*/           //  Now we have to copy with the case of to many tick marks.
/*?*/           //  The problem lies in the fact, that creating to many tick
/*?*/           //  marks results in an overrun of pool item reference counters.
/*?*/           //  Creating them without these items leaves them unchangeable.
/*?*/           //  The best solution is to generalize the data set, i.e.
/*?*/           //  to draw only a part of the tick marks (and draw only a part
/*?*/           //  of the data).  The number of tick marks to draw should ideally
/*?*/           //  depend on the real window size measured in pixel.  This is (at
/*?*/           //  the moment) not possible because we don't have access to the
/*?*/           //  view and therefore no access to it's output device.
/*?*/           //  Leaving a clean solution for the new chart for now we
/*?*/           //  set a fixed number as the maximal count of tick marks.
/*?*/           //  This solution has one advantage: output to the screen and to
/*?*/           //  the printer has the same number of tick marks.
/*?*/           const double maximum_number_of_tick_marks = 1000.0;
/*?*/           mfStep =(mfMax - mfMin) / ::std::min< double > (maximum_number_of_tick_marks, (mfMax - mfMin));
/*?*/       }
/*N*/       else
/*N*/       {
/*N*/           mnHelpTicks=0; //nicht per Gui möglich, daher fixe Werte
/*N*/           mnTicks=CHAXIS_MARK_OUTER;
/*N*/       }
/*N*/
/*N*/       mfStepHelp = mfStep / 2;
/*N*/   }
/*N*/
/*N*/   // #69810# prevent infinite loop if step wouldn't change the value of fAct
/*N*/   BOOL bStepIsOK = mbLogarithm? (fabs(mfStep) > 1.0): (mfStep != 0.0);
/*N*/
/*N*/   if( mfMax!=mfMin && ( bStepIsOK ) )
/*N*/   {
/*N*/       double fAct     = mfMin;
/*N*/       double fActHelp = mfMin;
/*N*/
/*N*/         // in the worst case the threshhold is 1/1000th of the height of the
/*N*/         // diagram this is just done because of minor inaccuracies that may
/*N*/         // occur, because in the following loop the current value is achieved by
/*N*/         // repeatedly adding the main step value where small errors might
/*N*/         // accumulate
/*N*/         double fThreshold = ::std::min( mfMax, ::std::min( mfStep, mfStepHelp )) / 1000.0;
/*N*/
/*N*/         if( ::rtl::math::isInf( mfMax ) || ::rtl::math::isInf( mfMin ))
/*N*/         {
/*N*/             OSL_FAIL( "maximum or minumum is infinity" );
/*N*/         }
/*N*/         else
/*N*/         {
/*N*/             // #102339# iterate one major tick further and inhibit creating
/*N*/             // ticks in case they are above the maximum (+threshold)
/*N*/             double fUpperLimit = mfMax + fThreshold;
/*N*/             double fIterationEnd = fUpperLimit + mfStep;
/*N*/             while( fAct <= fIterationEnd )
/*N*/             {
/*N*/                 long nMainPos = GetPos(fAct);
/*N*/
/*N*/                 if( fAct <= fUpperLimit )
/*N*/                 {
/*N*/                     GridLine(aLine,nMainPos);
/*N*/
/*N*/                     if (mpMainGridList)
/*N*/                         mpMainGridList->NbcInsertObject(SetObjectAttr(new SdrPathObj(OBJ_PLIN,aLine),
/*N*/                                                                       USHORT(mnIdMainGrid),TRUE,TRUE,mpMainGridAttr));
/*N*/                 }
/*N*/
/*N*/                 if(mpHelpGridList || (mpAxisList && mnHelpTicks) )
/*N*/                 {
/*?*/                     if(mbLogarithm)
/*?*/                     {
/*?*/                         fActHelp = mfStep / mfStepHelp * fAct;
/*?*/
/*?*/                         double fNext = fAct;
/*?*/                         IncValue(fNext,mfStep,mbLogarithm);
/*?*/
/*?*/                         while (fActHelp < fNext)
/*?*/                         {
/*?*/                             if(CalcFact(fActHelp) > 1.0)
/*?*/                                 break;
/*?*/
/*?*/                             if( fActHelp <= fUpperLimit )
/*?*/                             {
/*?*/                                 GridLine(aLine,nPos=GetPos(fActHelp));
/*?*/
/*?*/                                 if(mpHelpGridList)
/*?*/                                     mpHelpGridList->NbcInsertObject(SetObjectAttr(new SdrPathObj(OBJ_PLIN,aLine),
/*?*/                                                                                   USHORT(mnIdHelpGrid),TRUE,TRUE,mpHelpGridAttr));
/*?*/
/*?*/                                 InsertMark(nPos,mnHelpTickLen,mnHelpTicks);
/*?*/                             }
/*?*/
/*?*/                             fActHelp+=mfStep/mfStepHelp*fAct;
/*?*/                         }
/*?*/                     }
/*?*/                     else
/*?*/                     {
/*?*/                         while(fActHelp <= fAct)
/*?*/                         {
/*?*/                             if(CalcFact(fActHelp) > 1.0)
/*?*/                                 break;
/*?*/
/*?*/                             if( fActHelp <= fUpperLimit )
/*?*/                             {
/*?*/                                 GridLine(aLine,nPos=GetPos(fActHelp));
/*?*/
/*?*/                                 if(mpHelpGridList)
/*?*/                                     mpHelpGridList->NbcInsertObject(SetObjectAttr(new SdrPathObj(OBJ_PLIN, aLine),
/*?*/                                                                                   USHORT(mnIdHelpGrid),TRUE,TRUE,mpHelpGridAttr));
/*?*/
/*?*/                                 InsertMark(nPos,mnHelpTickLen,mnHelpTicks);
/*?*/                             }
/*?*/
/*?*/                             fActHelp+=mfStepHelp;
/*?*/                         }
/*?*/                         //    If the main grid is drawn then skip the coinciding help grid lines.
/*?*/                         if (((fActHelp == fAct) && mpMainGridList) || mbColText)
/*?*/                             fActHelp+=mfStepHelp;
/*?*/                     }
/*?*/                 }
/*N*/
/*N*/                 if( mpAxisList && fAct < fUpperLimit )
/*N*/                 {
/*N*/                     if(mbShowDescr)
/*N*/                         CreateMarkDescr(fAct,nMainPos);
/*N*/                     else
/*?*/                         InsertMark(nMainPos,mnTickLen,mnTicks);
/*N*/                 }
/*N*/                 IncValue( fAct, mfStep, mbLogarithm );
/*N*/             }
/*N*/         }
/*N*/   }
/*N*/
/*N*/   // restore original values. Might be obsolete
/*N*/   mfMin      = fMinBack;
/*N*/   mfMax      = fMaxBack;
/*N*/   mfStep     = fStepBack;
/*N*/   mfStepHelp = fStepHelpBack;
/*N*/
/*N*/   mnTicks         =nTicksBack;
/*N*/   mnHelpTicks     =nHelpTicksBack;
/*N*/   mnTickLen       =nTickLenBack;
/*N*/   mnHelpTickLen   =nHelpTickLenBack;
/*N*/   mbLogarithm     =bLogarithmBack;
/*N*/ }

/*?*/ inline double ChartAxis::GetData(long nCol,long nRow)
/*?*/ {
/*?*/   double fData=mpModel->GetData(nCol,nRow);
/*?*/   if(mbPercent)
/*?*/       fData=Data2Percent(fData,nCol,nRow);
/*?*/   return fData;
/*?*/ };
// Falls es sich um eine gespiegelte Achse handelt, ist es nicht möglich,
// einmal Logarithmus zu setzen, das andere mal nicht.
// Die anderen Werte müssen evtl. (bei automatik) angepasst werden.
// allerdings darf hier geändert werden, um z.B. links 0-10 Volt
// und rechts 0-1000 mV an der Achse zu setzen. Das die Werte dann trotzdem
// identisch sind, liegt in diesem Fall dann in der Verantwortung des Users.
/*N*/ BOOL ChartAxis::AttachIfNoOwnData(const ChartAxis* pAxis)
/*N*/ {
/*N*/   if(!mbAlternativIdUsed) //Hat eigene Daten!
/*N*/       return FALSE;

    //es macht keinen Sinn, unsichtbare Achsen zu kopieren:
/*?*/   if(!pAxis->IsVisible() && !pAxis->HasDescription())
/*?*/       return FALSE;
/*?*/
/*?*/   ReadAutoAttr();
/*?*/
/*?*/   mbLogarithm    = pAxis->mbLogarithm;
/*?*/   mpAxisAttr->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM,mbLogarithm));
/*?*/
/*?*/   if(mbAutoStep)
/*?*/       mfStep=pAxis->mfStep;
/*?*/   if(mbAutoStepHelp)
/*?*/       mfStepHelp=pAxis->mfStepHelp;
/*?*/   if(mbAutoMin)
/*?*/       mfMin=pAxis->mfMin;
/*?*/   if(mbAutoMax)
/*?*/       mfMax=pAxis->mfMax;
/*?*/   if(mbAutoOrigin)
/*?*/       mfOrigin=pAxis->mfOrigin;
/*?*/
/*?*/   FillItemSet();
/*?*/
/*?*/   return TRUE;
/*?*/
/*N*/ }
/*N*/ double ChartAxis::NumStepsMain()
/*N*/ {
/*N*/   if( mbLogarithm )
/*N*/   {
/*?*/       DBG_ASSERT( mfStep > 1.0, "ChartAxis: argument of log must be greater than 1" );
/*?*/       return log( mfMax - mfMin ) / log( mfStep );
/*N*/   }
/*N*/
/*N*/   return (mfMax - mfMin) / mfStep;
/*N*/ };

/*N*/ long ChartAxis::GetDescrWidth()
/*N*/ {
/*N*/   double fAllTextLen = IsVertical() ? (double)maRefArea.GetHeight()
/*N*/                                     : (double)maRefArea.GetWidth();
/*N*/   long   nDescrWidth=0;
/*N*/
/*N*/   if(!mbColText) //z.B. bei XY-Charts gelangt man hier hin!
/*N*/   {
/*N*/       if(mfStep!=0.0)
/*N*/       {
/*N*/           double fCnt = NumStepsMain();
/*N*/           if (mbCenterText)
/*N*/               fCnt -= 1.0;
/*N*/
/*N*/           nDescrWidth  = (long) (fAllTextLen / fCnt);
/*N*/       }
/*N*/   }
/*N*/   else //Area, Bar etc.
/*N*/   {
/*N*/       long  nColCnt=mpModel->GetColCount();
/*N*/
/*N*/       if (mbCenterText && nColCnt > 1)
/*N*/               nColCnt--;
/*N*/
/*N*/       nDescrWidth = (long) (fAllTextLen / (double)nColCnt);
/*N*/   }
/*N*/   return nDescrWidth;
/*N*/ }

/*N*/ UINT32 ChartAxis::GetNumFormat( BOOL bPercent )
/*N*/ {
/*N*/   return ((const SfxUInt32Item&)mpAxisAttr->Get(bPercent
/*N*/       ? SCHATTR_AXIS_NUMFMTPERCENT : SCHATTR_AXIS_NUMFMT)).GetValue();
/*N*/ }

/*N*/ void ChartAxis::SetAxisList( SdrObjList *pList )
/*N*/ {
/*N*/   mpAxisList = pList;
/*N*/   maRectA = maRectB = Rectangle();
/*N*/ }

/*N*/ long ChartAxis::GetUniqueIdByObjectId( long nObjectId )
/*N*/ {
/*N*/     long nResult = CHAXIS_AXIS_UNKNOWN;
/*N*/
/*N*/     switch( nObjectId )
/*N*/     {
/*N*/         case CHOBJID_DIAGRAM_X_AXIS:
/*N*/             nResult = CHAXIS_AXIS_X;
/*N*/             break;
/*N*/         case CHOBJID_DIAGRAM_Y_AXIS:
/*N*/             nResult = CHAXIS_AXIS_Y;
/*N*/             break;
/*N*/         case CHOBJID_DIAGRAM_Z_AXIS:
/*N*/             nResult = CHAXIS_AXIS_Z;
/*N*/             break;
/*N*/         case CHOBJID_DIAGRAM_A_AXIS:
/*N*/             nResult = CHAXIS_AXIS_A;
/*N*/             break;
/*N*/         case CHOBJID_DIAGRAM_B_AXIS:
/*N*/             nResult = CHAXIS_AXIS_B;
/*N*/             break;
/*N*/     }
/*N*/
/*N*/     return nResult;
/*N*/ }
}

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