LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sc/source/core/data - validat.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 71 413 17.2 %
Date: 2013-07-09 Functions: 19 38 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "validat.hxx"
      21             : 
      22             : #include <sfx2/app.hxx>
      23             : #include <sfx2/docfile.hxx>
      24             : #include <sfx2/objsh.hxx>
      25             : #include <basic/sbmeth.hxx>
      26             : #include <basic/sbmod.hxx>
      27             : #include <basic/sbstar.hxx>
      28             : #include <basic/basmgr.hxx>
      29             : 
      30             : #include <basic/sbx.hxx>
      31             : #include <svl/zforlist.hxx>
      32             : #include <vcl/msgbox.hxx>
      33             : #include <rtl/math.hxx>
      34             : 
      35             : #include "scitems.hxx"
      36             : #include "document.hxx"
      37             : #include "formulacell.hxx"
      38             : #include "patattr.hxx"
      39             : #include "rechead.hxx"
      40             : #include "globstr.hrc"
      41             : #include "rangenam.hxx"
      42             : #include "dbdata.hxx"
      43             : #include "typedstrdata.hxx"
      44             : #include "dociter.hxx"
      45             : #include "editutil.hxx"
      46             : #include "tokenarray.hxx"
      47             : #include "scmatrix.hxx"
      48             : 
      49             : #include <math.h>
      50             : #include <memory>
      51             : 
      52             : using namespace formula;
      53             : 
      54             : //
      55             : //  Eintrag fuer Gueltigkeit (es gibt nur eine Bedingung)
      56             : //
      57             : 
      58          65 : ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
      59             :                             const String& rExpr1, const String& rExpr2,
      60             :                             ScDocument* pDocument, const ScAddress& rPos,
      61             :                             const String& rExprNmsp1, const String& rExprNmsp2,
      62             :                             FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
      63             :     ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
      64             :     nKey( 0 ),
      65             :     eDataMode( eMode ),
      66             :     eErrorStyle( SC_VALERR_STOP ),
      67          65 :     mnListType( ValidListType::UNSORTED )
      68             : {
      69          65 :     bShowInput = bShowError = false;
      70          65 : }
      71             : 
      72           3 : ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
      73             :                             const ScTokenArray* pArr1, const ScTokenArray* pArr2,
      74             :                             ScDocument* pDocument, const ScAddress& rPos ) :
      75             :     ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
      76             :     nKey( 0 ),
      77             :     eDataMode( eMode ),
      78             :     eErrorStyle( SC_VALERR_STOP ),
      79           3 :     mnListType( ValidListType::UNSORTED )
      80             : {
      81           3 :     bShowInput = bShowError = false;
      82           3 : }
      83             : 
      84           3 : ScValidationData::ScValidationData( const ScValidationData& r ) :
      85             :     ScConditionEntry( r ),
      86             :     nKey( r.nKey ),
      87             :     eDataMode( r.eDataMode ),
      88             :     bShowInput( r.bShowInput ),
      89             :     bShowError( r.bShowError ),
      90             :     eErrorStyle( r.eErrorStyle ),
      91             :     mnListType( r.mnListType ),
      92             :     aInputTitle( r.aInputTitle ),
      93             :     aInputMessage( r.aInputMessage ),
      94             :     aErrorTitle( r.aErrorTitle ),
      95           3 :     aErrorMessage( r.aErrorMessage )
      96             : {
      97             :     //  Formeln per RefCount kopiert
      98           3 : }
      99             : 
     100          26 : ScValidationData::ScValidationData( ScDocument* pDocument, const ScValidationData& r ) :
     101             :     ScConditionEntry( pDocument, r ),
     102             :     nKey( r.nKey ),
     103             :     eDataMode( r.eDataMode ),
     104             :     bShowInput( r.bShowInput ),
     105             :     bShowError( r.bShowError ),
     106             :     eErrorStyle( r.eErrorStyle ),
     107             :     mnListType( r.mnListType ),
     108             :     aInputTitle( r.aInputTitle ),
     109             :     aInputMessage( r.aInputMessage ),
     110             :     aErrorTitle( r.aErrorTitle ),
     111          26 :     aErrorMessage( r.aErrorMessage )
     112             : {
     113             :     //  Formeln wirklich kopiert
     114          26 : }
     115             : 
     116         139 : ScValidationData::~ScValidationData()
     117             : {
     118         139 : }
     119             : 
     120          33 : sal_Bool ScValidationData::IsEmpty() const
     121             : {
     122          33 :     String aEmpty;
     123          66 :     ScValidationData aDefault( SC_VALID_ANY, SC_COND_EQUAL, aEmpty, aEmpty, GetDocument(), ScAddress() );
     124          66 :     return EqualEntries( aDefault );
     125             : }
     126             : 
     127         114 : sal_Bool ScValidationData::EqualEntries( const ScValidationData& r ) const
     128             : {
     129             :         //  gleiche Parameter eingestellt (ohne Key)
     130             : 
     131         154 :     return ScConditionEntry::operator==(r) &&
     132          80 :             eDataMode       == r.eDataMode &&
     133          80 :             bShowInput      == r.bShowInput &&
     134          80 :             bShowError      == r.bShowError &&
     135          80 :             eErrorStyle     == r.eErrorStyle &&
     136          80 :             mnListType      == r.mnListType &&
     137          73 :             aInputTitle     == r.aInputTitle &&
     138          61 :             aInputMessage   == r.aInputMessage &&
     139         164 :             aErrorTitle     == r.aErrorTitle &&
     140         136 :             aErrorMessage   == r.aErrorMessage;
     141             : }
     142             : 
     143          30 : void ScValidationData::ResetInput()
     144             : {
     145          30 :     bShowInput = false;
     146          30 : }
     147             : 
     148          16 : void ScValidationData::ResetError()
     149             : {
     150          16 :     bShowError = false;
     151          16 : }
     152             : 
     153          30 : void ScValidationData::SetInput( const String& rTitle, const String& rMsg )
     154             : {
     155          30 :     bShowInput = sal_True;
     156          30 :     aInputTitle = rTitle;
     157          30 :     aInputMessage = rMsg;
     158          30 : }
     159             : 
     160          35 : void ScValidationData::SetError( const String& rTitle, const String& rMsg,
     161             :                                     ScValidErrorStyle eStyle )
     162             : {
     163          35 :     bShowError = sal_True;
     164          35 :     eErrorStyle = eStyle;
     165          35 :     aErrorTitle = rTitle;
     166          35 :     aErrorMessage = rMsg;
     167          35 : }
     168             : 
     169          48 : sal_Bool ScValidationData::GetErrMsg( String& rTitle, String& rMsg,
     170             :                                     ScValidErrorStyle& rStyle ) const
     171             : {
     172          48 :     rTitle = aErrorTitle;
     173          48 :     rMsg   = aErrorMessage;
     174          48 :     rStyle = eErrorStyle;
     175          48 :     return bShowError;
     176             : }
     177             : 
     178           0 : sal_Bool ScValidationData::DoScript( const ScAddress& rPos, const String& rInput,
     179             :                                 ScFormulaCell* pCell, Window* pParent ) const
     180             : {
     181           0 :     ScDocument* pDocument = GetDocument();
     182           0 :     SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
     183           0 :     if ( !pDocSh || !pDocument->CheckMacroWarn() )
     184           0 :         return false;
     185             : 
     186           0 :     sal_Bool bScriptReturnedFalse = false;  // Standard: kein Abbruch
     187             : 
     188             :     // Set up parameters
     189           0 :     ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aParams(2);
     190             : 
     191             :     //  1) eingegebener / berechneter Wert
     192           0 :     String aValStr = rInput;
     193             :     double nValue;
     194           0 :     sal_Bool bIsValue = false;
     195           0 :     if ( pCell )                // wenn Zelle gesetzt, aus Interpret gerufen
     196             :     {
     197           0 :         bIsValue = pCell->IsValue();
     198           0 :         if ( bIsValue )
     199           0 :             nValue  = pCell->GetValue();
     200             :         else
     201           0 :             aValStr = pCell->GetString();
     202             :     }
     203           0 :     if ( bIsValue )
     204           0 :         aParams[0] = ::com::sun::star::uno::makeAny( nValue );
     205             :     else
     206           0 :         aParams[0] = ::com::sun::star::uno::makeAny( OUString( aValStr ) );
     207             : 
     208             :     //  2) Position der Zelle
     209           0 :     String aPosStr;
     210           0 :     rPos.Format( aPosStr, SCA_VALID | SCA_TAB_3D, pDocument, pDocument->GetAddressConvention() );
     211           0 :     aParams[1] = ::com::sun::star::uno::makeAny( OUString( aPosStr ) );
     212             : 
     213             :     //  use link-update flag to prevent closing the document
     214             :     //  while the macro is running
     215           0 :     sal_Bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
     216           0 :     if ( !bWasInLinkUpdate )
     217           0 :         pDocument->SetInLinkUpdate( sal_True );
     218             : 
     219           0 :     if ( pCell )
     220           0 :         pDocument->LockTable( rPos.Tab() );
     221             : 
     222           0 :     ::com::sun::star::uno::Any aRet;
     223           0 :     ::com::sun::star::uno::Sequence< sal_Int16 > aOutArgsIndex;
     224           0 :     ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aOutArgs;
     225             : 
     226             :     ErrCode eRet = pDocSh->CallXScript(
     227           0 :         aErrorTitle, aParams, aRet, aOutArgsIndex, aOutArgs );
     228             : 
     229           0 :     if ( pCell )
     230           0 :         pDocument->UnlockTable( rPos.Tab() );
     231             : 
     232           0 :     if ( !bWasInLinkUpdate )
     233           0 :         pDocument->SetInLinkUpdate( false );
     234             : 
     235             :     // Check the return value from the script
     236             :     // The contents of the cell get reset if the script returns false
     237           0 :     sal_Bool bTmp = false;
     238           0 :     if ( eRet == ERRCODE_NONE &&
     239           0 :              aRet.getValueType() == getCppuBooleanType() &&
     240           0 :              sal_True == ( aRet >>= bTmp ) &&
     241           0 :              bTmp == false )
     242             :     {
     243           0 :         bScriptReturnedFalse = sal_True;
     244             :     }
     245             : 
     246           0 :     if ( eRet == ERRCODE_BASIC_METHOD_NOT_FOUND && !pCell )
     247             :     // Makro nicht gefunden (nur bei Eingabe)
     248             :     {
     249             :         //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
     250             : 
     251             :         ErrorBox aBox( pParent, WinBits(WB_OK),
     252           0 :                         ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND ) );
     253           0 :         aBox.Execute();
     254             :     }
     255             : 
     256           0 :     return bScriptReturnedFalse;
     257             : }
     258             : 
     259             :     // sal_True -> Abbruch
     260             : 
     261           0 : sal_Bool ScValidationData::DoMacro( const ScAddress& rPos, const String& rInput,
     262             :                                 ScFormulaCell* pCell, Window* pParent ) const
     263             : {
     264           0 :     if ( SfxApplication::IsXScriptURL( aErrorTitle ) )
     265             :     {
     266           0 :         return DoScript( rPos, rInput, pCell, pParent );
     267             :     }
     268             : 
     269           0 :     ScDocument* pDocument = GetDocument();
     270           0 :     SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
     271           0 :     if ( !pDocSh || !pDocument->CheckMacroWarn() )
     272           0 :         return false;
     273             : 
     274           0 :     sal_Bool bDone = false;
     275           0 :     sal_Bool bRet = false;                      // Standard: kein Abbruch
     276             : 
     277             :     //  Wenn das Dok waehrend eines Basic-Calls geladen wurde,
     278             :     //  ist das Sbx-Objekt evtl. nicht angelegt (?)
     279             : //  pDocSh->GetSbxObject();
     280             : 
     281             : #ifndef DISABLE_SCRIPTING
     282             :     //  keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
     283             : 
     284             :     //  Funktion ueber den einfachen Namen suchen,
     285             :     //  dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
     286             : 
     287           0 :     StarBASIC* pRoot = pDocSh->GetBasic();
     288           0 :     SbxVariable* pVar = pRoot->Find( aErrorTitle, SbxCLASS_METHOD );
     289           0 :     if ( pVar && pVar->ISA(SbMethod) )
     290             :     {
     291           0 :         SbMethod* pMethod = (SbMethod*)pVar;
     292           0 :         SbModule* pModule = pMethod->GetModule();
     293           0 :         SbxObject* pObject = pModule->GetParent();
     294           0 :         String aMacroStr = pObject->GetName();
     295           0 :         aMacroStr += '.';
     296           0 :         aMacroStr += pModule->GetName();
     297           0 :         aMacroStr += '.';
     298           0 :         aMacroStr += pMethod->GetName();
     299           0 :         String aBasicStr;
     300             : 
     301             :         //  the distinction between document- and app-basic has to be done
     302             :         //  by checking the parent (as in ScInterpreter::ScMacro), not by looping
     303             :         //  over all open documents, because this may be called from within loading,
     304             :         //  when SfxObjectShell::GetFirst/GetNext won't find the document.
     305             : 
     306           0 :         if ( pObject->GetParent() )
     307           0 :             aBasicStr = pObject->GetParent()->GetName();    // Dokumentenbasic
     308             :         else
     309           0 :             aBasicStr = SFX_APP()->GetName();               // Applikationsbasic
     310             : 
     311             :         //  Parameter fuer Makro
     312           0 :         SbxArrayRef refPar = new SbxArray;
     313             : 
     314             :         //  1) eingegebener / berechneter Wert
     315           0 :         String aValStr = rInput;
     316           0 :         double nValue = 0.0;
     317           0 :         sal_Bool bIsValue = false;
     318           0 :         if ( pCell )                // wenn Zelle gesetzt, aus Interpret gerufen
     319             :         {
     320           0 :             bIsValue = pCell->IsValue();
     321           0 :             if ( bIsValue )
     322           0 :                 nValue  = pCell->GetValue();
     323             :             else
     324           0 :                 aValStr = pCell->GetString();
     325             :         }
     326           0 :         if ( bIsValue )
     327           0 :             refPar->Get(1)->PutDouble( nValue );
     328             :         else
     329           0 :             refPar->Get(1)->PutString( aValStr );
     330             : 
     331             :         //  2) Position der Zelle
     332           0 :         String aPosStr;
     333           0 :         rPos.Format( aPosStr, SCA_VALID | SCA_TAB_3D, pDocument, pDocument->GetAddressConvention() );
     334           0 :         refPar->Get(2)->PutString( aPosStr );
     335             : 
     336             :         //  use link-update flag to prevent closing the document
     337             :         //  while the macro is running
     338           0 :         sal_Bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
     339           0 :         if ( !bWasInLinkUpdate )
     340           0 :             pDocument->SetInLinkUpdate( sal_True );
     341             : 
     342           0 :         if ( pCell )
     343           0 :             pDocument->LockTable( rPos.Tab() );
     344           0 :         SbxVariableRef refRes = new SbxVariable;
     345           0 :         ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, refPar, refRes );
     346           0 :         if ( pCell )
     347           0 :             pDocument->UnlockTable( rPos.Tab() );
     348             : 
     349           0 :         if ( !bWasInLinkUpdate )
     350           0 :             pDocument->SetInLinkUpdate( false );
     351             : 
     352             :         //  Eingabe abbrechen, wenn Basic-Makro sal_False zurueckgibt
     353           0 :         if ( eRet == ERRCODE_NONE && refRes->GetType() == SbxBOOL && refRes->GetBool() == false )
     354           0 :             bRet = sal_True;
     355           0 :         bDone = sal_True;
     356             :     }
     357             : #endif
     358           0 :     if ( !bDone && !pCell )         // Makro nicht gefunden (nur bei Eingabe)
     359             :     {
     360             :         //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
     361             : 
     362             :         ErrorBox aBox( pParent, WinBits(WB_OK),
     363           0 :                         ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND ) );
     364           0 :         aBox.Execute();
     365             :     }
     366             : 
     367           0 :     return bRet;
     368             : }
     369             : 
     370           0 : void ScValidationData::DoCalcError( ScFormulaCell* pCell ) const
     371             : {
     372           0 :     if ( eErrorStyle == SC_VALERR_MACRO )
     373           0 :         DoMacro( pCell->aPos, EMPTY_STRING, pCell, NULL );
     374           0 : }
     375             : 
     376             :     // sal_True -> Abbruch
     377             : 
     378           0 : sal_Bool ScValidationData::DoError( Window* pParent, const String& rInput,
     379             :                                 const ScAddress& rPos ) const
     380             : {
     381           0 :     if ( eErrorStyle == SC_VALERR_MACRO )
     382           0 :         return DoMacro( rPos, rInput, NULL, pParent );
     383             : 
     384             :     //  Fehlermeldung ausgeben
     385             : 
     386           0 :     String aTitle = aErrorTitle;
     387           0 :     if (!aTitle.Len())
     388           0 :         aTitle = ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 );  // application title
     389           0 :     String aMessage = aErrorMessage;
     390           0 :     if (!aMessage.Len())
     391           0 :         aMessage = ScGlobal::GetRscString( STR_VALID_DEFERROR );
     392             : 
     393             :     //! ErrorBox / WarningBox / InfoBox ?
     394             :     //! (bei InfoBox immer nur OK-Button)
     395             : 
     396           0 :     WinBits nStyle = 0;
     397           0 :     switch (eErrorStyle)
     398             :     {
     399             :         case SC_VALERR_STOP:
     400           0 :             nStyle = WB_OK | WB_DEF_OK;
     401           0 :             break;
     402             :         case SC_VALERR_WARNING:
     403           0 :             nStyle = WB_OK_CANCEL | WB_DEF_CANCEL;
     404           0 :             break;
     405             :         case SC_VALERR_INFO:
     406           0 :             nStyle = WB_OK_CANCEL | WB_DEF_OK;
     407           0 :             break;
     408             :         default:
     409             :         {
     410             :             // added to avoid warnings
     411             :         }
     412             :     }
     413             : 
     414           0 :     MessBox aBox( pParent, WinBits(nStyle), aTitle, aMessage );
     415           0 :     sal_uInt16 nRet = aBox.Execute();
     416             : 
     417           0 :     return ( eErrorStyle == SC_VALERR_STOP || nRet == RET_CANCEL );
     418             : }
     419             : 
     420             : 
     421           0 : bool ScValidationData::IsDataValid(
     422             :     const OUString& rTest, const ScPatternAttr& rPattern, const ScAddress& rPos ) const
     423             : {
     424           0 :     if ( eDataMode == SC_VALID_ANY ) // check if any cell content is allowed
     425           0 :         return sal_True;
     426             : 
     427           0 :     if (rTest.isEmpty())              // check whether empty cells are allowed
     428           0 :         return IsIgnoreBlank();
     429             : 
     430           0 :     if (rTest[0] == '=')   // formulas do not pass the validity test
     431           0 :         return false;
     432             : 
     433             : 
     434           0 :     SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
     435             : 
     436             :     // get the value if any
     437           0 :     sal_uInt32 nFormat = rPattern.GetNumberFormat( pFormatter );
     438             :     double nVal;
     439           0 :     sal_Bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
     440             : 
     441             :     sal_Bool bRet;
     442           0 :     if (SC_VALID_TEXTLEN == eDataMode)
     443             :     {
     444             :         double nLenVal;
     445           0 :         if (!bIsVal)
     446           0 :             nLenVal = static_cast<double>(rTest.getLength());
     447             :         else
     448             :         {
     449             :             // For numeric values use the resulting input line string to
     450             :             // determine length, otherwise a once accepted value maybe could
     451             :             // not be edited again, for example abbreviated dates or leading
     452             :             // zeros or trailing zeros after decimal separator change length.
     453           0 :             OUString aStr;
     454           0 :             pFormatter->GetInputLineString( nVal, nFormat, aStr);
     455           0 :             nLenVal = static_cast<double>( aStr.getLength() );
     456             :         }
     457           0 :         ScRefCellValue aTmpCell(nLenVal);
     458           0 :         bRet = IsCellValid(aTmpCell, rPos);
     459             :     }
     460             :     else
     461             :     {
     462           0 :         if (bIsVal)
     463             :         {
     464           0 :             ScRefCellValue aTmpCell(nVal);
     465           0 :             bRet = IsDataValid(aTmpCell, rPos);
     466             :         }
     467             :         else
     468             :         {
     469           0 :             ScRefCellValue aTmpCell(&rTest);
     470           0 :             bRet = IsDataValid(aTmpCell, rPos);
     471             :         }
     472             :     }
     473             : 
     474           0 :     return bRet;
     475             : }
     476             : 
     477           0 : bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
     478             : {
     479           0 :     if( eDataMode == SC_VALID_LIST )
     480           0 :         return IsListValid(rCell, rPos);
     481             : 
     482           0 :     double nVal = 0.0;
     483           0 :     OUString aString;
     484           0 :     bool bIsVal = true;
     485             : 
     486           0 :     switch (rCell.meType)
     487             :     {
     488             :         case CELLTYPE_VALUE:
     489           0 :             nVal = rCell.mfValue;
     490           0 :         break;
     491             :         case CELLTYPE_STRING:
     492           0 :             aString = *rCell.mpString;
     493           0 :             bIsVal = false;
     494           0 :         break;
     495             :         case CELLTYPE_EDIT:
     496           0 :             if (rCell.mpEditText)
     497           0 :                 aString = ScEditUtil::GetString(*rCell.mpEditText);
     498           0 :             bIsVal = false;
     499           0 :         break;
     500             :         case CELLTYPE_FORMULA:
     501             :         {
     502           0 :             ScFormulaCell* pFCell = rCell.mpFormula;
     503           0 :             bIsVal = pFCell->IsValue();
     504           0 :             if ( bIsVal )
     505           0 :                 nVal  = pFCell->GetValue();
     506             :             else
     507           0 :                 aString = pFCell->GetString();
     508             :         }
     509           0 :         break;
     510             :         default:                        // Notizen, Broadcaster
     511           0 :             return IsIgnoreBlank();     // wie eingestellt
     512             :     }
     513             : 
     514           0 :     bool bOk = true;
     515           0 :     switch (eDataMode)
     516             :     {
     517             :         // SC_VALID_ANY schon oben
     518             : 
     519             :         case SC_VALID_WHOLE:
     520             :         case SC_VALID_DECIMAL:
     521             :         case SC_VALID_DATE:         // Date/Time ist nur Formatierung
     522             :         case SC_VALID_TIME:
     523           0 :             bOk = bIsVal;
     524           0 :             if ( bOk && eDataMode == SC_VALID_WHOLE )
     525           0 :                 bOk = ::rtl::math::approxEqual( nVal, floor(nVal+0.5) );        // ganze Zahlen
     526           0 :             if ( bOk )
     527           0 :                 bOk = IsCellValid(rCell, rPos);
     528           0 :             break;
     529             : 
     530             :         case SC_VALID_CUSTOM:
     531             :             //  fuer Custom muss eOp == SC_COND_DIRECT sein
     532             :             //! der Wert muss im Dokument stehen !!!!!!!!!!!!!!!!!!!!
     533           0 :             bOk = IsCellValid(rCell, rPos);
     534           0 :             break;
     535             : 
     536             :         case SC_VALID_TEXTLEN:
     537           0 :             bOk = !bIsVal;          // nur Text
     538           0 :             if ( bOk )
     539             :             {
     540           0 :                 double nLenVal = (double) aString.getLength();
     541           0 :                 ScRefCellValue aTmpCell(nLenVal);
     542           0 :                 bOk = IsCellValid(aTmpCell, rPos);
     543             :             }
     544           0 :             break;
     545             : 
     546             :         default:
     547             :             OSL_FAIL("not yet done");
     548           0 :             break;
     549             :     }
     550             : 
     551           0 :     return bOk;
     552             : }
     553             : 
     554             : namespace {
     555             : 
     556             : /** Token array helper. Iterates over all string tokens.
     557             :     @descr  The token array must contain separated string tokens only.
     558             :     @param bSkipEmpty  true = Ignores string tokens with empty strings. */
     559             : class ScStringTokenIterator
     560             : {
     561             : public:
     562           0 :     inline explicit             ScStringTokenIterator( ScTokenArray& rTokArr, bool bSkipEmpty = true ) :
     563           0 :                                     mrTokArr( rTokArr ), mbSkipEmpty( bSkipEmpty ), mbOk( true ) {}
     564             : 
     565             :     /** Returns the string of the first string token or NULL on error or empty token array. */
     566             :     const String*               First();
     567             :     /** Returns the string of the next string token or NULL on error or end of token array. */
     568             :     const String*               Next();
     569             : 
     570             :     /** Returns false, if a wrong token has been found. Does NOT return false on end of token array. */
     571           0 :     inline bool                 Ok() const { return mbOk; }
     572             : 
     573             : private:
     574             :     ScTokenArray&               mrTokArr;       /// The token array for iteration.
     575             :     bool                        mbSkipEmpty;    /// Ignore empty strings.
     576             :     bool                        mbOk;           /// true = correct token or end of token array.
     577             : };
     578             : 
     579           0 : const String* ScStringTokenIterator::First()
     580             : {
     581           0 :     mrTokArr.Reset();
     582           0 :     mbOk = true;
     583           0 :     return Next();
     584             : }
     585             : 
     586           0 : const String* ScStringTokenIterator::Next()
     587             : {
     588           0 :     if( !mbOk )
     589           0 :         return NULL;
     590             : 
     591             :     // seek to next non-separator token
     592           0 :     const FormulaToken* pToken = mrTokArr.NextNoSpaces();
     593           0 :     while( pToken && (pToken->GetOpCode() == ocSep) )
     594           0 :         pToken = mrTokArr.NextNoSpaces();
     595             : 
     596           0 :     mbOk = !pToken || (pToken->GetType() == formula::svString);
     597           0 :     const String* pString = (mbOk && pToken) ? &pToken->GetString() : NULL;
     598             :     // string found but empty -> get next token; otherwise return it
     599           0 :     return (mbSkipEmpty && pString && !pString->Len()) ? Next() : pString;
     600             : }
     601             : 
     602             : // ----------------------------------------------------------------------------
     603             : 
     604             : /** Returns the number format of the passed cell, or the standard format. */
     605           0 : sal_uLong lclGetCellFormat( ScDocument& rDoc, const ScAddress& rPos )
     606             : {
     607           0 :     const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() );
     608           0 :     if( !pPattern )
     609           0 :         pPattern = rDoc.GetDefPattern();
     610           0 :     return pPattern->GetNumberFormat( rDoc.GetFormatTable() );
     611             : }
     612             : 
     613             : } // namespace
     614             : 
     615             : // ----------------------------------------------------------------------------
     616             : 
     617           0 : bool ScValidationData::HasSelectionList() const
     618             : {
     619           0 :     return (eDataMode == SC_VALID_LIST) && (mnListType != ValidListType::INVISIBLE);
     620             : }
     621             : 
     622           0 : bool ScValidationData::GetSelectionFromFormula(
     623             :     std::vector<ScTypedStrData>* pStrings, ScRefCellValue& rCell, const ScAddress& rPos,
     624             :     const ScTokenArray& rTokArr, int& rMatch) const
     625             : {
     626           0 :     bool bOk = true;
     627             : 
     628             :     // pDoc is private in condition, use an accessor and a long winded name.
     629           0 :     ScDocument* pDocument = GetDocument();
     630           0 :     if( NULL == pDocument )
     631           0 :         return false;
     632             : 
     633             :     ScFormulaCell aValidationSrc( pDocument, rPos, &rTokArr,
     634           0 :            formula::FormulaGrammar::GRAM_DEFAULT, MM_FORMULA);
     635             : 
     636             :     // Make sure the formula gets interpreted and a result is delivered,
     637             :     // regardless of the AutoCalc setting.
     638           0 :     aValidationSrc.Interpret();
     639             : 
     640           0 :     ScMatrixRef xMatRef;
     641           0 :     const ScMatrix *pValues = aValidationSrc.GetMatrix();
     642           0 :     if (!pValues)
     643             :     {
     644             :         // The somewhat nasty case of either an error occurred, or the
     645             :         // dereferenced value of a single cell reference or an immediate result
     646             :         // is stored as a single value.
     647             : 
     648             :         // Use an interim matrix to create the TypedStrData below.
     649           0 :         xMatRef = new ScMatrix(1, 1, 0.0);
     650             : 
     651           0 :         sal_uInt16 nErrCode = aValidationSrc.GetErrCode();
     652           0 :         if (nErrCode)
     653             :         {
     654             :             /* TODO : to use later in an alert box?
     655             :              * String rStrResult = "...";
     656             :              * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
     657             :              */
     658             : 
     659           0 :             xMatRef->PutError( nErrCode, 0, 0);
     660           0 :             bOk = false;
     661             :         }
     662           0 :         else if (aValidationSrc.IsValue())
     663           0 :             xMatRef->PutDouble( aValidationSrc.GetValue(), 0);
     664             :         else
     665             :         {
     666           0 :             String aStr = aValidationSrc.GetString();
     667           0 :             xMatRef->PutString( aStr, 0);
     668             :         }
     669             : 
     670           0 :         pValues = xMatRef.get();
     671             :     }
     672             : 
     673             :     // which index matched.  We will want it eventually to pre-select that item.
     674           0 :     rMatch = -1;
     675             : 
     676           0 :     SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
     677             : 
     678           0 :     SCSIZE  nCol, nRow, nCols, nRows, n = 0;
     679           0 :     pValues->GetDimensions( nCols, nRows );
     680             : 
     681           0 :     bool bRef = false;
     682           0 :     ScRange aRange;
     683             : 
     684           0 :     ScTokenArray* pArr = (ScTokenArray*) &rTokArr;
     685           0 :     pArr->Reset();
     686           0 :     ScToken* t = NULL;
     687           0 :     if (pArr->GetLen() == 1 && (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL)
     688             :     {
     689           0 :         if (t->GetOpCode() == ocDBArea)
     690             :         {
     691           0 :             if (const ScDBData* pDBData = pDocument->GetDBCollection()->getNamedDBs().findByIndex(t->GetIndex()))
     692             :             {
     693           0 :                 pDBData->GetArea(aRange);
     694           0 :                 bRef = true;
     695             :             }
     696             :         }
     697           0 :         else if (t->GetOpCode() == ocName)
     698             :         {
     699           0 :             ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
     700           0 :             if (pName && pName->IsReference(aRange))
     701             :             {
     702           0 :                 bRef = true;
     703             :             }
     704             :         }
     705           0 :         else if (t->GetType() != svIndex)
     706             :         {
     707           0 :             t->CalcAbsIfRel(rPos);
     708           0 :             if (pArr->IsValidReference(aRange))
     709             :             {
     710           0 :                 bRef = true;
     711             :             }
     712             :         }
     713             :     }
     714             : 
     715             :     /* XL artificially limits things to a single col or row in the UI but does
     716             :      * not list the constraint in MOOXml. If a defined name or INDIRECT
     717             :      * resulting in 1D is entered in the UI and the definition later modified
     718             :      * to 2D, it is evaluated fine and also stored and loaded.  Lets get ahead
     719             :      * of the curve and support 2d. In XL, values are listed row-wise, do the
     720             :      * same. */
     721           0 :     for( nRow = 0; nRow < nRows ; nRow++ )
     722             :     {
     723           0 :         for( nCol = 0; nCol < nCols ; nCol++ )
     724             :         {
     725           0 :             ScTokenArray         aCondTokArr;
     726           0 :             ScTypedStrData*        pEntry = NULL;
     727           0 :             String               aValStr;
     728           0 :             ScMatrixValue nMatVal = pValues->Get( nCol, nRow);
     729             : 
     730             :             // strings and empties
     731           0 :             if( ScMatrix::IsNonValueType( nMatVal.nType ) )
     732             :             {
     733           0 :                 aValStr = nMatVal.GetString();
     734             : 
     735           0 :                 if( NULL != pStrings )
     736           0 :                     pEntry = new ScTypedStrData( aValStr, 0.0, ScTypedStrData::Standard);
     737             : 
     738           0 :                 if (!rCell.isEmpty() && rMatch < 0)
     739           0 :                     aCondTokArr.AddString( aValStr );
     740             :             }
     741             :             else
     742             :             {
     743           0 :                 sal_uInt16 nErr = nMatVal.GetError();
     744             : 
     745           0 :                 if( 0 != nErr )
     746             :                 {
     747           0 :                     aValStr = ScGlobal::GetErrorString( nErr );
     748             :                 }
     749             :                 else
     750             :                 {
     751             :                     // FIXME FIXME FIXME
     752             :                     // Feature regression.  Date formats are lost passing through the matrix
     753             :                     //pFormatter->GetInputLineString( pMatVal->fVal, 0, aValStr );
     754             :                     //For external reference and a formula that results in an area or array, date formats are still lost.
     755           0 :                     if ( bRef )
     756             :                     {
     757           0 :                         pDocument->GetInputString((SCCOL)(nCol+aRange.aStart.Col()),
     758           0 :                             (SCROW)(nRow+aRange.aStart.Row()), aRange.aStart.Tab() , aValStr);
     759             :                     }
     760             :                     else
     761             :                     {
     762           0 :                         OUString sTmp(aValStr);
     763           0 :                         pFormatter->GetInputLineString( nMatVal.fVal, 0, sTmp );
     764           0 :                         aValStr = sTmp;
     765             :                     }
     766             :                 }
     767             : 
     768           0 :                 if (!rCell.isEmpty() && rMatch < 0)
     769             :                 {
     770             :                     // I am not sure errors will work here, but a user can no
     771             :                     // manually enter an error yet so the point is somewhat moot.
     772           0 :                     aCondTokArr.AddDouble( nMatVal.fVal );
     773             :                 }
     774           0 :                 if( NULL != pStrings )
     775           0 :                     pEntry = new ScTypedStrData( aValStr, nMatVal.fVal, ScTypedStrData::Value);
     776             :             }
     777             : 
     778           0 :             if (rMatch < 0 && !rCell.isEmpty() && IsEqualToTokenArray(rCell, rPos, aCondTokArr))
     779             :             {
     780           0 :                 rMatch = n;
     781             :                 // short circuit on the first match if not filling the list
     782           0 :                 if( NULL == pStrings )
     783           0 :                     return true;
     784             :             }
     785             : 
     786           0 :             if( NULL != pEntry )
     787             :             {
     788           0 :                 pStrings->push_back(*pEntry);
     789           0 :                 delete pEntry;
     790           0 :                 n++;
     791             :             }
     792           0 :         }
     793             :     }
     794             : 
     795             :     // In case of no match needed and an error occurred, return that error
     796             :     // entry as valid instead of silently failing.
     797           0 :     return bOk || rCell.isEmpty();
     798             : }
     799             : 
     800           0 : bool ScValidationData::FillSelectionList(std::vector<ScTypedStrData>& rStrColl, const ScAddress& rPos) const
     801             : {
     802           0 :     bool bOk = false;
     803             : 
     804           0 :     if( HasSelectionList() )
     805             :     {
     806           0 :         boost::scoped_ptr<ScTokenArray> pTokArr( CreateTokenArry(0) );
     807             : 
     808             :         // *** try if formula is a string list ***
     809             : 
     810           0 :         sal_uInt32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
     811           0 :         ScStringTokenIterator aIt( *pTokArr );
     812           0 :         for( const String* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next() )
     813             :         {
     814             :             double fValue;
     815           0 :             bool bIsValue = GetDocument()->GetFormatTable()->IsNumberFormat( *pString, nFormat, fValue );
     816             :             rStrColl.push_back(
     817             :                 ScTypedStrData(
     818           0 :                     *pString, fValue, bIsValue ? ScTypedStrData::Value : ScTypedStrData::Standard));
     819             :         }
     820           0 :         bOk = aIt.Ok();
     821             : 
     822             :         // *** if not a string list, try if formula results in a cell range or
     823             :         // anything else we recognize as valid ***
     824             : 
     825           0 :         if (!bOk)
     826             :         {
     827             :             int nMatch;
     828           0 :             ScRefCellValue aEmptyCell;
     829           0 :             bOk = GetSelectionFromFormula(&rStrColl, aEmptyCell, rPos, *pTokArr, nMatch);
     830           0 :         }
     831             :     }
     832             : 
     833           0 :     return bOk;
     834             : }
     835             : 
     836             : // ----------------------------------------------------------------------------
     837             : 
     838           0 : bool ScValidationData::IsEqualToTokenArray( ScRefCellValue& rCell, const ScAddress& rPos, const ScTokenArray& rTokArr ) const
     839             : {
     840             :     // create a condition entry that tests on equality and set the passed token array
     841           0 :     ScConditionEntry aCondEntry( SC_COND_EQUAL, &rTokArr, NULL, GetDocument(), rPos );
     842           0 :     return aCondEntry.IsCellValid(rCell, rPos);
     843             : }
     844             : 
     845           0 : bool ScValidationData::IsListValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
     846             : {
     847           0 :     bool bIsValid = false;
     848             : 
     849             :     /*  Compare input cell with all supported tokens from the formula.
     850             :         Currently a formula may contain:
     851             :         1)  A list of strings (at least one string).
     852             :         2)  A single cell or range reference.
     853             :         3)  A single defined name (must contain a cell/range reference, another
     854             :             name, or DB range, or a formula resulting in a cell/range reference
     855             :             or matrix/array).
     856             :         4)  A single database range.
     857             :         5)  A formula resulting in a cell/range reference or matrix/array.
     858             :     */
     859             : 
     860             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
     861           0 :     ::std::auto_ptr< ScTokenArray > pTokArr( CreateTokenArry( 0 ) );
     862             :     SAL_WNODEPRECATED_DECLARATIONS_POP
     863             : 
     864             :     // *** try if formula is a string list ***
     865             : 
     866           0 :     sal_uInt32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
     867           0 :     ScStringTokenIterator aIt( *pTokArr );
     868           0 :     for( const String* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next() )
     869             :     {
     870             :         /*  Do not break the loop, if a valid string has been found.
     871             :             This is to find invalid tokens following in the formula. */
     872           0 :         if( !bIsValid )
     873             :         {
     874             :             // create a formula containing a single string or number
     875           0 :             ScTokenArray aCondTokArr;
     876             :             double fValue;
     877           0 :             if( GetDocument()->GetFormatTable()->IsNumberFormat( *pString, nFormat, fValue ) )
     878           0 :                 aCondTokArr.AddDouble( fValue );
     879             :             else
     880           0 :                 aCondTokArr.AddString( *pString );
     881             : 
     882           0 :             bIsValid = IsEqualToTokenArray(rCell, rPos, aCondTokArr);
     883             :         }
     884             :     }
     885             : 
     886           0 :     if( !aIt.Ok() )
     887           0 :         bIsValid = false;
     888             : 
     889             :     // *** if not a string list, try if formula results in a cell range or
     890             :     // anything else we recognize as valid ***
     891             : 
     892           0 :     if (!bIsValid)
     893             :     {
     894             :         int nMatch;
     895           0 :         bIsValid = GetSelectionFromFormula(NULL, rCell, rPos, *pTokArr, nMatch);
     896           0 :         bIsValid = bIsValid && nMatch >= 0;
     897             :     }
     898             : 
     899           0 :     return bIsValid;
     900             : }
     901             : 
     902             : // ============================================================================
     903             : // ============================================================================
     904             : 
     905           0 : ScValidationDataList::ScValidationDataList(const ScValidationDataList& rList) :
     906           0 :     std::set<ScValidationData*, CompareScValidationDataPtr>()
     907             : {
     908             :     //  fuer Ref-Undo - echte Kopie mit neuen Tokens!
     909             : 
     910           0 :     for (const_iterator it = rList.begin(); it != rList.end(); ++it)
     911             :     {
     912           0 :         InsertNew( (*it)->Clone() );
     913             :     }
     914             : 
     915             :     //!     sortierte Eintraege aus rList schneller einfuegen ???
     916           0 : }
     917             : 
     918           1 : ScValidationDataList::ScValidationDataList(ScDocument* pNewDoc,
     919           1 :                                             const ScValidationDataList& rList)
     920             : {
     921             :     //  fuer neues Dokument - echte Kopie mit neuen Tokens!
     922             : 
     923          11 :     for (const_iterator it = rList.begin(); it != rList.end(); ++it)
     924             :     {
     925          10 :         InsertNew( (*it)->Clone(pNewDoc) );
     926             :     }
     927             : 
     928             :     //!     sortierte Eintraege aus rList schneller einfuegen ???
     929           1 : }
     930             : 
     931          82 : ScValidationData* ScValidationDataList::GetData( sal_uInt32 nKey )
     932             : {
     933             :     //! binaer suchen
     934             : 
     935         201 :     for( iterator it = begin(); it != end(); ++it )
     936         201 :         if( (*it)->GetKey() == nKey )
     937          82 :             return *it;
     938             : 
     939             :     OSL_FAIL("ScValidationDataList: Entry not found");
     940           0 :     return NULL;
     941             : }
     942             : 
     943           1 : void ScValidationDataList::CompileXML()
     944             : {
     945           3 :     for( iterator it = begin(); it != end(); ++it )
     946           2 :         (*it)->CompileXML();
     947           1 : }
     948             : 
     949           5 : void ScValidationDataList::UpdateReference( UpdateRefMode eUpdateRefMode,
     950             :                                 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     951             : {
     952          19 :     for( iterator it = begin(); it != end(); ++it )
     953          14 :         (*it)->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz);
     954           5 : }
     955             : 
     956           0 : void ScValidationDataList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
     957             : {
     958           0 :     for( iterator it = begin(); it != end(); ++it )
     959           0 :         (*it)->UpdateMoveTab( nOldPos, nNewPos );
     960           0 : }
     961             : 
     962           0 : sal_Bool ScValidationDataList::operator==( const ScValidationDataList& r ) const
     963             : {
     964             :     // fuer Ref-Undo - interne Variablen werden nicht verglichen
     965             : 
     966           0 :     sal_uInt16 nCount = size();
     967           0 :     sal_Bool bEqual = ( nCount == r.size() );
     968           0 :     for( const_iterator it1 = begin(), it2 = r.begin(); it1 != end() && bEqual; ++it1, ++it2 ) // Eintraege sind sortiert
     969           0 :         if ( !(*it1)->EqualEntries(**it2) )         // Eintraege unterschiedlich ?
     970           0 :             bEqual = sal_False;
     971             : 
     972           0 :     return bEqual;
     973          93 : }
     974             : 
     975             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10