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