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