Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / validat.cxx
blobb7e51bad3cbfd673f921a6eaaeef1efeeff9ec85
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
43 #include "dbdata.hxx"
44 #include "typedstrdata.hxx"
45 #include "dociter.hxx"
46 #include "editutil.hxx"
47 #include "tokenarray.hxx"
48 #include "scmatrix.hxx"
50 #include <math.h>
51 #include <memory>
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 ),
65 nKey( 0 ),
66 eDataMode( eMode ),
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 ),
77 nKey( 0 ),
78 eDataMode( eMode ),
79 eErrorStyle( SC_VALERR_STOP ),
80 mnListType( ValidListType::UNSORTED )
82 bShowInput = bShowError = false;
85 ScValidationData::ScValidationData( const ScValidationData& r ) :
86 ScConditionEntry( r ),
87 nKey( r.nKey ),
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 ),
103 nKey( r.nKey ),
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
123 OUString aEmpty;
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()
146 bShowInput = false;
149 void ScValidationData::ResetError()
151 bShowError = false;
154 void ScValidationData::SetInput( const OUString& rTitle, const OUString& rMsg )
156 bShowInput = true;
157 aInputTitle = rTitle;
158 aInputMessage = rMsg;
161 void ScValidationData::SetError( const OUString& rTitle, const OUString& rMsg,
162 ScValidErrorStyle eStyle )
164 bShowError = true;
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;
176 return bShowError;
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() )
185 return false;
187 bool bScriptReturnedFalse = false; // Standard: kein Abbruch
189 // Set up parameters
190 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aParams(2);
192 // 1) eingegebener / berechneter Wert
193 OUString aValStr = rInput;
194 double nValue;
195 bool bIsValue = false;
196 if ( pCell ) // wenn Zelle gesetzt, aus Interpret gerufen
198 bIsValue = pCell->IsValue();
199 if ( bIsValue )
200 nValue = pCell->GetValue();
201 else
202 aValStr = pCell->GetString().getString();
204 if ( bIsValue )
205 aParams[0] = ::com::sun::star::uno::makeAny( nValue );
206 else
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 );
219 if ( pCell )
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 );
229 if ( pCell )
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
237 bool bTmp = false;
238 if ( eRet == ERRCODE_NONE &&
239 aRet.getValueType() == getCppuBooleanType() &&
240 ( aRet >>= bTmp ) &&
241 !bTmp )
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 ) );
253 aBox.Execute();
256 return bScriptReturnedFalse;
259 // true -> Abbruch
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() )
272 return false;
274 bool bDone = false;
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());
296 OUString aBasicStr;
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
305 else
306 aBasicStr = SFX_APP()->GetName(); // Applikationsbasic
308 // Parameter fuer Makro
309 SbxArrayRef refPar = new SbxArray;
311 // 1) eingegebener / berechneter Wert
312 OUString aValStr = rInput;
313 double nValue = 0.0;
314 bool bIsValue = false;
315 if ( pCell ) // wenn Zelle gesetzt, aus Interpret gerufen
317 bIsValue = pCell->IsValue();
318 if ( bIsValue )
319 nValue = pCell->GetValue();
320 else
321 aValStr = pCell->GetString().getString();
323 if ( bIsValue )
324 refPar->Get(1)->PutDouble( nValue );
325 else
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 );
338 if ( pCell )
339 pDocument->LockTable( rPos.Tab() );
340 SbxVariableRef refRes = new SbxVariable;
341 ErrCode eRet = pDocSh->CallBasic( aMacroStr.makeStringAndClear(), aBasicStr, refPar, refRes );
342 if ( pCell )
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 )
350 bRet = true;
351 bDone = true;
353 #endif
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 ) );
360 aBox.Execute();
363 return bRet;
366 void ScValidationData::DoCalcError( ScFormulaCell* pCell ) const
368 if ( eErrorStyle == SC_VALERR_MACRO )
369 DoMacro( pCell->aPos, EMPTY_OUSTRING, pCell, NULL );
372 // true -> Abbruch
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)
392 WinBits nStyle = 0;
393 switch (eErrorStyle)
395 case SC_VALERR_STOP:
396 nStyle = WB_OK | WB_DEF_OK;
397 break;
398 case SC_VALERR_WARNING:
399 nStyle = WB_OK_CANCEL | WB_DEF_CANCEL;
400 break;
401 case SC_VALERR_INFO:
402 nStyle = WB_OK_CANCEL | WB_DEF_OK;
403 break;
404 default:
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
421 return true;
423 if (rTest.isEmpty()) // check whether empty cells are allowed
424 return IsIgnoreBlank();
426 if (rTest[0] == '=') // formulas do not pass the validity test
427 return false;
430 SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
432 // get the value if any
433 sal_uInt32 nFormat = rPattern.GetNumberFormat( pFormatter );
434 double nVal;
435 bool bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
437 bool bRet;
438 if (SC_VALID_TEXTLEN == eDataMode)
440 double nLenVal;
441 if (!bIsVal)
442 nLenVal = static_cast<double>(rTest.getLength());
443 else
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.
449 OUString aStr;
450 pFormatter->GetInputLineString( nVal, nFormat, aStr);
451 nLenVal = static_cast<double>( aStr.getLength() );
453 ScRefCellValue aTmpCell(nLenVal);
454 bRet = IsCellValid(aTmpCell, rPos);
456 else
458 if (bIsVal)
460 ScRefCellValue aTmpCell(nVal);
461 bRet = IsDataValid(aTmpCell, rPos);
463 else
465 svl::SharedString aSS = mpDoc->GetSharedStringPool().intern(rTest);
466 ScRefCellValue aTmpCell(&aSS);
467 bRet = IsDataValid(aTmpCell, rPos);
471 return bRet;
474 bool ScValidationData::IsDataValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
476 if( eDataMode == SC_VALID_LIST )
477 return IsListValid(rCell, rPos);
479 double nVal = 0.0;
480 OUString aString;
481 bool bIsVal = true;
483 switch (rCell.meType)
485 case CELLTYPE_VALUE:
486 nVal = rCell.mfValue;
487 break;
488 case CELLTYPE_STRING:
489 aString = rCell.mpString->getString();
490 bIsVal = false;
491 break;
492 case CELLTYPE_EDIT:
493 if (rCell.mpEditText)
494 aString = ScEditUtil::GetString(*rCell.mpEditText, GetDocument());
495 bIsVal = false;
496 break;
497 case CELLTYPE_FORMULA:
499 ScFormulaCell* pFCell = rCell.mpFormula;
500 bIsVal = pFCell->IsValue();
501 if ( bIsVal )
502 nVal = pFCell->GetValue();
503 else
504 aString = pFCell->GetString().getString();
506 break;
507 default: // Notizen, Broadcaster
508 return IsIgnoreBlank(); // wie eingestellt
511 bool bOk = true;
512 switch (eDataMode)
514 // SC_VALID_ANY schon oben
516 case SC_VALID_WHOLE:
517 case SC_VALID_DECIMAL:
518 case SC_VALID_DATE: // Date/Time ist nur Formatierung
519 case SC_VALID_TIME:
520 bOk = bIsVal;
521 if ( bOk && eDataMode == SC_VALID_WHOLE )
522 bOk = ::rtl::math::approxEqual( nVal, floor(nVal+0.5) ); // ganze Zahlen
523 if ( bOk )
524 bOk = IsCellValid(rCell, rPos);
525 break;
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);
531 break;
533 case SC_VALID_TEXTLEN:
534 bOk = !bIsVal; // nur Text
535 if ( bOk )
537 double nLenVal = (double) aString.getLength();
538 ScRefCellValue aTmpCell(nLenVal);
539 bOk = IsCellValid(aTmpCell, rPos);
541 break;
543 default:
544 OSL_FAIL("not yet done");
545 break;
548 return bOk;
551 namespace {
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
558 public:
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. */
565 rtl_uString* Next();
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; }
570 private:
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()
579 mrTokArr.Reset();
580 mbOk = true;
581 return Next();
584 rtl_uString* ScStringTokenIterator::Next()
586 if( !mbOk )
587 return NULL;
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.
597 if (mbOk && pToken)
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() );
610 if( !pPattern )
611 pPattern = rDoc.GetDefPattern();
612 return pPattern->GetNumberFormat( rDoc.GetFormatTable() );
615 } // namespace
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
628 bool bOk = true;
630 // pDoc is private in condition, use an accessor and a long winded name.
631 ScDocument* pDocument = GetDocument();
632 if( NULL == pDocument )
633 return false;
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();
642 ScMatrixRef xMatRef;
643 const ScMatrix *pValues = aValidationSrc.GetMatrix();
644 if (!pValues)
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();
654 if (nErrCode)
656 /* TODO : to use later in an alert box?
657 * OUString rStrResult = "...";
658 * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
661 xMatRef->PutError( nErrCode, 0, 0);
662 bOk = false;
664 else if (aValidationSrc.IsValue())
665 xMatRef->PutDouble( aValidationSrc.GetValue(), 0);
666 else
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.
676 rMatch = -1;
678 SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
680 SCSIZE nCol, nRow, nCols, nRows, n = 0;
681 pValues->GetDimensions( nCols, nRows );
683 bool bRef = false;
684 ScRange aRange;
686 ScTokenArray* pArr = (ScTokenArray*) &rTokArr;
687 pArr->Reset();
688 ScToken* t = NULL;
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);
696 bRef = true;
699 else if (t->GetOpCode() == ocName)
701 ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
702 if (pName && pName->IsReference(aRange))
704 bRef = true;
707 else if (t->GetType() != svIndex)
709 if (pArr->IsValidReference(aRange, rPos))
711 bRef = true;
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
721 * same. */
722 for( nRow = 0; nRow < nRows ; nRow++ )
724 for( nCol = 0; nCol < nCols ; nCol++ )
726 ScTokenArray aCondTokArr;
727 ScTypedStrData* pEntry = NULL;
728 OUString aValStr;
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 );
742 else
744 sal_uInt16 nErr = nMatVal.GetError();
746 if( 0 != nErr )
748 aValStr = ScGlobal::GetErrorString( nErr );
750 else
752 // FIXME FIXME FIXME
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.
756 if ( bRef )
758 pDocument->GetInputString((SCCOL)(nCol+aRange.aStart.Col()),
759 (SCROW)(nRow+aRange.aStart.Row()), aRange.aStart.Tab() , aValStr);
761 else
763 OUString sTmp(aValStr);
764 pFormatter->GetInputLineString( nMatVal.fVal, 0, sTmp );
765 aValStr = 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))
781 rMatch = n;
782 // short circuit on the first match if not filling the list
783 if( NULL == pStrings )
784 return true;
787 if( NULL != pEntry )
789 pStrings->push_back(*pEntry);
790 delete pEntry;
791 n++;
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
803 bool bOk = false;
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())
815 double fValue;
816 OUString aStr(pString);
817 bool bIsValue = GetDocument()->GetFormatTable()->IsNumberFormat(aStr, nFormat, fValue);
818 rStrColl.push_back(
819 ScTypedStrData(
820 aStr, fValue, bIsValue ? ScTypedStrData::Value : ScTypedStrData::Standard));
822 bOk = aIt.Ok();
824 // *** if not a string list, try if formula results in a cell range or
825 // anything else we recognize as valid ***
827 if (!bOk)
829 int nMatch;
830 ScRefCellValue aEmptyCell;
831 bOk = GetSelectionFromFormula(&rStrColl, aEmptyCell, rPos, *pTokArr, nMatch);
835 return bOk;
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
857 or matrix/array).
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. */
874 if( !bIsValid )
876 // create a formula containing a single string or number
877 ScTokenArray aCondTokArr;
878 double fValue;
879 OUString aStr(pString);
880 if (GetDocument()->GetFormatTable()->IsNumberFormat(aStr, nFormat, fValue))
881 aCondTokArr.AddDouble( fValue );
882 else
883 aCondTokArr.AddString(aStr);
885 bIsValid = IsEqualToTokenArray(rCell, rPos, aCondTokArr);
889 if( !aIt.Ok() )
890 bIsValid = false;
892 // *** if not a string list, try if formula results in a cell range or
893 // anything else we recognize as valid ***
895 if (!bIsValid)
897 int nMatch;
898 bIsValid = GetSelectionFromFormula(NULL, rCell, rPos, *pTokArr, nMatch);
899 bIsValid = bIsValid && nMatch >= 0;
902 return bIsValid;
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 )
935 //! binaer suchen
937 for( iterator it = begin(); it != end(); ++it )
938 if( (*it)->GetKey() == nKey )
939 return *it;
941 OSL_FAIL("ScValidationDataList: Entry not found");
942 return NULL;
945 void ScValidationDataList::CompileXML()
947 for( iterator it = begin(); it != end(); ++it )
948 (*it)->CompileXML();
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 ?
983 bEqual = false;
985 return bEqual;
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()
1010 maData.clear();
1013 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */