1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "validat.hxx"
22 #include <sfx2/app.hxx>
23 #include <sfx2/docfile.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <basic/sbmeth.hxx>
26 #include <basic/sbmod.hxx>
27 #include <basic/sbstar.hxx>
28 #include <basic/basmgr.hxx>
30 #include <basic/sbx.hxx>
31 #include <svl/zforlist.hxx>
32 #include "svl/sharedstringpool.hxx"
33 #include <vcl/msgbox.hxx>
34 #include <rtl/math.hxx>
36 #include "scitems.hxx"
37 #include "document.hxx"
38 #include "formulacell.hxx"
39 #include "patattr.hxx"
40 #include "rechead.hxx"
41 #include "globstr.hrc"
42 #include "rangenam.hxx"
44 #include "typedstrdata.hxx"
45 #include "dociter.hxx"
46 #include "editutil.hxx"
47 #include "tokenarray.hxx"
48 #include "scmatrix.hxx"
53 using namespace formula
;
56 // Eintrag fuer Gueltigkeit (es gibt nur eine Bedingung)
59 ScValidationData::ScValidationData( ScValidationMode eMode
, ScConditionMode eOper
,
60 const OUString
& rExpr1
, const OUString
& rExpr2
,
61 ScDocument
* pDocument
, const ScAddress
& rPos
,
62 const OUString
& rExprNmsp1
, const OUString
& rExprNmsp2
,
63 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
) :
64 ScConditionEntry( eOper
, rExpr1
, rExpr2
, pDocument
, rPos
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
),
67 eErrorStyle( SC_VALERR_STOP
),
68 mnListType( ValidListType::UNSORTED
)
70 bShowInput
= bShowError
= false;
73 ScValidationData::ScValidationData( ScValidationMode eMode
, ScConditionMode eOper
,
74 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
75 ScDocument
* pDocument
, const ScAddress
& rPos
) :
76 ScConditionEntry( eOper
, pArr1
, pArr2
, pDocument
, rPos
),
79 eErrorStyle( SC_VALERR_STOP
),
80 mnListType( ValidListType::UNSORTED
)
82 bShowInput
= bShowError
= false;
85 ScValidationData::ScValidationData( const ScValidationData
& r
) :
86 ScConditionEntry( r
),
88 eDataMode( r
.eDataMode
),
89 bShowInput( r
.bShowInput
),
90 bShowError( r
.bShowError
),
91 eErrorStyle( r
.eErrorStyle
),
92 mnListType( r
.mnListType
),
93 aInputTitle( r
.aInputTitle
),
94 aInputMessage( r
.aInputMessage
),
95 aErrorTitle( r
.aErrorTitle
),
96 aErrorMessage( r
.aErrorMessage
)
98 // Formeln per RefCount kopiert
101 ScValidationData::ScValidationData( ScDocument
* pDocument
, const ScValidationData
& r
) :
102 ScConditionEntry( pDocument
, r
),
104 eDataMode( r
.eDataMode
),
105 bShowInput( r
.bShowInput
),
106 bShowError( r
.bShowError
),
107 eErrorStyle( r
.eErrorStyle
),
108 mnListType( r
.mnListType
),
109 aInputTitle( r
.aInputTitle
),
110 aInputMessage( r
.aInputMessage
),
111 aErrorTitle( r
.aErrorTitle
),
112 aErrorMessage( r
.aErrorMessage
)
114 // Formeln wirklich kopiert
117 ScValidationData::~ScValidationData()
121 bool ScValidationData::IsEmpty() const
124 ScValidationData
aDefault( SC_VALID_ANY
, SC_COND_EQUAL
, aEmpty
, aEmpty
, GetDocument(), ScAddress() );
125 return EqualEntries( aDefault
);
128 bool ScValidationData::EqualEntries( const ScValidationData
& r
) const
130 // gleiche Parameter eingestellt (ohne Key)
132 return ScConditionEntry::operator==(r
) &&
133 eDataMode
== r
.eDataMode
&&
134 bShowInput
== r
.bShowInput
&&
135 bShowError
== r
.bShowError
&&
136 eErrorStyle
== r
.eErrorStyle
&&
137 mnListType
== r
.mnListType
&&
138 aInputTitle
== r
.aInputTitle
&&
139 aInputMessage
== r
.aInputMessage
&&
140 aErrorTitle
== r
.aErrorTitle
&&
141 aErrorMessage
== r
.aErrorMessage
;
144 void ScValidationData::ResetInput()
149 void ScValidationData::ResetError()
154 void ScValidationData::SetInput( const OUString
& rTitle
, const OUString
& rMsg
)
157 aInputTitle
= rTitle
;
158 aInputMessage
= rMsg
;
161 void ScValidationData::SetError( const OUString
& rTitle
, const OUString
& rMsg
,
162 ScValidErrorStyle eStyle
)
165 eErrorStyle
= eStyle
;
166 aErrorTitle
= rTitle
;
167 aErrorMessage
= rMsg
;
170 bool ScValidationData::GetErrMsg( OUString
& rTitle
, OUString
& rMsg
,
171 ScValidErrorStyle
& rStyle
) const
173 rTitle
= aErrorTitle
;
174 rMsg
= aErrorMessage
;
175 rStyle
= eErrorStyle
;
179 bool ScValidationData::DoScript( const ScAddress
& rPos
, const OUString
& rInput
,
180 ScFormulaCell
* pCell
, Window
* pParent
) const
182 ScDocument
* pDocument
= GetDocument();
183 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
184 if ( !pDocSh
|| !pDocument
->CheckMacroWarn() )
187 bool bScriptReturnedFalse
= false; // Standard: kein Abbruch
190 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
> aParams(2);
192 // 1) eingegebener / berechneter Wert
193 OUString aValStr
= rInput
;
195 bool bIsValue
= false;
196 if ( pCell
) // wenn Zelle gesetzt, aus Interpret gerufen
198 bIsValue
= pCell
->IsValue();
200 nValue
= pCell
->GetValue();
202 aValStr
= pCell
->GetString().getString();
205 aParams
[0] = ::com::sun::star::uno::makeAny( nValue
);
207 aParams
[0] = ::com::sun::star::uno::makeAny( OUString( aValStr
) );
209 // 2) Position der Zelle
210 OUString
aPosStr(rPos
.Format(SCA_VALID
| SCA_TAB_3D
, pDocument
, pDocument
->GetAddressConvention()));
211 aParams
[1] = ::com::sun::star::uno::makeAny(aPosStr
);
213 // use link-update flag to prevent closing the document
214 // while the macro is running
215 bool bWasInLinkUpdate
= pDocument
->IsInLinkUpdate();
216 if ( !bWasInLinkUpdate
)
217 pDocument
->SetInLinkUpdate( true );
220 pDocument
->LockTable( rPos
.Tab() );
222 ::com::sun::star::uno::Any aRet
;
223 ::com::sun::star::uno::Sequence
< sal_Int16
> aOutArgsIndex
;
224 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Any
> aOutArgs
;
226 ErrCode eRet
= pDocSh
->CallXScript(
227 aErrorTitle
, aParams
, aRet
, aOutArgsIndex
, aOutArgs
);
230 pDocument
->UnlockTable( rPos
.Tab() );
232 if ( !bWasInLinkUpdate
)
233 pDocument
->SetInLinkUpdate( false );
235 // Check the return value from the script
236 // The contents of the cell get reset if the script returns false
238 if ( eRet
== ERRCODE_NONE
&&
239 aRet
.getValueType() == getCppuBooleanType() &&
243 bScriptReturnedFalse
= true;
246 if ( eRet
== ERRCODE_BASIC_METHOD_NOT_FOUND
&& !pCell
)
247 // Makro nicht gefunden (nur bei Eingabe)
249 //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
251 ErrorBox
aBox( pParent
, WinBits(WB_OK
),
252 ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND
) );
256 return bScriptReturnedFalse
;
261 bool ScValidationData::DoMacro( const ScAddress
& rPos
, const OUString
& rInput
,
262 ScFormulaCell
* pCell
, Window
* pParent
) const
264 if ( SfxApplication::IsXScriptURL( aErrorTitle
) )
266 return DoScript( rPos
, rInput
, pCell
, pParent
);
269 ScDocument
* pDocument
= GetDocument();
270 SfxObjectShell
* pDocSh
= pDocument
->GetDocumentShell();
271 if ( !pDocSh
|| !pDocument
->CheckMacroWarn() )
275 bool bRet
= false; // Standard: kein Abbruch
277 // Wenn das Dok waehrend eines Basic-Calls geladen wurde,
278 // ist das Sbx-Objekt evtl. nicht angelegt (?)
279 // pDocSh->GetSbxObject();
281 #ifndef DISABLE_SCRIPTING
282 // keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
284 // Funktion ueber den einfachen Namen suchen,
285 // dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
287 StarBASIC
* pRoot
= pDocSh
->GetBasic();
288 SbxVariable
* pVar
= pRoot
->Find( aErrorTitle
, SbxCLASS_METHOD
);
289 if ( pVar
&& pVar
->ISA(SbMethod
) )
291 SbMethod
* pMethod
= (SbMethod
*)pVar
;
292 SbModule
* pModule
= pMethod
->GetModule();
293 SbxObject
* pObject
= pModule
->GetParent();
294 OUStringBuffer aMacroStr
= pObject
->GetName();
295 aMacroStr
.append('.').append(pModule
->GetName()).append('.').append(pMethod
->GetName());
298 // the distinction between document- and app-basic has to be done
299 // by checking the parent (as in ScInterpreter::ScMacro), not by looping
300 // over all open documents, because this may be called from within loading,
301 // when SfxObjectShell::GetFirst/GetNext won't find the document.
303 if ( pObject
->GetParent() )
304 aBasicStr
= pObject
->GetParent()->GetName(); // Dokumentenbasic
306 aBasicStr
= SFX_APP()->GetName(); // Applikationsbasic
308 // Parameter fuer Makro
309 SbxArrayRef refPar
= new SbxArray
;
311 // 1) eingegebener / berechneter Wert
312 OUString aValStr
= rInput
;
314 bool bIsValue
= false;
315 if ( pCell
) // wenn Zelle gesetzt, aus Interpret gerufen
317 bIsValue
= pCell
->IsValue();
319 nValue
= pCell
->GetValue();
321 aValStr
= pCell
->GetString().getString();
324 refPar
->Get(1)->PutDouble( nValue
);
326 refPar
->Get(1)->PutString( aValStr
);
328 // 2) Position der Zelle
329 OUString
aPosStr(rPos
.Format(SCA_VALID
| SCA_TAB_3D
, pDocument
, pDocument
->GetAddressConvention()));
330 refPar
->Get(2)->PutString( aPosStr
);
332 // use link-update flag to prevent closing the document
333 // while the macro is running
334 bool bWasInLinkUpdate
= pDocument
->IsInLinkUpdate();
335 if ( !bWasInLinkUpdate
)
336 pDocument
->SetInLinkUpdate( true );
339 pDocument
->LockTable( rPos
.Tab() );
340 SbxVariableRef refRes
= new SbxVariable
;
341 ErrCode eRet
= pDocSh
->CallBasic( aMacroStr
.makeStringAndClear(), aBasicStr
, refPar
, refRes
);
343 pDocument
->UnlockTable( rPos
.Tab() );
345 if ( !bWasInLinkUpdate
)
346 pDocument
->SetInLinkUpdate( false );
348 // Eingabe abbrechen, wenn Basic-Makro sal_False zurueckgibt
349 if ( eRet
== ERRCODE_NONE
&& refRes
->GetType() == SbxBOOL
&& refRes
->GetBool() == false )
354 if ( !bDone
&& !pCell
) // Makro nicht gefunden (nur bei Eingabe)
356 //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
358 ErrorBox
aBox( pParent
, WinBits(WB_OK
),
359 ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND
) );
366 void ScValidationData::DoCalcError( ScFormulaCell
* pCell
) const
368 if ( eErrorStyle
== SC_VALERR_MACRO
)
369 DoMacro( pCell
->aPos
, EMPTY_OUSTRING
, pCell
, NULL
);
374 bool ScValidationData::DoError( Window
* pParent
, const OUString
& rInput
,
375 const ScAddress
& rPos
) const
377 if ( eErrorStyle
== SC_VALERR_MACRO
)
378 return DoMacro( rPos
, rInput
, NULL
, pParent
);
380 // Fehlermeldung ausgeben
382 OUString aTitle
= aErrorTitle
;
383 if (aTitle
.isEmpty())
384 aTitle
= ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0
); // application title
385 OUString aMessage
= aErrorMessage
;
386 if (aMessage
.isEmpty())
387 aMessage
= ScGlobal::GetRscString( STR_VALID_DEFERROR
);
389 //! ErrorBox / WarningBox / InfoBox ?
390 //! (bei InfoBox immer nur OK-Button)
396 nStyle
= WB_OK
| WB_DEF_OK
;
398 case SC_VALERR_WARNING
:
399 nStyle
= WB_OK_CANCEL
| WB_DEF_CANCEL
;
402 nStyle
= WB_OK_CANCEL
| WB_DEF_OK
;
406 // added to avoid warnings
410 MessBox
aBox( pParent
, WinBits(nStyle
), aTitle
, aMessage
);
411 sal_uInt16 nRet
= aBox
.Execute();
413 return ( eErrorStyle
== SC_VALERR_STOP
|| nRet
== RET_CANCEL
);
417 bool ScValidationData::IsDataValid(
418 const OUString
& rTest
, const ScPatternAttr
& rPattern
, const ScAddress
& rPos
) const
420 if ( eDataMode
== SC_VALID_ANY
) // check if any cell content is allowed
423 if (rTest
.isEmpty()) // check whether empty cells are allowed
424 return IsIgnoreBlank();
426 if (rTest
[0] == '=') // formulas do not pass the validity test
430 SvNumberFormatter
* pFormatter
= GetDocument()->GetFormatTable();
432 // get the value if any
433 sal_uInt32 nFormat
= rPattern
.GetNumberFormat( pFormatter
);
435 bool bIsVal
= pFormatter
->IsNumberFormat( rTest
, nFormat
, nVal
);
438 if (SC_VALID_TEXTLEN
== eDataMode
)
442 nLenVal
= static_cast<double>(rTest
.getLength());
445 // For numeric values use the resulting input line string to
446 // determine length, otherwise a once accepted value maybe could
447 // not be edited again, for example abbreviated dates or leading
448 // zeros or trailing zeros after decimal separator change length.
450 pFormatter
->GetInputLineString( nVal
, nFormat
, aStr
);
451 nLenVal
= static_cast<double>( aStr
.getLength() );
453 ScRefCellValue
aTmpCell(nLenVal
);
454 bRet
= IsCellValid(aTmpCell
, rPos
);
460 ScRefCellValue
aTmpCell(nVal
);
461 bRet
= IsDataValid(aTmpCell
, rPos
);
465 svl::SharedString aSS
= mpDoc
->GetSharedStringPool().intern(rTest
);
466 ScRefCellValue
aTmpCell(&aSS
);
467 bRet
= IsDataValid(aTmpCell
, rPos
);
474 bool ScValidationData::IsDataValid( ScRefCellValue
& rCell
, const ScAddress
& rPos
) const
476 if( eDataMode
== SC_VALID_LIST
)
477 return IsListValid(rCell
, rPos
);
483 switch (rCell
.meType
)
486 nVal
= rCell
.mfValue
;
488 case CELLTYPE_STRING
:
489 aString
= rCell
.mpString
->getString();
493 if (rCell
.mpEditText
)
494 aString
= ScEditUtil::GetString(*rCell
.mpEditText
, GetDocument());
497 case CELLTYPE_FORMULA
:
499 ScFormulaCell
* pFCell
= rCell
.mpFormula
;
500 bIsVal
= pFCell
->IsValue();
502 nVal
= pFCell
->GetValue();
504 aString
= pFCell
->GetString().getString();
507 default: // Notizen, Broadcaster
508 return IsIgnoreBlank(); // wie eingestellt
514 // SC_VALID_ANY schon oben
517 case SC_VALID_DECIMAL
:
518 case SC_VALID_DATE
: // Date/Time ist nur Formatierung
521 if ( bOk
&& eDataMode
== SC_VALID_WHOLE
)
522 bOk
= ::rtl::math::approxEqual( nVal
, floor(nVal
+0.5) ); // ganze Zahlen
524 bOk
= IsCellValid(rCell
, rPos
);
527 case SC_VALID_CUSTOM
:
528 // fuer Custom muss eOp == SC_COND_DIRECT sein
529 //! der Wert muss im Dokument stehen !!!!!!!!!!!!!!!!!!!!
530 bOk
= IsCellValid(rCell
, rPos
);
533 case SC_VALID_TEXTLEN
:
534 bOk
= !bIsVal
; // nur Text
537 double nLenVal
= (double) aString
.getLength();
538 ScRefCellValue
aTmpCell(nLenVal
);
539 bOk
= IsCellValid(aTmpCell
, rPos
);
544 OSL_FAIL("not yet done");
553 /** Token array helper. Iterates over all string tokens.
554 @descr The token array must contain separated string tokens only.
555 @param bSkipEmpty true = Ignores string tokens with empty strings. */
556 class ScStringTokenIterator
559 inline explicit ScStringTokenIterator( ScTokenArray
& rTokArr
, bool bSkipEmpty
= true ) :
560 mrTokArr( rTokArr
), mbSkipEmpty( bSkipEmpty
), mbOk( true ) {}
562 /** Returns the string of the first string token or NULL on error or empty token array. */
563 rtl_uString
* First();
564 /** Returns the string of the next string token or NULL on error or end of token array. */
567 /** Returns false, if a wrong token has been found. Does NOT return false on end of token array. */
568 inline bool Ok() const { return mbOk
; }
571 svl::SharedString maCurString
; /// Current string.
572 ScTokenArray
& mrTokArr
; /// The token array for iteration.
573 bool mbSkipEmpty
; /// Ignore empty strings.
574 bool mbOk
; /// true = correct token or end of token array.
577 rtl_uString
* ScStringTokenIterator::First()
584 rtl_uString
* ScStringTokenIterator::Next()
589 // seek to next non-separator token
590 const FormulaToken
* pToken
= mrTokArr
.NextNoSpaces();
591 while( pToken
&& (pToken
->GetOpCode() == ocSep
) )
592 pToken
= mrTokArr
.NextNoSpaces();
594 mbOk
= !pToken
|| (pToken
->GetType() == formula::svString
);
596 maCurString
= svl::SharedString(); // start with invalid string.
598 maCurString
= pToken
->GetString();
600 // string found but empty -> get next token; otherwise return it
601 return (mbSkipEmpty
&& maCurString
.isValid() && maCurString
.isEmpty()) ? Next() : maCurString
.getData();
604 // ----------------------------------------------------------------------------
606 /** Returns the number format of the passed cell, or the standard format. */
607 sal_uLong
lclGetCellFormat( ScDocument
& rDoc
, const ScAddress
& rPos
)
609 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( rPos
.Col(), rPos
.Row(), rPos
.Tab() );
611 pPattern
= rDoc
.GetDefPattern();
612 return pPattern
->GetNumberFormat( rDoc
.GetFormatTable() );
617 // ----------------------------------------------------------------------------
619 bool ScValidationData::HasSelectionList() const
621 return (eDataMode
== SC_VALID_LIST
) && (mnListType
!= ValidListType::INVISIBLE
);
624 bool ScValidationData::GetSelectionFromFormula(
625 std::vector
<ScTypedStrData
>* pStrings
, ScRefCellValue
& rCell
, const ScAddress
& rPos
,
626 const ScTokenArray
& rTokArr
, int& rMatch
) const
630 // pDoc is private in condition, use an accessor and a long winded name.
631 ScDocument
* pDocument
= GetDocument();
632 if( NULL
== pDocument
)
635 ScFormulaCell
aValidationSrc(
636 pDocument
, rPos
, rTokArr
, formula::FormulaGrammar::GRAM_DEFAULT
, MM_FORMULA
);
638 // Make sure the formula gets interpreted and a result is delivered,
639 // regardless of the AutoCalc setting.
640 aValidationSrc
.Interpret();
643 const ScMatrix
*pValues
= aValidationSrc
.GetMatrix();
646 // The somewhat nasty case of either an error occurred, or the
647 // dereferenced value of a single cell reference or an immediate result
648 // is stored as a single value.
650 // Use an interim matrix to create the TypedStrData below.
651 xMatRef
= new ScMatrix(1, 1, 0.0);
653 sal_uInt16 nErrCode
= aValidationSrc
.GetErrCode();
656 /* TODO : to use later in an alert box?
657 * OUString rStrResult = "...";
658 * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
661 xMatRef
->PutError( nErrCode
, 0, 0);
664 else if (aValidationSrc
.IsValue())
665 xMatRef
->PutDouble( aValidationSrc
.GetValue(), 0);
668 svl::SharedString aStr
= aValidationSrc
.GetString();
669 xMatRef
->PutString(aStr
, 0);
672 pValues
= xMatRef
.get();
675 // which index matched. We will want it eventually to pre-select that item.
678 SvNumberFormatter
* pFormatter
= GetDocument()->GetFormatTable();
680 SCSIZE nCol
, nRow
, nCols
, nRows
, n
= 0;
681 pValues
->GetDimensions( nCols
, nRows
);
686 ScTokenArray
* pArr
= (ScTokenArray
*) &rTokArr
;
689 if (pArr
->GetLen() == 1 && (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName())) != NULL
)
691 if (t
->GetOpCode() == ocDBArea
)
693 if (const ScDBData
* pDBData
= pDocument
->GetDBCollection()->getNamedDBs().findByIndex(t
->GetIndex()))
695 pDBData
->GetArea(aRange
);
699 else if (t
->GetOpCode() == ocName
)
701 ScRangeData
* pName
= pDocument
->GetRangeName()->findByIndex( t
->GetIndex() );
702 if (pName
&& pName
->IsReference(aRange
))
707 else if (t
->GetType() != svIndex
)
709 if (pArr
->IsValidReference(aRange
, rPos
))
716 /* XL artificially limits things to a single col or row in the UI but does
717 * not list the constraint in MOOXml. If a defined name or INDIRECT
718 * resulting in 1D is entered in the UI and the definition later modified
719 * to 2D, it is evaluated fine and also stored and loaded. Lets get ahead
720 * of the curve and support 2d. In XL, values are listed row-wise, do the
722 for( nRow
= 0; nRow
< nRows
; nRow
++ )
724 for( nCol
= 0; nCol
< nCols
; nCol
++ )
726 ScTokenArray aCondTokArr
;
727 ScTypedStrData
* pEntry
= NULL
;
729 ScMatrixValue nMatVal
= pValues
->Get( nCol
, nRow
);
731 // strings and empties
732 if( ScMatrix::IsNonValueType( nMatVal
.nType
) )
734 aValStr
= nMatVal
.GetString().getString();
736 if( NULL
!= pStrings
)
737 pEntry
= new ScTypedStrData( aValStr
, 0.0, ScTypedStrData::Standard
);
739 if (!rCell
.isEmpty() && rMatch
< 0)
740 aCondTokArr
.AddString( aValStr
);
744 sal_uInt16 nErr
= nMatVal
.GetError();
748 aValStr
= ScGlobal::GetErrorString( nErr
);
753 // Feature regression. Date formats are lost passing through the matrix
754 //pFormatter->GetInputLineString( pMatVal->fVal, 0, aValStr );
755 //For external reference and a formula that results in an area or array, date formats are still lost.
758 pDocument
->GetInputString((SCCOL
)(nCol
+aRange
.aStart
.Col()),
759 (SCROW
)(nRow
+aRange
.aStart
.Row()), aRange
.aStart
.Tab() , aValStr
);
763 OUString
sTmp(aValStr
);
764 pFormatter
->GetInputLineString( nMatVal
.fVal
, 0, sTmp
);
769 if (!rCell
.isEmpty() && rMatch
< 0)
771 // I am not sure errors will work here, but a user can no
772 // manually enter an error yet so the point is somewhat moot.
773 aCondTokArr
.AddDouble( nMatVal
.fVal
);
775 if( NULL
!= pStrings
)
776 pEntry
= new ScTypedStrData( aValStr
, nMatVal
.fVal
, ScTypedStrData::Value
);
779 if (rMatch
< 0 && !rCell
.isEmpty() && IsEqualToTokenArray(rCell
, rPos
, aCondTokArr
))
782 // short circuit on the first match if not filling the list
783 if( NULL
== pStrings
)
789 pStrings
->push_back(*pEntry
);
796 // In case of no match needed and an error occurred, return that error
797 // entry as valid instead of silently failing.
798 return bOk
|| rCell
.isEmpty();
801 bool ScValidationData::FillSelectionList(std::vector
<ScTypedStrData
>& rStrColl
, const ScAddress
& rPos
) const
805 if( HasSelectionList() )
807 boost::scoped_ptr
<ScTokenArray
> pTokArr( CreateTokenArry(0) );
809 // *** try if formula is a string list ***
811 sal_uInt32 nFormat
= lclGetCellFormat( *GetDocument(), rPos
);
812 ScStringTokenIterator
aIt( *pTokArr
);
813 for (rtl_uString
* pString
= aIt
.First(); pString
&& aIt
.Ok(); pString
= aIt
.Next())
816 OUString
aStr(pString
);
817 bool bIsValue
= GetDocument()->GetFormatTable()->IsNumberFormat(aStr
, nFormat
, fValue
);
820 aStr
, fValue
, bIsValue
? ScTypedStrData::Value
: ScTypedStrData::Standard
));
824 // *** if not a string list, try if formula results in a cell range or
825 // anything else we recognize as valid ***
830 ScRefCellValue aEmptyCell
;
831 bOk
= GetSelectionFromFormula(&rStrColl
, aEmptyCell
, rPos
, *pTokArr
, nMatch
);
838 // ----------------------------------------------------------------------------
840 bool ScValidationData::IsEqualToTokenArray( ScRefCellValue
& rCell
, const ScAddress
& rPos
, const ScTokenArray
& rTokArr
) const
842 // create a condition entry that tests on equality and set the passed token array
843 ScConditionEntry
aCondEntry( SC_COND_EQUAL
, &rTokArr
, NULL
, GetDocument(), rPos
);
844 return aCondEntry
.IsCellValid(rCell
, rPos
);
847 bool ScValidationData::IsListValid( ScRefCellValue
& rCell
, const ScAddress
& rPos
) const
849 bool bIsValid
= false;
851 /* Compare input cell with all supported tokens from the formula.
852 Currently a formula may contain:
853 1) A list of strings (at least one string).
854 2) A single cell or range reference.
855 3) A single defined name (must contain a cell/range reference, another
856 name, or DB range, or a formula resulting in a cell/range reference
858 4) A single database range.
859 5) A formula resulting in a cell/range reference or matrix/array.
862 SAL_WNODEPRECATED_DECLARATIONS_PUSH
863 ::std::auto_ptr
< ScTokenArray
> pTokArr( CreateTokenArry( 0 ) );
864 SAL_WNODEPRECATED_DECLARATIONS_POP
866 // *** try if formula is a string list ***
868 sal_uInt32 nFormat
= lclGetCellFormat( *GetDocument(), rPos
);
869 ScStringTokenIterator
aIt( *pTokArr
);
870 for (rtl_uString
* pString
= aIt
.First(); pString
&& aIt
.Ok(); pString
= aIt
.Next())
872 /* Do not break the loop, if a valid string has been found.
873 This is to find invalid tokens following in the formula. */
876 // create a formula containing a single string or number
877 ScTokenArray aCondTokArr
;
879 OUString
aStr(pString
);
880 if (GetDocument()->GetFormatTable()->IsNumberFormat(aStr
, nFormat
, fValue
))
881 aCondTokArr
.AddDouble( fValue
);
883 aCondTokArr
.AddString(aStr
);
885 bIsValid
= IsEqualToTokenArray(rCell
, rPos
, aCondTokArr
);
892 // *** if not a string list, try if formula results in a cell range or
893 // anything else we recognize as valid ***
898 bIsValid
= GetSelectionFromFormula(NULL
, rCell
, rPos
, *pTokArr
, nMatch
);
899 bIsValid
= bIsValid
&& nMatch
>= 0;
905 // ============================================================================
906 // ============================================================================
908 ScValidationDataList::ScValidationDataList(const ScValidationDataList
& rList
)
910 // fuer Ref-Undo - echte Kopie mit neuen Tokens!
912 for (const_iterator it
= rList
.begin(); it
!= rList
.end(); ++it
)
914 InsertNew( (*it
)->Clone() );
917 //! sortierte Eintraege aus rList schneller einfuegen ???
920 ScValidationDataList::ScValidationDataList(ScDocument
* pNewDoc
,
921 const ScValidationDataList
& rList
)
923 // fuer neues Dokument - echte Kopie mit neuen Tokens!
925 for (const_iterator it
= rList
.begin(); it
!= rList
.end(); ++it
)
927 InsertNew( (*it
)->Clone(pNewDoc
) );
930 //! sortierte Eintraege aus rList schneller einfuegen ???
933 ScValidationData
* ScValidationDataList::GetData( sal_uInt32 nKey
)
937 for( iterator it
= begin(); it
!= end(); ++it
)
938 if( (*it
)->GetKey() == nKey
)
941 OSL_FAIL("ScValidationDataList: Entry not found");
945 void ScValidationDataList::CompileXML()
947 for( iterator it
= begin(); it
!= end(); ++it
)
951 void ScValidationDataList::UpdateReference( sc::RefUpdateContext
& rCxt
)
953 for( iterator it
= begin(); it
!= end(); ++it
)
954 (*it
)->UpdateReference(rCxt
);
957 void ScValidationDataList::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
959 for (iterator it
= begin(); it
!= end(); ++it
)
960 (*it
)->UpdateInsertTab(rCxt
);
963 void ScValidationDataList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
965 for (iterator it
= begin(); it
!= end(); ++it
)
966 (*it
)->UpdateDeleteTab(rCxt
);
969 void ScValidationDataList::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
)
971 for (iterator it
= begin(); it
!= end(); ++it
)
972 (*it
)->UpdateMoveTab(rCxt
);
975 bool ScValidationDataList::operator==( const ScValidationDataList
& r
) const
977 // fuer Ref-Undo - interne Variablen werden nicht verglichen
979 size_t nCount
= maData
.size();
980 bool bEqual
= ( nCount
== r
.maData
.size() );
981 for( const_iterator it1
= begin(), it2
= r
.begin(); it1
!= end() && bEqual
; ++it1
, ++it2
) // Eintraege sind sortiert
982 if ( !(*it1
)->EqualEntries(**it2
) ) // Eintraege unterschiedlich ?
988 ScValidationDataList::iterator
ScValidationDataList::begin()
990 return maData
.begin();
993 ScValidationDataList::const_iterator
ScValidationDataList::begin() const
995 return maData
.begin();
998 ScValidationDataList::iterator
ScValidationDataList::end()
1000 return maData
.end();
1003 ScValidationDataList::const_iterator
ScValidationDataList::end() const
1005 return maData
.end();
1008 void ScValidationDataList::clear()
1013 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */