Update ooo320-m1
[ooovba.git] / sc / source / core / tool / doubleref.cxx
blobe1bba5c2d4264d774b1fc7ff3c2222509780a0b6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
37 #include "cell.hxx"
38 #include "global.hxx"
39 #include "document.hxx"
40 #include "queryparam.hxx"
41 #include "globstr.hrc"
43 #include <memory>
44 #include <vector>
46 using ::rtl::OUString;
47 using ::std::auto_ptr;
48 using ::std::vector;
50 namespace {
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)
69 return false;
71 BOOL bValid;
72 BOOL bFound;
73 OUString aCellStr;
74 SCSIZE nIndex = 0;
75 SCROW nRow = 0;
76 SCROW nRows = pDBRef->getRowSize();
77 SCSIZE nNewEntries = static_cast<SCSIZE>(nRows);
78 pParam->Resize(nNewEntries);
82 ScQueryEntry& rEntry = pParam->GetEntry(nIndex);
84 bValid = FALSE;
86 if (nIndex > 0)
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;
94 bValid = TRUE;
96 else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) )
98 rEntry.eConnect = SC_OR;
99 bValid = TRUE;
103 if ((nIndex < 1) || bValid)
105 // field name in the 2nd column.
106 bFound = FALSE;
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;
112 bValid = true;
114 else
115 bValid = false;
118 if (bValid)
120 // equality, non-equality operator in the 3rd column.
121 bFound = FALSE;
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;
131 else
132 rEntry.eOp = SC_LESS;
134 else if (p[0] == sal_Unicode('>'))
136 if (p[1] == sal_Unicode('='))
137 rEntry.eOp = SC_GREATER_EQUAL;
138 else
139 rEntry.eOp = SC_GREATER;
141 else if (p[0] == sal_Unicode('='))
142 rEntry.eOp = SC_EQUAL;
146 if (bValid)
148 // Finally, the right-hand-side value in the 4th column.
149 *rEntry.pStr = pQueryRef->getString(3, nRow);
150 rEntry.bDoQuery = TRUE;
152 nIndex++;
153 nRow++;
155 while (bValid && (nRow < nRows) /* && (nIndex < MAXQUERY) */ );
156 return bValid;
159 bool lcl_createExcelQuery(
160 ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
162 bool bValid = true;
163 SCCOL nCols = pQueryRef->getColSize();
164 SCROW nRows = pQueryRef->getRowSize();
165 vector<SCCOL> aFields(nCols);
166 SCCOL nCol = 0;
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;
173 else
174 bValid = false;
175 ++nCol;
178 if (bValid)
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");
190 nVisible = 0;
193 SCSIZE nNewEntries = nVisible;
194 pParam->Resize( nNewEntries );
196 SCSIZE nIndex = 0;
197 SCROW nRow = 1;
198 String aCellStr;
199 while (nRow < nRows)
201 nCol = 0;
202 while (nCol < nCols)
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);
212 nIndex++;
213 if (nIndex < nNewEntries)
214 pParam->GetEntry(nIndex).eConnect = SC_AND;
216 else
217 bValid = FALSE;
219 nCol++;
221 nRow++;
222 if (nIndex < nNewEntries)
223 pParam->GetEntry(nIndex).eConnect = SC_OR;
226 return bValid;
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
239 if (!bValid)
240 bValid = lcl_createExcelQuery(pParam, pDBRef, pQueryRef);
242 nCount = pParam->GetEntryCount();
243 if (bValid)
245 // bQueryByString muss gesetzt sein
246 for (SCSIZE i = 0; i < nCount; ++i)
247 pParam->GetEntry(i).bQueryByString = true;
249 else
251 // nix
252 for (SCSIZE i = 0; i < nCount; ++i)
253 pParam->GetEntry(i).Clear();
255 return bValid;
260 // ============================================================================
262 ScDBRangeBase::ScDBRangeBase(ScDocument* pDoc, RefType eType) :
263 mpDoc(pDoc), meType(eType)
267 ScDBRangeBase::~ScDBRangeBase()
271 ScDBRangeBase::RefType ScDBRangeBase::getType() const
273 return meType;
276 bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const
278 if (!pDBRef)
279 return false;
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
297 return mpDoc;
300 // ============================================================================
302 ScDBInternalRange::ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange) :
303 ScDBRangeBase(pDoc, INTERNAL), maRange(rRange)
307 ScDBInternalRange::~ScDBInternalRange()
311 const ScRange& ScDBInternalRange::getRange() const
313 return maRange;
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();
330 if (nRows <= 1)
331 return 0;
333 return (nRows-1)*nCols;
336 OUString ScDBInternalRange::getString(SCCOL nCol, SCROW nRow) const
338 String aStr;
339 const ScAddress& s = maRange.aStart;
340 getDoc()->GetString(s.Col() + nCol, s.Row() + nRow, maRange.aStart.Tab(), aStr);
341 return 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) )
359 return nDBCol1;
361 return Min(nDBCol2, static_cast<SCCOL>(nDBCol1 + nIndex - 1));
364 sal_uInt16 ScDBInternalRange::getCellString(OUString& rStr, ScBaseCell* pCell) const
366 sal_uInt16 nErr = 0;
367 String aStr;
368 if (pCell)
370 SvNumberFormatter* pFormatter = getDoc()->GetFormatTable();
371 switch (pCell->GetCellType())
373 case CELLTYPE_STRING:
374 ((ScStringCell*) pCell)->GetString(aStr);
375 break;
376 case CELLTYPE_EDIT:
377 ((ScEditCell*) pCell)->GetString(aStr);
378 break;
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(
387 NUMBERFORMAT_NUMBER,
388 ScGlobal::eLnge);
389 pFormatter->GetInputLineString(fVal, nIndex, aStr);
391 else
392 pFCell->GetString(aStr);
394 break;
395 case CELLTYPE_VALUE:
397 double fVal = ((ScValueCell*) pCell)->GetValue();
398 ULONG nIndex = pFormatter->GetStandardFormat(
399 NUMBERFORMAT_NUMBER,
400 ScGlobal::eLnge);
401 pFormatter->GetInputLineString(fVal, nIndex, aStr);
403 break;
404 default:
408 rStr = aStr;
409 return nErr;
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;
417 lcl_toUpper(aUpper);
419 SCCOL nDBCol1 = s.Col();
420 SCROW nDBRow1 = s.Row();
421 SCTAB nDBTab1 = s.Tab();
422 SCCOL nDBCol2 = e.Col();
424 SCCOL nField = nDBCol1;
425 BOOL bFound = TRUE;
427 bFound = FALSE;
428 OUString aCellStr;
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 );
434 if (pErr)
435 *pErr = nErr;
436 lcl_toUpper(aCellStr);
437 bFound = ScGlobal::GetpTransliteration()->isEqual(aCellStr, aUpper);
438 if (!bFound)
439 aLook.IncCol();
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))
463 return NULL;
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)
478 SCSIZE nC, nR;
479 mpMatrix->GetDimensions(nC, nR);
480 mnCols = nC;
481 mnRows = nR;
484 ScDBExternalRange::~ScDBExternalRange()
488 SCCOL ScDBExternalRange::getColSize() const
490 return mnCols;
493 SCROW ScDBExternalRange::getRowSize() const
495 return mnRows;
498 SCSIZE ScDBExternalRange::getVisibleDataCellCount() const
500 SCCOL nCols = getColSize();
501 SCROW nRows = getRowSize();
502 if (nRows <= 1)
503 return 0;
505 return (nRows-1)*nCols;
508 OUString ScDBExternalRange::getString(SCCOL nCol, SCROW nRow) const
510 if (nCol >= mnCols || nRow >= mnRows)
511 return OUString();
513 return mpMatrix->GetString(nCol, nRow);
516 SCCOL ScDBExternalRange::getFirstFieldColumn() const
518 return 0;
521 SCCOL ScDBExternalRange::findFieldColumn(SCCOL nIndex) const
523 if (nIndex < 1)
524 // 1st field
525 return 0;
527 if (nIndex > mnCols)
528 // last field
529 return mnCols - 1;
531 return nIndex - 1;
534 SCCOL ScDBExternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
536 if (pErr)
537 pErr = 0;
539 OUString aUpper = rStr;
540 lcl_toUpper(aUpper);
541 for (SCCOL i = 0; i < mnCols; ++i)
543 OUString aUpperVal = mpMatrix->GetString(i, 0);
544 lcl_toUpper(aUpperVal);
545 if (aUpper.equals(aUpperVal))
546 return i;
548 return -1;
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))
559 return NULL;
561 return pParam.release();
564 bool ScDBExternalRange::isRangeEqual(const ScRange& /*rRange*/) const
566 return false;