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

Generated by: LCOV version 1.10