1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpre.hxx,v $
10 * $Revision: 1.35.44.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "doubleref.hxx"
39 #include "document.hxx"
40 #include "queryparam.hxx"
41 #include "globstr.hrc"
46 using ::rtl::OUString
;
47 using ::std::auto_ptr
;
52 void lcl_toUpper(OUString
& rStr
)
54 rStr
= ScGlobal::pCharClass
->toUpper(rStr
.trim(), 0, rStr
.getLength());
57 bool lcl_createStarQuery(ScQueryParamBase
* pParam
, const ScDBRangeBase
* pDBRef
, const ScDBRangeBase
* pQueryRef
)
59 // A valid StarQuery must be at least 4 columns wide. To be precise it
60 // should be exactly 4 columns ...
61 // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
62 // column Excel style query range immediately left to itself would result
63 // in a circular reference when the field name or operator or value (first
64 // to third query range column) is obtained (#i58354#). Furthermore, if the
65 // range wasn't sufficiently specified data changes wouldn't flag formula
66 // cells for recalculation.
68 if (pQueryRef
->getColSize() < 4)
76 SCROW nRows
= pDBRef
->getRowSize();
77 SCSIZE nNewEntries
= static_cast<SCSIZE
>(nRows
);
78 pParam
->Resize(nNewEntries
);
82 ScQueryEntry
& rEntry
= pParam
->GetEntry(nIndex
);
88 // For all entries after the first one, check the and/or connector in the first column.
89 aCellStr
= pQueryRef
->getString(0, nRow
);
90 lcl_toUpper(aCellStr
);
91 if ( aCellStr
.equals(ScGlobal::GetRscString(STR_TABLE_UND
)) )
93 rEntry
.eConnect
= SC_AND
;
96 else if ( aCellStr
.equals(ScGlobal::GetRscString(STR_TABLE_ODER
)) )
98 rEntry
.eConnect
= SC_OR
;
103 if ((nIndex
< 1) || bValid
)
105 // field name in the 2nd column.
107 aCellStr
= pQueryRef
->getString(1, nRow
);
108 SCCOL nField
= pDBRef
->findFieldColumn(aCellStr
); // TODO: must be case insensitive comparison.
109 if (ValidCol(nField
))
111 rEntry
.nField
= nField
;
120 // equality, non-equality operator in the 3rd column.
122 aCellStr
= pQueryRef
->getString(2, nRow
);
123 lcl_toUpper(aCellStr
);
124 const sal_Unicode
* p
= aCellStr
.getStr();
125 if (p
[0] == sal_Unicode('<'))
127 if (p
[1] == sal_Unicode('>'))
128 rEntry
.eOp
= SC_NOT_EQUAL
;
129 else if (p
[1] == sal_Unicode('='))
130 rEntry
.eOp
= SC_LESS_EQUAL
;
132 rEntry
.eOp
= SC_LESS
;
134 else if (p
[0] == sal_Unicode('>'))
136 if (p
[1] == sal_Unicode('='))
137 rEntry
.eOp
= SC_GREATER_EQUAL
;
139 rEntry
.eOp
= SC_GREATER
;
141 else if (p
[0] == sal_Unicode('='))
142 rEntry
.eOp
= SC_EQUAL
;
148 // Finally, the right-hand-side value in the 4th column.
149 *rEntry
.pStr
= pQueryRef
->getString(3, nRow
);
150 rEntry
.bDoQuery
= TRUE
;
155 while (bValid
&& (nRow
< nRows
) /* && (nIndex < MAXQUERY) */ );
159 bool lcl_createExcelQuery(
160 ScQueryParamBase
* pParam
, const ScDBRangeBase
* pDBRef
, const ScDBRangeBase
* pQueryRef
)
163 SCCOL nCols
= pQueryRef
->getColSize();
164 SCROW nRows
= pQueryRef
->getRowSize();
165 vector
<SCCOL
> aFields(nCols
);
167 while (bValid
&& (nCol
< nCols
))
169 OUString aQueryStr
= pQueryRef
->getString(nCol
, 0);
170 SCCOL nField
= pDBRef
->findFieldColumn(aQueryStr
);
171 if (ValidCol(nField
))
172 aFields
[nCol
] = nField
;
180 // ULONG nVisible = 0;
181 // for ( nCol=nCol1; nCol<=nCol2; nCol++ )
182 // nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
184 // Count the number of visible cells (excluding the header row). Each
185 // visible cell corresponds with a single query.
186 SCSIZE nVisible
= pQueryRef
->getVisibleDataCellCount();
187 if ( nVisible
> SCSIZE_MAX
/ sizeof(void*) )
189 DBG_ERROR("zu viele Filterkritierien");
193 SCSIZE nNewEntries
= nVisible
;
194 pParam
->Resize( nNewEntries
);
204 aCellStr
= pQueryRef
->getString(nCol
, nRow
);
205 ScGlobal::pCharClass
->toUpper( aCellStr
);
206 if (aCellStr
.Len() > 0)
208 if (nIndex
< nNewEntries
)
210 pParam
->GetEntry(nIndex
).nField
= aFields
[nCol
];
211 pParam
->FillInExcelSyntax(aCellStr
, nIndex
);
213 if (nIndex
< nNewEntries
)
214 pParam
->GetEntry(nIndex
).eConnect
= SC_AND
;
222 if (nIndex
< nNewEntries
)
223 pParam
->GetEntry(nIndex
).eConnect
= SC_OR
;
229 bool lcl_fillQueryEntries(
230 ScQueryParamBase
* pParam
, const ScDBRangeBase
* pDBRef
, const ScDBRangeBase
* pQueryRef
)
232 SCSIZE nCount
= pParam
->GetEntryCount();
233 for (SCSIZE i
= 0; i
< nCount
; ++i
)
234 pParam
->GetEntry(i
).Clear();
236 // Standard QueryTabelle
237 bool bValid
= lcl_createStarQuery(pParam
, pDBRef
, pQueryRef
);
238 // Excel QueryTabelle
240 bValid
= lcl_createExcelQuery(pParam
, pDBRef
, pQueryRef
);
242 nCount
= pParam
->GetEntryCount();
245 // bQueryByString muss gesetzt sein
246 for (SCSIZE i
= 0; i
< nCount
; ++i
)
247 pParam
->GetEntry(i
).bQueryByString
= true;
252 for (SCSIZE i
= 0; i
< nCount
; ++i
)
253 pParam
->GetEntry(i
).Clear();
260 // ============================================================================
262 ScDBRangeBase::ScDBRangeBase(ScDocument
* pDoc
, RefType eType
) :
263 mpDoc(pDoc
), meType(eType
)
267 ScDBRangeBase::~ScDBRangeBase()
271 ScDBRangeBase::RefType
ScDBRangeBase::getType() const
276 bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase
* pParam
, const ScDBRangeBase
* pDBRef
) const
281 return lcl_fillQueryEntries(pParam
, pDBRef
, this);
284 void ScDBRangeBase::fillQueryOptions(ScQueryParamBase
* pParam
)
286 pParam
->bHasHeader
= true;
287 pParam
->bByRow
= true;
288 pParam
->bInplace
= true;
289 pParam
->bCaseSens
= false;
290 pParam
->bRegExp
= false;
291 pParam
->bDuplicate
= true;
292 pParam
->bMixedComparison
= false;
295 ScDocument
* ScDBRangeBase::getDoc() const
300 // ============================================================================
302 ScDBInternalRange::ScDBInternalRange(ScDocument
* pDoc
, const ScRange
& rRange
) :
303 ScDBRangeBase(pDoc
, INTERNAL
), maRange(rRange
)
307 ScDBInternalRange::~ScDBInternalRange()
311 const ScRange
& ScDBInternalRange::getRange() const
316 SCCOL
ScDBInternalRange::getColSize() const
318 return maRange
.aEnd
.Col() - maRange
.aStart
.Col() + 1;
321 SCROW
ScDBInternalRange::getRowSize() const
323 return maRange
.aEnd
.Row() - maRange
.aStart
.Row() + 1;
326 SCSIZE
ScDBInternalRange::getVisibleDataCellCount() const
328 SCCOL nCols
= getColSize();
329 SCROW nRows
= getRowSize();
333 return (nRows
-1)*nCols
;
336 OUString
ScDBInternalRange::getString(SCCOL nCol
, SCROW nRow
) const
339 const ScAddress
& s
= maRange
.aStart
;
340 getDoc()->GetString(s
.Col() + nCol
, s
.Row() + nRow
, maRange
.aStart
.Tab(), aStr
);
344 SCCOL
ScDBInternalRange::getFirstFieldColumn() const
346 return getRange().aStart
.Col();
349 SCCOL
ScDBInternalRange::findFieldColumn(SCCOL nIndex
) const
351 const ScRange
& rRange
= getRange();
352 const ScAddress
& s
= rRange
.aStart
;
353 const ScAddress
& e
= rRange
.aEnd
;
355 SCCOL nDBCol1
= s
.Col();
356 SCCOL nDBCol2
= e
.Col();
358 if ( nIndex
<= 0 || nIndex
> (nDBCol2
- nDBCol1
+ 1) )
361 return Min(nDBCol2
, static_cast<SCCOL
>(nDBCol1
+ nIndex
- 1));
364 sal_uInt16
ScDBInternalRange::getCellString(OUString
& rStr
, ScBaseCell
* pCell
) const
370 SvNumberFormatter
* pFormatter
= getDoc()->GetFormatTable();
371 switch (pCell
->GetCellType())
373 case CELLTYPE_STRING
:
374 ((ScStringCell
*) pCell
)->GetString(aStr
);
377 ((ScEditCell
*) pCell
)->GetString(aStr
);
379 case CELLTYPE_FORMULA
:
381 ScFormulaCell
* pFCell
= (ScFormulaCell
*) pCell
;
382 nErr
= pFCell
->GetErrCode();
383 if (pFCell
->IsValue())
385 double fVal
= pFCell
->GetValue();
386 ULONG nIndex
= pFormatter
->GetStandardFormat(
389 pFormatter
->GetInputLineString(fVal
, nIndex
, aStr
);
392 pFCell
->GetString(aStr
);
397 double fVal
= ((ScValueCell
*) pCell
)->GetValue();
398 ULONG nIndex
= pFormatter
->GetStandardFormat(
401 pFormatter
->GetInputLineString(fVal
, nIndex
, aStr
);
412 SCCOL
ScDBInternalRange::findFieldColumn(const OUString
& rStr
, sal_uInt16
* pErr
) const
414 const ScAddress
& s
= maRange
.aStart
;
415 const ScAddress
& e
= maRange
.aEnd
;
416 OUString aUpper
= rStr
;
419 SCCOL nDBCol1
= s
.Col();
420 SCROW nDBRow1
= s
.Row();
421 SCTAB nDBTab1
= s
.Tab();
422 SCCOL nDBCol2
= e
.Col();
424 SCCOL nField
= nDBCol1
;
429 ScAddress
aLook( nDBCol1
, nDBRow1
, nDBTab1
);
430 while (!bFound
&& (aLook
.Col() <= nDBCol2
))
432 ScBaseCell
* pCell
= getDoc()->GetCell( aLook
);
433 sal_uInt16 nErr
= getCellString( aCellStr
, pCell
);
436 lcl_toUpper(aCellStr
);
437 bFound
= ScGlobal::GetpTransliteration()->isEqual(aCellStr
, aUpper
);
441 nField
= aLook
.Col();
443 return bFound
? nField
: -1;
446 ScDBQueryParamBase
* ScDBInternalRange::createQueryParam(const ScDBRangeBase
* pQueryRef
) const
448 auto_ptr
<ScDBQueryParamInternal
> pParam(new ScDBQueryParamInternal
);
450 // Set the database range first.
451 const ScAddress
& s
= maRange
.aStart
;
452 const ScAddress
& e
= maRange
.aEnd
;
453 pParam
->nCol1
= s
.Col();
454 pParam
->nRow1
= s
.Row();
455 pParam
->nCol2
= e
.Col();
456 pParam
->nRow2
= e
.Row();
457 pParam
->nTab
= s
.Tab();
459 fillQueryOptions(pParam
.get());
461 // Now construct the query entries from the query range.
462 if (!pQueryRef
->fillQueryEntries(pParam
.get(), this))
465 return pParam
.release();
468 bool ScDBInternalRange::isRangeEqual(const ScRange
& rRange
) const
470 return maRange
== rRange
;
473 // ============================================================================
475 ScDBExternalRange::ScDBExternalRange(ScDocument
* pDoc
, const ScMatrixRef
& pMat
) :
476 ScDBRangeBase(pDoc
, EXTERNAL
), mpMatrix(pMat
)
479 mpMatrix
->GetDimensions(nC
, nR
);
484 ScDBExternalRange::~ScDBExternalRange()
488 SCCOL
ScDBExternalRange::getColSize() const
493 SCROW
ScDBExternalRange::getRowSize() const
498 SCSIZE
ScDBExternalRange::getVisibleDataCellCount() const
500 SCCOL nCols
= getColSize();
501 SCROW nRows
= getRowSize();
505 return (nRows
-1)*nCols
;
508 OUString
ScDBExternalRange::getString(SCCOL nCol
, SCROW nRow
) const
510 if (nCol
>= mnCols
|| nRow
>= mnRows
)
513 return mpMatrix
->GetString(nCol
, nRow
);
516 SCCOL
ScDBExternalRange::getFirstFieldColumn() const
521 SCCOL
ScDBExternalRange::findFieldColumn(SCCOL nIndex
) const
534 SCCOL
ScDBExternalRange::findFieldColumn(const OUString
& rStr
, sal_uInt16
* pErr
) const
539 OUString aUpper
= rStr
;
541 for (SCCOL i
= 0; i
< mnCols
; ++i
)
543 OUString aUpperVal
= mpMatrix
->GetString(i
, 0);
544 lcl_toUpper(aUpperVal
);
545 if (aUpper
.equals(aUpperVal
))
551 ScDBQueryParamBase
* ScDBExternalRange::createQueryParam(const ScDBRangeBase
* pQueryRef
) const
553 auto_ptr
<ScDBQueryParamMatrix
> pParam(new ScDBQueryParamMatrix
);
554 pParam
->mpMatrix
= mpMatrix
;
555 fillQueryOptions(pParam
.get());
557 // Now construct the query entries from the query range.
558 if (!pQueryRef
->fillQueryEntries(pParam
.get(), this))
561 return pParam
.release();
564 bool ScDBExternalRange::isRangeEqual(const ScRange
& /*rRange*/) const