1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: validat.cxx,v $
10 * $Revision: 1.24.110.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <sfx2/app.hxx>
40 #include <sfx2/docfile.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <basic/sbmeth.hxx>
43 #include <basic/sbmod.hxx>
44 #include <basic/sbstar.hxx>
45 #include <basic/basmgr.hxx>
47 #include <basic/sbx.hxx>
48 #include <svtools/zforlist.hxx>
49 #include <vcl/msgbox.hxx>
50 #include <tools/urlobj.hxx>
51 #include <rtl/math.hxx>
53 #include "validat.hxx"
54 #include "document.hxx"
56 #include "patattr.hxx"
57 #include "rechead.hxx"
58 #include "globstr.hrc"
59 #include "rangenam.hxx"
60 #include "dbcolect.hxx"
65 using namespace formula
;
66 //------------------------------------------------------------------------
68 SV_IMPL_OP_PTRARR_SORT( ScValidationEntries_Impl
, ScValidationDataPtr
);
70 //------------------------------------------------------------------------
73 // Eintrag fuer Gueltigkeit (es gibt nur eine Bedingung)
76 ScValidationData::ScValidationData( ScValidationMode eMode
, ScConditionMode eOper
,
77 const String
& rExpr1
, const String
& rExpr2
,
78 ScDocument
* pDocument
, const ScAddress
& rPos
,
79 const String
& rExprNmsp1
, const String
& rExprNmsp2
,
80 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
) :
81 ScConditionEntry( eOper
, rExpr1
, rExpr2
, pDocument
, rPos
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
),
84 eErrorStyle( SC_VALERR_STOP
),
85 mnListType( ValidListType::UNSORTED
)
87 bShowInput
= bShowError
= FALSE
;
90 ScValidationData::ScValidationData( ScValidationMode eMode
, ScConditionMode eOper
,
91 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
92 ScDocument
* pDocument
, const ScAddress
& rPos
) :
93 ScConditionEntry( eOper
, pArr1
, pArr2
, pDocument
, rPos
),
96 eErrorStyle( SC_VALERR_STOP
),
97 mnListType( ValidListType::UNSORTED
)
99 bShowInput
= bShowError
= FALSE
;
102 ScValidationData::ScValidationData( const ScValidationData
& r
) :
103 ScConditionEntry( r
),
105 eDataMode( r
.eDataMode
),
106 bShowInput( r
.bShowInput
),
107 bShowError( r
.bShowError
),
108 eErrorStyle( r
.eErrorStyle
),
109 mnListType( r
.mnListType
),
110 aInputTitle( r
.aInputTitle
),
111 aInputMessage( r
.aInputMessage
),
112 aErrorTitle( r
.aErrorTitle
),
113 aErrorMessage( r
.aErrorMessage
)
115 // Formeln per RefCount kopiert
118 ScValidationData::ScValidationData( ScDocument
* pDocument
, const ScValidationData
& r
) :
119 ScConditionEntry( pDocument
, r
),
121 eDataMode( r
.eDataMode
),
122 bShowInput( r
.bShowInput
),
123 bShowError( r
.bShowError
),
124 eErrorStyle( r
.eErrorStyle
),
125 mnListType( r
.mnListType
),
126 aInputTitle( r
.aInputTitle
),
127 aInputMessage( r
.aInputMessage
),
128 aErrorTitle( r
.aErrorTitle
),
129 aErrorMessage( r
.aErrorMessage
)
131 // Formeln wirklich kopiert
134 ScValidationData::~ScValidationData()
138 BOOL
ScValidationData::IsEmpty() const
141 ScValidationData
aDefault( SC_VALID_ANY
, SC_COND_EQUAL
, aEmpty
, aEmpty
, GetDocument(), ScAddress() );
142 return EqualEntries( aDefault
);
145 BOOL
ScValidationData::EqualEntries( const ScValidationData
& r
) const
147 // gleiche Parameter eingestellt (ohne Key)
149 return ScConditionEntry::operator==(r
) &&
150 eDataMode
== r
.eDataMode
&&
151 bShowInput
== r
.bShowInput
&&
152 bShowError
== r
.bShowError
&&
153 eErrorStyle
== r
.eErrorStyle
&&
154 mnListType
== r
.mnListType
&&
155 aInputTitle
== r
.aInputTitle
&&
156 aInputMessage
== r
.aInputMessage
&&
157 aErrorTitle
== r
.aErrorTitle
&&
158 aErrorMessage
== r
.aErrorMessage
;
161 void ScValidationData::ResetInput()
166 void ScValidationData::ResetError()
171 void ScValidationData::SetInput( const String
& rTitle
, const String
& rMsg
)
174 aInputTitle
= rTitle
;
175 aInputMessage
= rMsg
;
178 void ScValidationData::SetError( const String
& rTitle
, const String
& rMsg
,
179 ScValidErrorStyle eStyle
)
182 eErrorStyle
= eStyle
;
183 aErrorTitle
= rTitle
;
184 aErrorMessage
= rMsg
;
187 BOOL
ScValidationData::GetErrMsg( String
& rTitle
, String
& rMsg
,
188 ScValidErrorStyle
& rStyle
) const
190 rTitle
= aErrorTitle
;
191 rMsg
= aErrorMessage
;
192 rStyle
= eErrorStyle
;
196 BOOL
ScValidationData::DoScript( const ScAddress
& rPos
, const String
& rInput
,
197 ScFormulaCell
* pCell
, Window
* pParent
) const
199 ScDocument
* pDocument
= GetDocument();
200 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
201 if ( !pDocSh
|| !pDocument
->CheckMacroWarn() )
204 BOOL bScriptReturnedFalse
= FALSE
; // Standard: kein Abbruch
207 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
> aParams(2);
209 // 1) eingegebener / berechneter Wert
210 String aValStr
= rInput
;
212 BOOL bIsValue
= FALSE
;
213 if ( pCell
) // wenn Zelle gesetzt, aus Interpret gerufen
215 bIsValue
= pCell
->IsValue();
217 nValue
= pCell
->GetValue();
219 pCell
->GetString( aValStr
);
222 aParams
[0] = ::com::sun::star::uno::makeAny( nValue
);
224 aParams
[0] = ::com::sun::star::uno::makeAny( ::rtl::OUString( aValStr
) );
226 // 2) Position der Zelle
228 rPos
.Format( aPosStr
, SCA_VALID
| SCA_TAB_3D
, pDocument
, pDocument
->GetAddressConvention() );
229 aParams
[1] = ::com::sun::star::uno::makeAny( ::rtl::OUString( aPosStr
) );
231 // use link-update flag to prevent closing the document
232 // while the macro is running
233 BOOL bWasInLinkUpdate
= pDocument
->IsInLinkUpdate();
234 if ( !bWasInLinkUpdate
)
235 pDocument
->SetInLinkUpdate( TRUE
);
238 pDocument
->LockTable( rPos
.Tab() );
240 ::com::sun::star::uno::Any aRet
;
241 ::com::sun::star::uno::Sequence
< sal_Int16
> aOutArgsIndex
;
242 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
> aOutArgs
;
244 ErrCode eRet
= pDocSh
->CallXScript(
245 aErrorTitle
, aParams
, aRet
, aOutArgsIndex
, aOutArgs
);
248 pDocument
->UnlockTable( rPos
.Tab() );
250 if ( !bWasInLinkUpdate
)
251 pDocument
->SetInLinkUpdate( FALSE
);
253 // Check the return value from the script
254 // The contents of the cell get reset if the script returns false
256 if ( eRet
== ERRCODE_NONE
&&
257 aRet
.getValueType() == getCppuBooleanType() &&
258 sal_True
== ( aRet
>>= bTmp
) &&
261 bScriptReturnedFalse
= TRUE
;
264 if ( eRet
== ERRCODE_BASIC_METHOD_NOT_FOUND
&& !pCell
)
265 // Makro nicht gefunden (nur bei Eingabe)
267 //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
269 ErrorBox
aBox( pParent
, WinBits(WB_OK
),
270 ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND
) );
274 return bScriptReturnedFalse
;
279 BOOL
ScValidationData::DoMacro( const ScAddress
& rPos
, const String
& rInput
,
280 ScFormulaCell
* pCell
, Window
* pParent
) const
282 if ( SfxApplication::IsXScriptURL( aErrorTitle
) )
284 return DoScript( rPos
, rInput
, pCell
, pParent
);
287 ScDocument
* pDocument
= GetDocument();
288 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
289 if ( !pDocSh
|| !pDocument
->CheckMacroWarn() )
293 BOOL bRet
= FALSE
; // Standard: kein Abbruch
294 SfxApplication
* pSfxApp
= SFX_APP();
295 pSfxApp
->EnterBasicCall(); // Dok-Basic anlegen etc.
297 // Wenn das Dok waehrend eines Basic-Calls geladen wurde,
298 // ist das Sbx-Objekt evtl. nicht angelegt (?)
299 // pDocSh->GetSbxObject();
301 // keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
304 // Makro-Name liegt in folgender Form vor:
305 // "Macroname.Modulname.Libname.Dokumentname" oder
306 // "Macroname.Modulname.Libname.Applikationsname"
307 String aMacroName
= aErrorTitle
.GetToken(0, '.');
308 String aModulName
= aErrorTitle
.GetToken(1, '.');
309 String aLibName
= aErrorTitle
.GetToken(2, '.');
310 String aDocName
= aErrorTitle
.GetToken(3, '.');
313 // Funktion ueber den einfachen Namen suchen,
314 // dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
316 StarBASIC
* pRoot
= pDocSh
->GetBasic();
317 SbxVariable
* pVar
= pRoot
->Find( aErrorTitle
, SbxCLASS_METHOD
);
318 if ( pVar
&& pVar
->ISA(SbMethod
) )
320 SbMethod
* pMethod
= (SbMethod
*)pVar
;
321 SbModule
* pModule
= pMethod
->GetModule();
322 SbxObject
* pObject
= pModule
->GetParent();
323 String aMacroStr
= pObject
->GetName();
325 aMacroStr
+= pModule
->GetName();
327 aMacroStr
+= pMethod
->GetName();
330 // #95867# the distinction between document- and app-basic has to be done
331 // by checking the parent (as in ScInterpreter::ScMacro), not by looping
332 // over all open documents, because this may be called from within loading,
333 // when SfxObjectShell::GetFirst/GetNext won't find the document.
335 if ( pObject
->GetParent() )
336 aBasicStr
= pObject
->GetParent()->GetName(); // Dokumentenbasic
338 aBasicStr
= SFX_APP()->GetName(); // Applikationsbasic
340 // Parameter fuer Makro
341 SbxArrayRef refPar
= new SbxArray
;
343 // 1) eingegebener / berechneter Wert
344 String aValStr
= rInput
;
346 BOOL bIsValue
= FALSE
;
347 if ( pCell
) // wenn Zelle gesetzt, aus Interpret gerufen
349 bIsValue
= pCell
->IsValue();
351 nValue
= pCell
->GetValue();
353 pCell
->GetString( aValStr
);
356 refPar
->Get(1)->PutDouble( nValue
);
358 refPar
->Get(1)->PutString( aValStr
);
360 // 2) Position der Zelle
362 rPos
.Format( aPosStr
, SCA_VALID
| SCA_TAB_3D
, pDocument
, pDocument
->GetAddressConvention() );
363 refPar
->Get(2)->PutString( aPosStr
);
365 // use link-update flag to prevent closing the document
366 // while the macro is running
367 BOOL bWasInLinkUpdate
= pDocument
->IsInLinkUpdate();
368 if ( !bWasInLinkUpdate
)
369 pDocument
->SetInLinkUpdate( TRUE
);
372 pDocument
->LockTable( rPos
.Tab() );
373 SbxVariableRef refRes
= new SbxVariable
;
374 ErrCode eRet
= pDocSh
->CallBasic( aMacroStr
, aBasicStr
, NULL
, refPar
, refRes
);
376 pDocument
->UnlockTable( rPos
.Tab() );
378 if ( !bWasInLinkUpdate
)
379 pDocument
->SetInLinkUpdate( FALSE
);
381 // Eingabe abbrechen, wenn Basic-Makro FALSE zurueckgibt
382 if ( eRet
== ERRCODE_NONE
&& refRes
->GetType() == SbxBOOL
&& refRes
->GetBool() == FALSE
)
386 pSfxApp
->LeaveBasicCall();
388 if ( !bDone
&& !pCell
) // Makro nicht gefunden (nur bei Eingabe)
390 //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
392 ErrorBox
aBox( pParent
, WinBits(WB_OK
),
393 ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND
) );
400 void ScValidationData::DoCalcError( ScFormulaCell
* pCell
) const
402 if ( eErrorStyle
== SC_VALERR_MACRO
)
403 DoMacro( pCell
->aPos
, EMPTY_STRING
, pCell
, NULL
);
408 BOOL
ScValidationData::DoError( Window
* pParent
, const String
& rInput
,
409 const ScAddress
& rPos
) const
411 if ( eErrorStyle
== SC_VALERR_MACRO
)
412 return DoMacro( rPos
, rInput
, NULL
, pParent
);
414 // Fehlermeldung ausgeben
416 String aTitle
= aErrorTitle
;
418 aTitle
= ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0
); // application title
419 String aMessage
= aErrorMessage
;
421 aMessage
= ScGlobal::GetRscString( STR_VALID_DEFERROR
);
423 //! ErrorBox / WarningBox / InfoBox ?
424 //! (bei InfoBox immer nur OK-Button)
430 nStyle
= WB_OK
| WB_DEF_OK
;
432 case SC_VALERR_WARNING
:
433 nStyle
= WB_OK_CANCEL
| WB_DEF_CANCEL
;
436 nStyle
= WB_OK_CANCEL
| WB_DEF_OK
;
440 // added to avoid warnings
444 MessBox
aBox( pParent
, WinBits(nStyle
), aTitle
, aMessage
);
445 USHORT nRet
= aBox
.Execute();
447 return ( eErrorStyle
== SC_VALERR_STOP
|| nRet
== RET_CANCEL
);
451 BOOL
ScValidationData::IsDataValid( const String
& rTest
, const ScPatternAttr
& rPattern
,
452 const ScAddress
& rPos
) const
454 if ( eDataMode
== SC_VALID_ANY
)
455 return TRUE
; // alles erlaubt
457 if ( rTest
.GetChar(0) == '=' )
458 return FALSE
; // Formeln sind sonst immer ungueltig
461 return IsIgnoreBlank(); // leer: wie eingestellt
463 SvNumberFormatter
* pFormatter
= GetDocument()->GetFormatTable();
465 // Test, was es denn ist - wie in ScColumn::SetString
467 sal_uInt32 nFormat
= rPattern
.GetNumberFormat( pFormatter
);
470 BOOL bIsVal
= pFormatter
->IsNumberFormat( rTest
, nFormat
, nVal
);
473 pCell
= new ScValueCell( nVal
);
475 pCell
= new ScStringCell( rTest
);
477 BOOL bRet
= IsDataValid( pCell
, rPos
);
483 BOOL
ScValidationData::IsDataValid( ScBaseCell
* pCell
, const ScAddress
& rPos
) const
485 if( eDataMode
== SC_VALID_LIST
)
486 return IsListValid( pCell
, rPos
);
492 switch (pCell
->GetCellType())
495 nVal
= ((ScValueCell
*)pCell
)->GetValue();
497 case CELLTYPE_STRING
:
498 ((ScStringCell
*)pCell
)->GetString( aString
);
502 ((ScEditCell
*)pCell
)->GetString( aString
);
505 case CELLTYPE_FORMULA
:
507 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
508 bIsVal
= pFCell
->IsValue();
510 nVal
= pFCell
->GetValue();
512 pFCell
->GetString( aString
);
515 default: // Notizen, Broadcaster
516 return IsIgnoreBlank(); // wie eingestellt
522 // SC_VALID_ANY schon oben
525 case SC_VALID_DECIMAL
:
526 case SC_VALID_DATE
: // Date/Time ist nur Formatierung
529 if ( bOk
&& eDataMode
== SC_VALID_WHOLE
)
530 bOk
= ::rtl::math::approxEqual( nVal
, floor(nVal
+0.5) ); // ganze Zahlen
532 bOk
= IsCellValid( pCell
, rPos
);
535 case SC_VALID_CUSTOM
:
536 // fuer Custom muss eOp == SC_COND_DIRECT sein
537 //! der Wert muss im Dokument stehen !!!!!!!!!!!!!!!!!!!!
538 bOk
= IsCellValid( pCell
, rPos
);
541 case SC_VALID_TEXTLEN
:
542 bOk
= !bIsVal
; // nur Text
545 double nLenVal
= (double) aString
.Len();
546 ScValueCell
aTmpCell( nLenVal
);
547 bOk
= IsCellValid( &aTmpCell
, rPos
);
552 DBG_ERROR("hammanochnich");
559 // ----------------------------------------------------------------------------
563 /** Token array helper. Iterates over all string tokens.
564 @descr The token array must contain separated string tokens only.
565 @param bSkipEmpty true = Ignores string tokens with empty strings. */
566 class ScStringTokenIterator
569 inline explicit ScStringTokenIterator( ScTokenArray
& rTokArr
, bool bSkipEmpty
= true ) :
570 mrTokArr( rTokArr
), mbSkipEmpty( bSkipEmpty
), mbOk( true ) {}
572 /** Returns the string of the first string token or NULL on error or empty token array. */
573 const String
* First();
574 /** Returns the string of the next string token or NULL on error or end of token array. */
575 const String
* Next();
577 /** Returns false, if a wrong token has been found. Does NOT return false on end of token array. */
578 inline bool Ok() const { return mbOk
; }
581 ScTokenArray
& mrTokArr
; /// The token array for iteration.
582 bool mbSkipEmpty
; /// Ignore empty strings.
583 bool mbOk
; /// true = correct token or end of token array.
586 const String
* ScStringTokenIterator::First()
593 const String
* ScStringTokenIterator::Next()
598 // seek to next non-separator token
599 const FormulaToken
* pToken
= mrTokArr
.NextNoSpaces();
600 while( pToken
&& (pToken
->GetOpCode() == ocSep
) )
601 pToken
= mrTokArr
.NextNoSpaces();
603 mbOk
= !pToken
|| (pToken
->GetType() == formula::svString
);
604 const String
* pString
= (mbOk
&& pToken
) ? &pToken
->GetString() : NULL
;
605 // string found but empty -> get next token; otherwise return it
606 return (mbSkipEmpty
&& pString
&& !pString
->Len()) ? Next() : pString
;
609 // ----------------------------------------------------------------------------
611 /** Returns the number format of the passed cell, or the standard format. */
612 ULONG
lclGetCellFormat( ScDocument
& rDoc
, const ScAddress
& rPos
)
614 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( rPos
.Col(), rPos
.Row(), rPos
.Tab() );
616 pPattern
= rDoc
.GetDefPattern();
617 return pPattern
->GetNumberFormat( rDoc
.GetFormatTable() );
620 /** Inserts the passed string object. Always takes ownership. pData is invalid after this call! */
621 void lclInsertStringToCollection( TypedScStrCollection
& rStrColl
, TypedStrData
* pData
, bool bSorted
)
623 if( !(bSorted
? rStrColl
.Insert( pData
) : rStrColl
.AtInsert( rStrColl
.GetCount(), pData
)) )
629 // ----------------------------------------------------------------------------
631 bool ScValidationData::HasSelectionList() const
633 return (eDataMode
== SC_VALID_LIST
) && (mnListType
!= ValidListType::INVISIBLE
);
636 bool ScValidationData::GetSelectionFromFormula( TypedScStrCollection
* pStrings
,
638 const ScAddress
& rPos
,
639 const ScTokenArray
& rTokArr
,
644 // pDoc is private in condition, use an accessor and a long winded name.
645 ScDocument
* pDocument
= GetDocument();
646 if( NULL
== pDocument
)
649 ScFormulaCell
aValidationSrc( pDocument
, rPos
, &rTokArr
,
650 formula::FormulaGrammar::GRAM_DEFAULT
, MM_FORMULA
);
652 // Make sure the formula gets interpreted and a result is delivered,
653 // regardless of the AutoCalc setting.
654 aValidationSrc
.Interpret();
657 const ScMatrix
*pValues
= aValidationSrc
.GetMatrix();
660 // The somewhat nasty case of either an error occured, or the
661 // dereferenced value of a single cell reference or an immediate result
662 // is stored as a single value.
664 // Use an interim matrix to create the TypedStrData below.
665 xMatRef
= new ScMatrix(1,1);
667 USHORT nErrCode
= aValidationSrc
.GetErrCode();
670 /* TODO : to use later in an alert box?
671 * String rStrResult = "...";
672 * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
675 xMatRef
->PutError( nErrCode
, 0);
678 else if (aValidationSrc
.HasValueData())
679 xMatRef
->PutDouble( aValidationSrc
.GetValue(), 0);
683 aValidationSrc
.GetString( aStr
);
684 xMatRef
->PutString( aStr
, 0);
690 // which index matched. We will want it eventually to pre-select that item.
693 SvNumberFormatter
* pFormatter
= GetDocument()->GetFormatTable();
695 bool bSortList
= (mnListType
== ValidListType::SORTEDASCENDING
);
696 SCSIZE nCol
, nRow
, nCols
, nRows
, n
= 0;
697 pValues
->GetDimensions( nCols
, nRows
);
702 ScTokenArray
* pArr
= (ScTokenArray
*) &rTokArr
;
705 if (pArr
->GetLen() == 1 && (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName())) != NULL
)
707 if (t
->GetOpCode() == ocDBArea
)
709 if( ScDBData
* pDBData
= pDocument
->GetDBCollection()->FindIndex( t
->GetIndex() ) )
711 pDBData
->GetArea(aRange
);
715 else if (t
->GetOpCode() == ocName
)
717 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
718 if (pName
&& pName
->IsReference(aRange
))
723 else if (t
->GetType() != svIndex
)
725 t
->CalcAbsIfRel(rPos
);
726 if (pArr
->IsValidReference(aRange
))
733 /* XL artificially limits things to a single col or row in the UI but does
734 * not list the constraint in MOOXml. If a defined name or INDIRECT
735 * resulting in 1D is entered in the UI and the definition later modified
736 * to 2D, it is evaluated fine and also stored and loaded. Lets get ahead
737 * of the curve and support 2d. In XL, values are listed row-wise, do the
739 for( nRow
= 0; nRow
< nRows
; nRow
++ )
741 for( nCol
= 0; nCol
< nCols
; nCol
++ )
743 ScTokenArray aCondTokArr
;
744 TypedStrData
* pEntry
= NULL
;
745 ScMatValType nMatValType
;
747 const ScMatrixValue
* pMatVal
= pValues
->Get( nCol
, nRow
, nMatValType
);
749 // strings and empties
750 if( NULL
== pMatVal
|| ScMatrix::IsNonValueType( nMatValType
) )
752 if( NULL
!= pMatVal
)
753 aValStr
= pMatVal
->GetString();
755 if( NULL
!= pStrings
)
756 pEntry
= new TypedStrData( aValStr
, 0.0, SC_STRTYPE_STANDARD
);
758 if( pCell
&& rMatch
< 0 )
759 aCondTokArr
.AddString( aValStr
);
763 USHORT nErr
= pMatVal
->GetError();
767 aValStr
= ScGlobal::GetErrorString( nErr
);
772 // Feature regression. Date formats are lost passing through the matrix
773 //pFormatter->GetInputLineString( pMatVal->fVal, 0, aValStr );
774 //For external reference and a formula that results in an area or array, date formats are still lost.
777 pDocument
->GetInputString((SCCOL
)(nCol
+aRange
.aStart
.Col()),
778 (SCROW
)(nRow
+aRange
.aStart
.Row()), aRange
.aStart
.Tab() , aValStr
);
781 pFormatter
->GetInputLineString( pMatVal
->fVal
, 0, aValStr
);
784 if( pCell
&& rMatch
< 0 )
786 // I am not sure errors will work here, but a user can no
787 // manually enter an error yet so the point is somewhat moot.
788 aCondTokArr
.AddDouble( pMatVal
->fVal
);
790 if( NULL
!= pStrings
)
791 pEntry
= new TypedStrData( aValStr
, pMatVal
->fVal
, SC_STRTYPE_VALUE
);
794 if( rMatch
< 0 && NULL
!= pCell
&& IsEqualToTokenArray( pCell
, rPos
, aCondTokArr
) )
797 // short circuit on the first match if not filling the list
798 if( NULL
== pStrings
)
804 lclInsertStringToCollection( *pStrings
, pEntry
, bSortList
);
810 // In case of no match needed and an error occurred, return that error
811 // entry as valid instead of silently failing.
812 return bOk
|| NULL
== pCell
;
815 bool ScValidationData::FillSelectionList( TypedScStrCollection
& rStrColl
, const ScAddress
& rPos
) const
819 if( HasSelectionList() )
821 ::std::auto_ptr
< ScTokenArray
> pTokArr( CreateTokenArry( 0 ) );
823 // *** try if formula is a string list ***
825 bool bSortList
= (mnListType
== ValidListType::SORTEDASCENDING
);
826 UINT32 nFormat
= lclGetCellFormat( *GetDocument(), rPos
);
827 ScStringTokenIterator
aIt( *pTokArr
);
828 for( const String
* pString
= aIt
.First(); pString
&& aIt
.Ok(); pString
= aIt
.Next() )
831 bool bIsValue
= GetDocument()->GetFormatTable()->IsNumberFormat( *pString
, nFormat
, fValue
);
832 TypedStrData
* pData
= new TypedStrData( *pString
, fValue
, bIsValue
? SC_STRTYPE_VALUE
: SC_STRTYPE_STANDARD
);
833 lclInsertStringToCollection( rStrColl
, pData
, bSortList
);
837 // *** if not a string list, try if formula results in a cell range or
838 // anything else we recognize as valid ***
843 bOk
= GetSelectionFromFormula( &rStrColl
, NULL
, rPos
, *pTokArr
, nMatch
);
850 // ----------------------------------------------------------------------------
852 bool ScValidationData::IsEqualToTokenArray( ScBaseCell
* pCell
, const ScAddress
& rPos
, const ScTokenArray
& rTokArr
) const
854 // create a condition entry that tests on equality and set the passed token array
855 ScConditionEntry
aCondEntry( SC_COND_EQUAL
, &rTokArr
, NULL
, GetDocument(), rPos
);
856 return aCondEntry
.IsCellValid( pCell
, rPos
);
859 bool ScValidationData::IsListValid( ScBaseCell
* pCell
, const ScAddress
& rPos
) const
861 bool bIsValid
= false;
863 /* Compare input cell with all supported tokens from the formula.
864 Currently a formula may contain:
865 1) A list of strings (at least one string).
866 2) A single cell or range reference.
867 3) A single defined name (must contain a cell/range reference, another
868 name, or DB range, or a formula resulting in a cell/range reference
870 4) A single database range.
871 5) A formula resulting in a cell/range reference or matrix/array.
874 ::std::auto_ptr
< ScTokenArray
> pTokArr( CreateTokenArry( 0 ) );
876 // *** try if formula is a string list ***
878 UINT32 nFormat
= lclGetCellFormat( *GetDocument(), rPos
);
879 ScStringTokenIterator
aIt( *pTokArr
);
880 for( const String
* pString
= aIt
.First(); pString
&& aIt
.Ok(); pString
= aIt
.Next() )
882 /* Do not break the loop, if a valid string has been found.
883 This is to find invalid tokens following in the formula. */
886 // create a formula containing a single string or number
887 ScTokenArray aCondTokArr
;
889 if( GetDocument()->GetFormatTable()->IsNumberFormat( *pString
, nFormat
, fValue
) )
890 aCondTokArr
.AddDouble( fValue
);
892 aCondTokArr
.AddString( *pString
);
894 bIsValid
= IsEqualToTokenArray( pCell
, rPos
, aCondTokArr
);
901 // *** if not a string list, try if formula results in a cell range or
902 // anything else we recognize as valid ***
907 bIsValid
= GetSelectionFromFormula( NULL
, pCell
, rPos
, *pTokArr
, nMatch
);
908 bIsValid
= bIsValid
&& nMatch
>= 0;
914 // ============================================================================
915 // ============================================================================
917 ScValidationDataList::ScValidationDataList(const ScValidationDataList
& rList
) :
918 ScValidationEntries_Impl()
920 // fuer Ref-Undo - echte Kopie mit neuen Tokens!
922 USHORT nCount
= rList
.Count();
924 for (USHORT i
=0; i
<nCount
; i
++)
925 InsertNew( rList
[i
]->Clone() );
927 //! sortierte Eintraege aus rList schneller einfuegen ???
930 ScValidationDataList::ScValidationDataList(ScDocument
* pNewDoc
,
931 const ScValidationDataList
& rList
)
933 // fuer neues Dokument - echte Kopie mit neuen Tokens!
935 USHORT nCount
= rList
.Count();
937 for (USHORT i
=0; i
<nCount
; i
++)
938 InsertNew( rList
[i
]->Clone(pNewDoc
) );
940 //! sortierte Eintraege aus rList schneller einfuegen ???
943 ScValidationData
* ScValidationDataList::GetData( sal_uInt32 nKey
)
947 USHORT nCount
= Count();
948 for (USHORT i
=0; i
<nCount
; i
++)
949 if ((*this)[i
]->GetKey() == nKey
)
952 DBG_ERROR("ScValidationDataList: Eintrag nicht gefunden");
956 void ScValidationDataList::CompileXML()
958 USHORT nCount
= Count();
959 for (USHORT i
=0; i
<nCount
; i
++)
960 (*this)[i
]->CompileXML();
963 void ScValidationDataList::UpdateReference( UpdateRefMode eUpdateRefMode
,
964 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
966 USHORT nCount
= Count();
967 for (USHORT i
=0; i
<nCount
; i
++)
968 (*this)[i
]->UpdateReference( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
971 void ScValidationDataList::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
)
973 USHORT nCount
= Count();
974 for (USHORT i
=0; i
<nCount
; i
++)
975 (*this)[i
]->UpdateMoveTab( nOldPos
, nNewPos
);
978 bool ScValidationDataList::MarkUsedExternalReferences() const
980 bool bAllMarked
= false;
981 USHORT nCount
= Count();
982 for (USHORT i
=0; !bAllMarked
&& i
<nCount
; i
++)
983 bAllMarked
= (*this)[i
]->MarkUsedExternalReferences();
987 BOOL
ScValidationDataList::operator==( const ScValidationDataList
& r
) const
989 // fuer Ref-Undo - interne Variablen werden nicht verglichen
991 USHORT nCount
= Count();
992 BOOL bEqual
= ( nCount
== r
.Count() );
993 for (USHORT i
=0; i
<nCount
&& bEqual
; i
++) // Eintraege sind sortiert
994 if ( !(*this)[i
]->EqualEntries(*r
[i
]) ) // Eintraege unterschiedlich ?