LCOV - code coverage report
Current view: top level - sc/source/core/data - validat.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 79 432 18.3 %
Date: 2014-04-11 Functions: 22 44 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 "svl/sharedstringpool.hxx"
      33             : #include <vcl/msgbox.hxx>
      34             : #include <rtl/math.hxx>
      35             : 
      36             : #include "scitems.hxx"
      37             : #include "document.hxx"
      38             : #include "formulacell.hxx"
      39             : #include "patattr.hxx"
      40             : #include "rechead.hxx"
      41             : #include "globstr.hrc"
      42             : #include "rangenam.hxx"
      43             : #include "dbdata.hxx"
      44             : #include "typedstrdata.hxx"
      45             : #include "dociter.hxx"
      46             : #include "editutil.hxx"
      47             : #include "tokenarray.hxx"
      48             : #include "scmatrix.hxx"
      49             : 
      50             : #include <math.h>
      51             : #include <boost/scoped_ptr.hpp>
      52             : 
      53             : using namespace formula;
      54             : 
      55             : 
      56             : //  Eintrag fuer Gueltigkeit (es gibt nur eine Bedingung)
      57             : 
      58             : 
      59          65 : ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
      60             :                                     const OUString& rExpr1, const OUString& rExpr2,
      61             :                                     ScDocument* pDocument, const ScAddress& rPos,
      62             :                                     const OUString& rExprNmsp1, const OUString& rExprNmsp2,
      63             :                                     FormulaGrammar::Grammar eGrammar1,
      64             :                                     FormulaGrammar::Grammar eGrammar2 )
      65             :     : ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1,
      66             :                         rExprNmsp2, eGrammar1, eGrammar2 )
      67             :     , nKey( 0 )
      68             :     , eDataMode( eMode )
      69             :     , bShowInput(false)
      70             :     , bShowError(false)
      71             :     , eErrorStyle( SC_VALERR_STOP )
      72          65 :     , mnListType( ValidListType::UNSORTED )
      73             : {
      74          65 : }
      75             : 
      76           3 : ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
      77             :                                     const ScTokenArray* pArr1, const ScTokenArray* pArr2,
      78             :                                     ScDocument* pDocument, const ScAddress& rPos )
      79             :     : ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos )
      80             :     , nKey( 0 )
      81             :     , eDataMode( eMode )
      82             :     , bShowInput(false)
      83             :     , bShowError(false)
      84             :     , eErrorStyle( SC_VALERR_STOP )
      85           3 :     , mnListType( ValidListType::UNSORTED )
      86             : {
      87           3 : }
      88             : 
      89           3 : ScValidationData::ScValidationData( const ScValidationData& r )
      90             :     : ScConditionEntry( r )
      91             :     , nKey( r.nKey )
      92             :     , eDataMode( r.eDataMode )
      93             :     , bShowInput( r.bShowInput )
      94             :     , bShowError( r.bShowError )
      95             :     , eErrorStyle( r.eErrorStyle )
      96             :     , mnListType( r.mnListType )
      97             :     , aInputTitle( r.aInputTitle )
      98             :     , aInputMessage( r.aInputMessage )
      99             :     , aErrorTitle( r.aErrorTitle )
     100           3 :     , aErrorMessage( r.aErrorMessage )
     101             : {
     102             :     //  Formeln per RefCount kopiert
     103           3 : }
     104             : 
     105          26 : ScValidationData::ScValidationData( ScDocument* pDocument, const ScValidationData& r )
     106             :     : ScConditionEntry( pDocument, r )
     107             :     , nKey( r.nKey )
     108             :     , eDataMode( r.eDataMode )
     109             :     , bShowInput( r.bShowInput )
     110             :     , bShowError( r.bShowError )
     111             :     , eErrorStyle( r.eErrorStyle )
     112             :     , mnListType( r.mnListType )
     113             :     , aInputTitle( r.aInputTitle )
     114             :     , aInputMessage( r.aInputMessage )
     115             :     , aErrorTitle( r.aErrorTitle )
     116          26 :     , aErrorMessage( r.aErrorMessage )
     117             : {
     118             :     //  Formeln wirklich kopiert
     119          26 : }
     120             : 
     121         139 : ScValidationData::~ScValidationData()
     122             : {
     123         139 : }
     124             : 
     125          33 : bool ScValidationData::IsEmpty() const
     126             : {
     127          33 :     OUString aEmpty;
     128          66 :     ScValidationData aDefault( SC_VALID_ANY, SC_COND_EQUAL, aEmpty, aEmpty, GetDocument(), ScAddress() );
     129          66 :     return EqualEntries( aDefault );
     130             : }
     131             : 
     132         114 : bool ScValidationData::EqualEntries( const ScValidationData& r ) const
     133             : {
     134             :         //  gleiche Parameter eingestellt (ohne Key)
     135             : 
     136         154 :     return ScConditionEntry::operator==(r) &&
     137          80 :             eDataMode       == r.eDataMode &&
     138          80 :             bShowInput      == r.bShowInput &&
     139          80 :             bShowError      == r.bShowError &&
     140          80 :             eErrorStyle     == r.eErrorStyle &&
     141          80 :             mnListType      == r.mnListType &&
     142          73 :             aInputTitle     == r.aInputTitle &&
     143          61 :             aInputMessage   == r.aInputMessage &&
     144         164 :             aErrorTitle     == r.aErrorTitle &&
     145         136 :             aErrorMessage   == r.aErrorMessage;
     146             : }
     147             : 
     148          30 : void ScValidationData::ResetInput()
     149             : {
     150          30 :     bShowInput = false;
     151          30 : }
     152             : 
     153          16 : void ScValidationData::ResetError()
     154             : {
     155          16 :     bShowError = false;
     156          16 : }
     157             : 
     158          30 : void ScValidationData::SetInput( const OUString& rTitle, const OUString& rMsg )
     159             : {
     160          30 :     bShowInput = true;
     161          30 :     aInputTitle = rTitle;
     162          30 :     aInputMessage = rMsg;
     163          30 : }
     164             : 
     165          35 : void ScValidationData::SetError( const OUString& rTitle, const OUString& rMsg,
     166             :                                     ScValidErrorStyle eStyle )
     167             : {
     168          35 :     bShowError = true;
     169          35 :     eErrorStyle = eStyle;
     170          35 :     aErrorTitle = rTitle;
     171          35 :     aErrorMessage = rMsg;
     172          35 : }
     173             : 
     174          48 : bool ScValidationData::GetErrMsg( OUString& rTitle, OUString& rMsg,
     175             :                                     ScValidErrorStyle& rStyle ) const
     176             : {
     177          48 :     rTitle = aErrorTitle;
     178          48 :     rMsg   = aErrorMessage;
     179          48 :     rStyle = eErrorStyle;
     180          48 :     return bShowError;
     181             : }
     182             : 
     183           0 : bool ScValidationData::DoScript( const ScAddress& rPos, const OUString& rInput,
     184             :                                 ScFormulaCell* pCell, Window* pParent ) const
     185             : {
     186           0 :     ScDocument* pDocument = GetDocument();
     187           0 :     SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
     188           0 :     if ( !pDocSh || !pDocument->CheckMacroWarn() )
     189           0 :         return false;
     190             : 
     191           0 :     bool bScriptReturnedFalse = false;  // Standard: kein Abbruch
     192             : 
     193             :     // Set up parameters
     194           0 :     ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aParams(2);
     195             : 
     196             :     //  1) eingegebener / berechneter Wert
     197           0 :     OUString aValStr = rInput;
     198             :     double nValue;
     199           0 :     bool bIsValue = false;
     200           0 :     if ( pCell )                // wenn Zelle gesetzt, aus Interpret gerufen
     201             :     {
     202           0 :         bIsValue = pCell->IsValue();
     203           0 :         if ( bIsValue )
     204           0 :             nValue  = pCell->GetValue();
     205             :         else
     206           0 :             aValStr = pCell->GetString().getString();
     207             :     }
     208           0 :     if ( bIsValue )
     209           0 :         aParams[0] = ::com::sun::star::uno::makeAny( nValue );
     210             :     else
     211           0 :         aParams[0] = ::com::sun::star::uno::makeAny( OUString( aValStr ) );
     212             : 
     213             :     //  2) Position der Zelle
     214           0 :     OUString aPosStr(rPos.Format(SCA_VALID | SCA_TAB_3D, pDocument, pDocument->GetAddressConvention()));
     215           0 :     aParams[1] = ::com::sun::star::uno::makeAny(aPosStr);
     216             : 
     217             :     //  use link-update flag to prevent closing the document
     218             :     //  while the macro is running
     219           0 :     bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
     220           0 :     if ( !bWasInLinkUpdate )
     221           0 :         pDocument->SetInLinkUpdate( true );
     222             : 
     223           0 :     if ( pCell )
     224           0 :         pDocument->LockTable( rPos.Tab() );
     225             : 
     226           0 :     ::com::sun::star::uno::Any aRet;
     227           0 :     ::com::sun::star::uno::Sequence< sal_Int16 > aOutArgsIndex;
     228           0 :     ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aOutArgs;
     229             : 
     230             :     ErrCode eRet = pDocSh->CallXScript(
     231           0 :         aErrorTitle, aParams, aRet, aOutArgsIndex, aOutArgs );
     232             : 
     233           0 :     if ( pCell )
     234           0 :         pDocument->UnlockTable( rPos.Tab() );
     235             : 
     236           0 :     if ( !bWasInLinkUpdate )
     237           0 :         pDocument->SetInLinkUpdate( false );
     238             : 
     239             :     // Check the return value from the script
     240             :     // The contents of the cell get reset if the script returns false
     241           0 :     bool bTmp = false;
     242           0 :     if ( eRet == ERRCODE_NONE &&
     243           0 :              aRet.getValueType() == getCppuBooleanType() &&
     244           0 :              ( aRet >>= bTmp ) &&
     245           0 :              !bTmp )
     246             :     {
     247           0 :         bScriptReturnedFalse =  true;
     248             :     }
     249             : 
     250           0 :     if ( eRet == ERRCODE_BASIC_METHOD_NOT_FOUND && !pCell )
     251             :     // Makro nicht gefunden (nur bei Eingabe)
     252             :     {
     253             :         //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
     254             : 
     255             :         ErrorBox aBox( pParent, WinBits(WB_OK),
     256           0 :                         ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND ) );
     257           0 :         aBox.Execute();
     258             :     }
     259             : 
     260           0 :     return bScriptReturnedFalse;
     261             : }
     262             : 
     263             :     // true -> Abbruch
     264             : 
     265           0 : bool ScValidationData::DoMacro( const ScAddress& rPos, const OUString& rInput,
     266             :                                 ScFormulaCell* pCell, Window* pParent ) const
     267             : {
     268           0 :     if ( SfxApplication::IsXScriptURL( aErrorTitle ) )
     269             :     {
     270           0 :         return DoScript( rPos, rInput, pCell, pParent );
     271             :     }
     272             : 
     273           0 :     ScDocument* pDocument = GetDocument();
     274           0 :     SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
     275           0 :     if ( !pDocSh || !pDocument->CheckMacroWarn() )
     276           0 :         return false;
     277             : 
     278           0 :     bool bDone = false;
     279           0 :     bool bRet = false;                      // Standard: kein Abbruch
     280             : 
     281             :     //  Wenn das Dok waehrend eines Basic-Calls geladen wurde,
     282             :     //  ist das Sbx-Objekt evtl. nicht angelegt (?)
     283             : //  pDocSh->GetSbxObject();
     284             : 
     285             : #ifndef DISABLE_SCRIPTING
     286             :     //  keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
     287             : 
     288             :     //  Funktion ueber den einfachen Namen suchen,
     289             :     //  dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
     290             : 
     291           0 :     StarBASIC* pRoot = pDocSh->GetBasic();
     292           0 :     SbxVariable* pVar = pRoot->Find( aErrorTitle, SbxCLASS_METHOD );
     293           0 :     if ( pVar && pVar->ISA(SbMethod) )
     294             :     {
     295           0 :         SbMethod* pMethod = (SbMethod*)pVar;
     296           0 :         SbModule* pModule = pMethod->GetModule();
     297           0 :         SbxObject* pObject = pModule->GetParent();
     298           0 :         OUStringBuffer aMacroStr = pObject->GetName();
     299           0 :         aMacroStr.append('.').append(pModule->GetName()).append('.').append(pMethod->GetName());
     300           0 :         OUString aBasicStr;
     301             : 
     302             :         //  the distinction between document- and app-basic has to be done
     303             :         //  by checking the parent (as in ScInterpreter::ScMacro), not by looping
     304             :         //  over all open documents, because this may be called from within loading,
     305             :         //  when SfxObjectShell::GetFirst/GetNext won't find the document.
     306             : 
     307           0 :         if ( pObject->GetParent() )
     308           0 :             aBasicStr = pObject->GetParent()->GetName();    // Dokumentenbasic
     309             :         else
     310           0 :             aBasicStr = SFX_APP()->GetName();               // Applikationsbasic
     311             : 
     312             :         //  Parameter fuer Makro
     313           0 :         SbxArrayRef refPar = new SbxArray;
     314             : 
     315             :         //  1) eingegebener / berechneter Wert
     316           0 :         OUString aValStr = rInput;
     317           0 :         double nValue = 0.0;
     318           0 :         bool bIsValue = false;
     319           0 :         if ( pCell )                // wenn Zelle gesetzt, aus Interpret gerufen
     320             :         {
     321           0 :             bIsValue = pCell->IsValue();
     322           0 :             if ( bIsValue )
     323           0 :                 nValue  = pCell->GetValue();
     324             :             else
     325           0 :                 aValStr = pCell->GetString().getString();
     326             :         }
     327           0 :         if ( bIsValue )
     328           0 :             refPar->Get(1)->PutDouble( nValue );
     329             :         else
     330           0 :             refPar->Get(1)->PutString( aValStr );
     331             : 
     332             :         //  2) Position der Zelle
     333           0 :         OUString aPosStr(rPos.Format(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 :         bool bWasInLinkUpdate = pDocument->IsInLinkUpdate();
     339           0 :         if ( !bWasInLinkUpdate )
     340           0 :             pDocument->SetInLinkUpdate( 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.makeStringAndClear(), 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() )
     354           0 :             bRet = true;
     355           0 :         bDone = 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_OUSTRING, pCell, NULL );
     374           0 : }
     375             : 
     376             :     // true -> Abbruch
     377             : 
     378           0 : bool ScValidationData::DoError( Window* pParent, const OUString& 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 :     OUString aTitle = aErrorTitle;
     387           0 :     if (aTitle.isEmpty())
     388           0 :         aTitle = ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 );  // application title
     389           0 :     OUString aMessage = aErrorMessage;
     390           0 :     if (aMessage.isEmpty())
     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 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 :     bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
     440             : 
     441             :     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 :             svl::SharedString aSS = mpDoc->GetSharedStringPool().intern(rTest);
     470           0 :             ScRefCellValue aTmpCell(&aSS);
     471           0 :             bRet = IsDataValid(aTmpCell, rPos);
     472             :         }
     473             :     }
     474             : 
     475           0 :     return bRet;
     476             : }
     477             : 
     478           0 : bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
     479             : {
     480           0 :     if( eDataMode == SC_VALID_LIST )
     481           0 :         return IsListValid(rCell, rPos);
     482             : 
     483           0 :     double nVal = 0.0;
     484           0 :     OUString aString;
     485           0 :     bool bIsVal = true;
     486             : 
     487           0 :     switch (rCell.meType)
     488             :     {
     489             :         case CELLTYPE_VALUE:
     490           0 :             nVal = rCell.mfValue;
     491           0 :         break;
     492             :         case CELLTYPE_STRING:
     493           0 :             aString = rCell.mpString->getString();
     494           0 :             bIsVal = false;
     495           0 :         break;
     496             :         case CELLTYPE_EDIT:
     497           0 :             if (rCell.mpEditText)
     498           0 :                 aString = ScEditUtil::GetString(*rCell.mpEditText, GetDocument());
     499           0 :             bIsVal = false;
     500           0 :         break;
     501             :         case CELLTYPE_FORMULA:
     502             :         {
     503           0 :             ScFormulaCell* pFCell = rCell.mpFormula;
     504           0 :             bIsVal = pFCell->IsValue();
     505           0 :             if ( bIsVal )
     506           0 :                 nVal  = pFCell->GetValue();
     507             :             else
     508           0 :                 aString = pFCell->GetString().getString();
     509             :         }
     510           0 :         break;
     511             :         default:                        // Notizen, Broadcaster
     512           0 :             return IsIgnoreBlank();     // wie eingestellt
     513             :     }
     514             : 
     515           0 :     bool bOk = true;
     516           0 :     switch (eDataMode)
     517             :     {
     518             :         // SC_VALID_ANY schon oben
     519             : 
     520             :         case SC_VALID_WHOLE:
     521             :         case SC_VALID_DECIMAL:
     522             :         case SC_VALID_DATE:         // Date/Time ist nur Formatierung
     523             :         case SC_VALID_TIME:
     524           0 :             bOk = bIsVal;
     525           0 :             if ( bOk && eDataMode == SC_VALID_WHOLE )
     526           0 :                 bOk = ::rtl::math::approxEqual( nVal, floor(nVal+0.5) );        // ganze Zahlen
     527           0 :             if ( bOk )
     528           0 :                 bOk = IsCellValid(rCell, rPos);
     529           0 :             break;
     530             : 
     531             :         case SC_VALID_CUSTOM:
     532             :             //  fuer Custom muss eOp == SC_COND_DIRECT sein
     533             :             //! der Wert muss im Dokument stehen !!!!!!!!!!!!!!!!!!!!
     534           0 :             bOk = IsCellValid(rCell, rPos);
     535           0 :             break;
     536             : 
     537             :         case SC_VALID_TEXTLEN:
     538           0 :             bOk = !bIsVal;          // nur Text
     539           0 :             if ( bOk )
     540             :             {
     541           0 :                 double nLenVal = (double) aString.getLength();
     542           0 :                 ScRefCellValue aTmpCell(nLenVal);
     543           0 :                 bOk = IsCellValid(aTmpCell, rPos);
     544             :             }
     545           0 :             break;
     546             : 
     547             :         default:
     548             :             OSL_FAIL("not yet done");
     549           0 :             break;
     550             :     }
     551             : 
     552           0 :     return bOk;
     553             : }
     554             : 
     555             : namespace {
     556             : 
     557             : /** Token array helper. Iterates over all string tokens.
     558             :     @descr  The token array must contain separated string tokens only.
     559             :     @param bSkipEmpty  true = Ignores string tokens with empty strings. */
     560           0 : class ScStringTokenIterator
     561             : {
     562             : public:
     563           0 :     inline explicit             ScStringTokenIterator( ScTokenArray& rTokArr, bool bSkipEmpty = true ) :
     564           0 :                                     mrTokArr( rTokArr ), mbSkipEmpty( bSkipEmpty ), mbOk( true ) {}
     565             : 
     566             :     /** Returns the string of the first string token or NULL on error or empty token array. */
     567             :     rtl_uString* First();
     568             :     /** Returns the string of the next string token or NULL on error or end of token array. */
     569             :     rtl_uString* Next();
     570             : 
     571             :     /** Returns false, if a wrong token has been found. Does NOT return false on end of token array. */
     572           0 :     inline bool                 Ok() const { return mbOk; }
     573             : 
     574             : private:
     575             :     svl::SharedString maCurString; /// Current string.
     576             :     ScTokenArray&               mrTokArr;       /// The token array for iteration.
     577             :     bool                        mbSkipEmpty;    /// Ignore empty strings.
     578             :     bool                        mbOk;           /// true = correct token or end of token array.
     579             : };
     580             : 
     581           0 : rtl_uString* ScStringTokenIterator::First()
     582             : {
     583           0 :     mrTokArr.Reset();
     584           0 :     mbOk = true;
     585           0 :     return Next();
     586             : }
     587             : 
     588           0 : rtl_uString* ScStringTokenIterator::Next()
     589             : {
     590           0 :     if( !mbOk )
     591           0 :         return NULL;
     592             : 
     593             :     // seek to next non-separator token
     594           0 :     const FormulaToken* pToken = mrTokArr.NextNoSpaces();
     595           0 :     while( pToken && (pToken->GetOpCode() == ocSep) )
     596           0 :         pToken = mrTokArr.NextNoSpaces();
     597             : 
     598           0 :     mbOk = !pToken || (pToken->GetType() == formula::svString);
     599             : 
     600           0 :     maCurString = svl::SharedString(); // start with invalid string.
     601           0 :     if (mbOk && pToken)
     602           0 :         maCurString = pToken->GetString();
     603             : 
     604             :     // string found but empty -> get next token; otherwise return it
     605           0 :     return (mbSkipEmpty && maCurString.isValid() && maCurString.isEmpty()) ? Next() : maCurString.getData();
     606             : }
     607             : 
     608             : /** Returns the number format of the passed cell, or the standard format. */
     609           0 : sal_uLong lclGetCellFormat( ScDocument& rDoc, const ScAddress& rPos )
     610             : {
     611           0 :     const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() );
     612           0 :     if( !pPattern )
     613           0 :         pPattern = rDoc.GetDefPattern();
     614           0 :     return pPattern->GetNumberFormat( rDoc.GetFormatTable() );
     615             : }
     616             : 
     617             : } // namespace
     618             : 
     619           0 : bool ScValidationData::HasSelectionList() const
     620             : {
     621           0 :     return (eDataMode == SC_VALID_LIST) && (mnListType != ValidListType::INVISIBLE);
     622             : }
     623             : 
     624           0 : bool ScValidationData::GetSelectionFromFormula(
     625             :     std::vector<ScTypedStrData>* pStrings, ScRefCellValue& rCell, const ScAddress& rPos,
     626             :     const ScTokenArray& rTokArr, int& rMatch) const
     627             : {
     628           0 :     bool bOk = true;
     629             : 
     630             :     // pDoc is private in condition, use an accessor and a long winded name.
     631           0 :     ScDocument* pDocument = GetDocument();
     632           0 :     if( NULL == pDocument )
     633           0 :         return false;
     634             : 
     635             :     ScFormulaCell aValidationSrc(
     636           0 :         pDocument, rPos, rTokArr, formula::FormulaGrammar::GRAM_DEFAULT, MM_FORMULA);
     637             : 
     638             :     // Make sure the formula gets interpreted and a result is delivered,
     639             :     // regardless of the AutoCalc setting.
     640           0 :     aValidationSrc.Interpret();
     641             : 
     642           0 :     ScMatrixRef xMatRef;
     643           0 :     const ScMatrix *pValues = aValidationSrc.GetMatrix();
     644           0 :     if (!pValues)
     645             :     {
     646             :         // The somewhat nasty case of either an error occurred, or the
     647             :         // dereferenced value of a single cell reference or an immediate result
     648             :         // is stored as a single value.
     649             : 
     650             :         // Use an interim matrix to create the TypedStrData below.
     651           0 :         xMatRef = new ScMatrix(1, 1, 0.0);
     652             : 
     653           0 :         sal_uInt16 nErrCode = aValidationSrc.GetErrCode();
     654           0 :         if (nErrCode)
     655             :         {
     656             :             /* TODO : to use later in an alert box?
     657             :              * OUString rStrResult = "...";
     658             :              * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
     659             :              */
     660             : 
     661           0 :             xMatRef->PutError( nErrCode, 0, 0);
     662           0 :             bOk = false;
     663             :         }
     664           0 :         else if (aValidationSrc.IsValue())
     665           0 :             xMatRef->PutDouble( aValidationSrc.GetValue(), 0);
     666             :         else
     667             :         {
     668           0 :             svl::SharedString aStr = aValidationSrc.GetString();
     669           0 :             xMatRef->PutString(aStr, 0);
     670             :         }
     671             : 
     672           0 :         pValues = xMatRef.get();
     673             :     }
     674             : 
     675             :     // which index matched.  We will want it eventually to pre-select that item.
     676           0 :     rMatch = -1;
     677             : 
     678           0 :     SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
     679             : 
     680           0 :     SCSIZE  nCol, nRow, nCols, nRows, n = 0;
     681           0 :     pValues->GetDimensions( nCols, nRows );
     682             : 
     683           0 :     bool bRef = false;
     684           0 :     ScRange aRange;
     685             : 
     686           0 :     ScTokenArray* pArr = (ScTokenArray*) &rTokArr;
     687           0 :     pArr->Reset();
     688           0 :     ScToken* t = NULL;
     689           0 :     if (pArr->GetLen() == 1 && (t = static_cast<ScToken*>(pArr->GetNextReferenceOrName())) != NULL)
     690             :     {
     691           0 :         if (t->GetOpCode() == ocDBArea)
     692             :         {
     693           0 :             if (const ScDBData* pDBData = pDocument->GetDBCollection()->getNamedDBs().findByIndex(t->GetIndex()))
     694             :             {
     695           0 :                 pDBData->GetArea(aRange);
     696           0 :                 bRef = true;
     697             :             }
     698             :         }
     699           0 :         else if (t->GetOpCode() == ocName)
     700             :         {
     701           0 :             ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
     702           0 :             if (pName && pName->IsReference(aRange))
     703             :             {
     704           0 :                 bRef = true;
     705             :             }
     706             :         }
     707           0 :         else if (t->GetType() != svIndex)
     708             :         {
     709           0 :             if (pArr->IsValidReference(aRange, rPos))
     710             :             {
     711           0 :                 bRef = true;
     712             :             }
     713             :         }
     714             :     }
     715             : 
     716           0 :     bool bHaveEmpty = false;
     717             : 
     718             :     /* XL artificially limits things to a single col or row in the UI but does
     719             :      * not list the constraint in MOOXml. If a defined name or INDIRECT
     720             :      * resulting in 1D is entered in the UI and the definition later modified
     721             :      * to 2D, it is evaluated fine and also stored and loaded.  Lets get ahead
     722             :      * of the curve and support 2d. In XL, values are listed row-wise, do the
     723             :      * same. */
     724           0 :     for( nRow = 0; nRow < nRows ; nRow++ )
     725             :     {
     726           0 :         for( nCol = 0; nCol < nCols ; nCol++ )
     727             :         {
     728           0 :             ScTokenArray         aCondTokArr;
     729           0 :             ScTypedStrData*        pEntry = NULL;
     730           0 :             OUString               aValStr;
     731           0 :             ScMatrixValue nMatVal = pValues->Get( nCol, nRow);
     732             : 
     733             :             // strings and empties
     734           0 :             if( ScMatrix::IsNonValueType( nMatVal.nType ) )
     735             :             {
     736           0 :                 aValStr = nMatVal.GetString().getString();
     737             : 
     738             :                 // Do not add multiple empty strings to the validation list,
     739             :                 // especially not if they'd bloat the tail with a million empty
     740             :                 // entries for a column range, fdo#61520
     741           0 :                 if (aValStr.isEmpty())
     742             :                 {
     743           0 :                     if (bHaveEmpty)
     744           0 :                         continue;
     745           0 :                     bHaveEmpty = true;
     746             :                 }
     747             : 
     748           0 :                 if( NULL != pStrings )
     749           0 :                     pEntry = new ScTypedStrData( aValStr, 0.0, ScTypedStrData::Standard);
     750             : 
     751           0 :                 if (!rCell.isEmpty() && rMatch < 0)
     752           0 :                     aCondTokArr.AddString( aValStr );
     753             :             }
     754             :             else
     755             :             {
     756           0 :                 sal_uInt16 nErr = nMatVal.GetError();
     757             : 
     758           0 :                 if( 0 != nErr )
     759             :                 {
     760           0 :                     aValStr = ScGlobal::GetErrorString( nErr );
     761             :                 }
     762             :                 else
     763             :                 {
     764             :                     // FIXME FIXME FIXME
     765             :                     // Feature regression.  Date formats are lost passing through the matrix
     766             :                     //pFormatter->GetInputLineString( pMatVal->fVal, 0, aValStr );
     767             :                     //For external reference and a formula that results in an area or array, date formats are still lost.
     768           0 :                     if ( bRef )
     769             :                     {
     770           0 :                         pDocument->GetInputString((SCCOL)(nCol+aRange.aStart.Col()),
     771           0 :                             (SCROW)(nRow+aRange.aStart.Row()), aRange.aStart.Tab() , aValStr);
     772             :                     }
     773             :                     else
     774             :                     {
     775           0 :                         pFormatter->GetInputLineString( nMatVal.fVal, 0, aValStr );
     776             :                     }
     777             :                 }
     778             : 
     779           0 :                 if (!rCell.isEmpty() && rMatch < 0)
     780             :                 {
     781             :                     // I am not sure errors will work here, but a user can no
     782             :                     // manually enter an error yet so the point is somewhat moot.
     783           0 :                     aCondTokArr.AddDouble( nMatVal.fVal );
     784             :                 }
     785           0 :                 if( NULL != pStrings )
     786           0 :                     pEntry = new ScTypedStrData( aValStr, nMatVal.fVal, ScTypedStrData::Value);
     787             :             }
     788             : 
     789           0 :             if (rMatch < 0 && !rCell.isEmpty() && IsEqualToTokenArray(rCell, rPos, aCondTokArr))
     790             :             {
     791           0 :                 rMatch = n;
     792             :                 // short circuit on the first match if not filling the list
     793           0 :                 if( NULL == pStrings )
     794           0 :                     return true;
     795             :             }
     796             : 
     797           0 :             if( NULL != pEntry )
     798             :             {
     799           0 :                 pStrings->push_back(*pEntry);
     800           0 :                 delete pEntry;
     801           0 :                 n++;
     802             :             }
     803           0 :         }
     804             :     }
     805             : 
     806             :     // In case of no match needed and an error occurred, return that error
     807             :     // entry as valid instead of silently failing.
     808           0 :     return bOk || rCell.isEmpty();
     809             : }
     810             : 
     811           0 : bool ScValidationData::FillSelectionList(std::vector<ScTypedStrData>& rStrColl, const ScAddress& rPos) const
     812             : {
     813           0 :     bool bOk = false;
     814             : 
     815           0 :     if( HasSelectionList() )
     816             :     {
     817           0 :         boost::scoped_ptr<ScTokenArray> pTokArr( CreateTokenArry(0) );
     818             : 
     819             :         // *** try if formula is a string list ***
     820             : 
     821           0 :         sal_uInt32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
     822           0 :         ScStringTokenIterator aIt( *pTokArr );
     823           0 :         for (rtl_uString* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next())
     824             :         {
     825             :             double fValue;
     826           0 :             OUString aStr(pString);
     827           0 :             bool bIsValue = GetDocument()->GetFormatTable()->IsNumberFormat(aStr, nFormat, fValue);
     828             :             rStrColl.push_back(
     829             :                 ScTypedStrData(
     830           0 :                     aStr, fValue, bIsValue ? ScTypedStrData::Value : ScTypedStrData::Standard));
     831           0 :         }
     832           0 :         bOk = aIt.Ok();
     833             : 
     834             :         // *** if not a string list, try if formula results in a cell range or
     835             :         // anything else we recognize as valid ***
     836             : 
     837           0 :         if (!bOk)
     838             :         {
     839             :             int nMatch;
     840           0 :             ScRefCellValue aEmptyCell;
     841           0 :             bOk = GetSelectionFromFormula(&rStrColl, aEmptyCell, rPos, *pTokArr, nMatch);
     842           0 :         }
     843             :     }
     844             : 
     845           0 :     return bOk;
     846             : }
     847             : 
     848           0 : bool ScValidationData::IsEqualToTokenArray( ScRefCellValue& rCell, const ScAddress& rPos, const ScTokenArray& rTokArr ) const
     849             : {
     850             :     // create a condition entry that tests on equality and set the passed token array
     851           0 :     ScConditionEntry aCondEntry( SC_COND_EQUAL, &rTokArr, NULL, GetDocument(), rPos );
     852           0 :     return aCondEntry.IsCellValid(rCell, rPos);
     853             : }
     854             : 
     855           0 : bool ScValidationData::IsListValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
     856             : {
     857           0 :     bool bIsValid = false;
     858             : 
     859             :     /*  Compare input cell with all supported tokens from the formula.
     860             :         Currently a formula may contain:
     861             :         1)  A list of strings (at least one string).
     862             :         2)  A single cell or range reference.
     863             :         3)  A single defined name (must contain a cell/range reference, another
     864             :             name, or DB range, or a formula resulting in a cell/range reference
     865             :             or matrix/array).
     866             :         4)  A single database range.
     867             :         5)  A formula resulting in a cell/range reference or matrix/array.
     868             :     */
     869             : 
     870           0 :     boost::scoped_ptr< ScTokenArray > pTokArr( CreateTokenArry( 0 ) );
     871             : 
     872             :     // *** try if formula is a string list ***
     873             : 
     874           0 :     sal_uInt32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
     875           0 :     ScStringTokenIterator aIt( *pTokArr );
     876           0 :     for (rtl_uString* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next())
     877             :     {
     878             :         /*  Do not break the loop, if a valid string has been found.
     879             :             This is to find invalid tokens following in the formula. */
     880           0 :         if( !bIsValid )
     881             :         {
     882             :             // create a formula containing a single string or number
     883           0 :             ScTokenArray aCondTokArr;
     884             :             double fValue;
     885           0 :             OUString aStr(pString);
     886           0 :             if (GetDocument()->GetFormatTable()->IsNumberFormat(aStr, nFormat, fValue))
     887           0 :                 aCondTokArr.AddDouble( fValue );
     888             :             else
     889           0 :                 aCondTokArr.AddString(aStr);
     890             : 
     891           0 :             bIsValid = IsEqualToTokenArray(rCell, rPos, aCondTokArr);
     892             :         }
     893             :     }
     894             : 
     895           0 :     if( !aIt.Ok() )
     896           0 :         bIsValid = false;
     897             : 
     898             :     // *** if not a string list, try if formula results in a cell range or
     899             :     // anything else we recognize as valid ***
     900             : 
     901           0 :     if (!bIsValid)
     902             :     {
     903             :         int nMatch;
     904           0 :         bIsValid = GetSelectionFromFormula(NULL, rCell, rPos, *pTokArr, nMatch);
     905           0 :         bIsValid = bIsValid && nMatch >= 0;
     906             :     }
     907             : 
     908           0 :     return bIsValid;
     909             : }
     910             : 
     911             : 
     912           0 : ScValidationDataList::ScValidationDataList(const ScValidationDataList& rList)
     913             : {
     914             :     //  fuer Ref-Undo - echte Kopie mit neuen Tokens!
     915             : 
     916           0 :     for (const_iterator it = rList.begin(); it != rList.end(); ++it)
     917             :     {
     918           0 :         InsertNew( (*it)->Clone() );
     919             :     }
     920             : 
     921             :     //!     sortierte Eintraege aus rList schneller einfuegen ???
     922           0 : }
     923             : 
     924           1 : ScValidationDataList::ScValidationDataList(ScDocument* pNewDoc,
     925           1 :                                             const ScValidationDataList& rList)
     926             : {
     927             :     //  fuer neues Dokument - echte Kopie mit neuen Tokens!
     928             : 
     929          11 :     for (const_iterator it = rList.begin(); it != rList.end(); ++it)
     930             :     {
     931          10 :         InsertNew( (*it)->Clone(pNewDoc) );
     932             :     }
     933             : 
     934             :     //!     sortierte Eintraege aus rList schneller einfuegen ???
     935           1 : }
     936             : 
     937          82 : ScValidationData* ScValidationDataList::GetData( sal_uInt32 nKey )
     938             : {
     939             :     //! binaer suchen
     940             : 
     941         201 :     for( iterator it = begin(); it != end(); ++it )
     942         201 :         if( (*it)->GetKey() == nKey )
     943          82 :             return *it;
     944             : 
     945             :     OSL_FAIL("ScValidationDataList: Entry not found");
     946           0 :     return NULL;
     947             : }
     948             : 
     949           1 : void ScValidationDataList::CompileXML()
     950             : {
     951           3 :     for( iterator it = begin(); it != end(); ++it )
     952           2 :         (*it)->CompileXML();
     953           1 : }
     954             : 
     955           5 : void ScValidationDataList::UpdateReference( sc::RefUpdateContext& rCxt )
     956             : {
     957          19 :     for( iterator it = begin(); it != end(); ++it )
     958          14 :         (*it)->UpdateReference(rCxt);
     959           5 : }
     960             : 
     961           0 : void ScValidationDataList::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
     962             : {
     963           0 :     for (iterator it = begin(); it != end(); ++it)
     964           0 :         (*it)->UpdateInsertTab(rCxt);
     965           0 : }
     966             : 
     967           0 : void ScValidationDataList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
     968             : {
     969           0 :     for (iterator it = begin(); it != end(); ++it)
     970           0 :         (*it)->UpdateDeleteTab(rCxt);
     971           0 : }
     972             : 
     973           0 : void ScValidationDataList::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
     974             : {
     975           0 :     for (iterator it = begin(); it != end(); ++it)
     976           0 :         (*it)->UpdateMoveTab(rCxt);
     977           0 : }
     978             : 
     979           0 : bool ScValidationDataList::operator==( const ScValidationDataList& r ) const
     980             : {
     981             :     // fuer Ref-Undo - interne Variablen werden nicht verglichen
     982             : 
     983           0 :     size_t nCount = maData.size();
     984           0 :     bool bEqual = ( nCount == r.maData.size() );
     985           0 :     for( const_iterator it1 = begin(), it2 = r.begin(); it1 != end() && bEqual; ++it1, ++it2 ) // Eintraege sind sortiert
     986           0 :         if ( !(*it1)->EqualEntries(**it2) )         // Eintraege unterschiedlich ?
     987           0 :             bEqual = false;
     988             : 
     989           0 :     return bEqual;
     990             : }
     991             : 
     992         128 : ScValidationDataList::iterator ScValidationDataList::begin()
     993             : {
     994         128 :     return maData.begin();
     995             : }
     996             : 
     997           1 : ScValidationDataList::const_iterator ScValidationDataList::begin() const
     998             : {
     999           1 :     return maData.begin();
    1000             : }
    1001             : 
    1002         351 : ScValidationDataList::iterator ScValidationDataList::end()
    1003             : {
    1004         351 :     return maData.end();
    1005             : }
    1006             : 
    1007          11 : ScValidationDataList::const_iterator ScValidationDataList::end() const
    1008             : {
    1009          11 :     return maData.end();
    1010             : }
    1011             : 
    1012           7 : void ScValidationDataList::clear()
    1013             : {
    1014           7 :     maData.clear();
    1015           7 : }
    1016             : 
    1017             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10