fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / tool / doubleref.cxx
blob4f4c523b47b397593c7998138a07aa2832b38e57
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 "doubleref.hxx"
21 #include "formulacell.hxx"
22 #include "global.hxx"
23 #include "document.hxx"
24 #include "queryparam.hxx"
25 #include "queryentry.hxx"
26 #include "globstr.hrc"
27 #include "scmatrix.hxx"
29 #include <svl/sharedstringpool.hxx>
30 #include <osl/diagnose.h>
32 #include <memory>
33 #include <vector>
35 using ::std::unique_ptr;
36 using ::std::vector;
38 namespace {
40 void lcl_uppercase(OUString& rStr)
42 rStr = ScGlobal::pCharClass->uppercase(rStr.trim());
45 bool lcl_createStarQuery(
46 svl::SharedStringPool& rPool, ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
48 // A valid StarQuery must be at least 4 columns wide. To be precise it
49 // should be exactly 4 columns ...
50 // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
51 // column Excel style query range immediately left to itself would result
52 // in a circular reference when the field name or operator or value (first
53 // to third query range column) is obtained (#i58354#). Furthermore, if the
54 // range wasn't sufficiently specified data changes wouldn't flag formula
55 // cells for recalculation.
57 if (pQueryRef->getColSize() < 4)
58 return false;
60 bool bValid;
61 OUString aCellStr;
62 SCSIZE nIndex = 0;
63 SCROW nRow = 0;
64 SCROW nRows = pDBRef->getRowSize();
65 SCSIZE nNewEntries = static_cast<SCSIZE>(nRows);
66 pParam->Resize(nNewEntries);
70 ScQueryEntry& rEntry = pParam->GetEntry(nIndex);
72 bValid = false;
74 if (nIndex > 0)
76 // For all entries after the first one, check the and/or connector in the first column.
77 aCellStr = pQueryRef->getString(0, nRow);
78 lcl_uppercase(aCellStr);
79 if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_UND)) )
81 rEntry.eConnect = SC_AND;
82 bValid = true;
84 else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) )
86 rEntry.eConnect = SC_OR;
87 bValid = true;
91 if ((nIndex < 1) || bValid)
93 // field name in the 2nd column.
94 aCellStr = pQueryRef->getString(1, nRow);
95 SCCOL nField = pDBRef->findFieldColumn(aCellStr); // TODO: must be case insensitive comparison.
96 if (ValidCol(nField))
98 rEntry.nField = nField;
99 bValid = true;
101 else
102 bValid = false;
105 if (bValid)
107 // equality, non-equality operator in the 3rd column.
108 aCellStr = pQueryRef->getString(2, nRow);
109 lcl_uppercase(aCellStr);
110 const sal_Unicode* p = aCellStr.getStr();
111 if (p[0] == '<')
113 if (p[1] == '>')
114 rEntry.eOp = SC_NOT_EQUAL;
115 else if (p[1] == '=')
116 rEntry.eOp = SC_LESS_EQUAL;
117 else
118 rEntry.eOp = SC_LESS;
120 else if (p[0] == '>')
122 if (p[1] == '=')
123 rEntry.eOp = SC_GREATER_EQUAL;
124 else
125 rEntry.eOp = SC_GREATER;
127 else if (p[0] == '=')
128 rEntry.eOp = SC_EQUAL;
132 if (bValid)
134 // Finally, the right-hand-side value in the 4th column.
135 rEntry.GetQueryItem().maString =
136 rPool.intern(pQueryRef->getString(3, nRow));
137 rEntry.bDoQuery = true;
139 nIndex++;
140 nRow++;
142 while (bValid && (nRow < nRows) /* && (nIndex < MAXQUERY) */ );
143 return bValid;
146 bool lcl_createExcelQuery(
147 svl::SharedStringPool& rPool, ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
149 bool bValid = true;
150 SCCOL nCols = pQueryRef->getColSize();
151 SCROW nRows = pQueryRef->getRowSize();
152 vector<SCCOL> aFields(nCols);
153 SCCOL nCol = 0;
154 while (bValid && (nCol < nCols))
156 OUString aQueryStr = pQueryRef->getString(nCol, 0);
157 SCCOL nField = pDBRef->findFieldColumn(aQueryStr);
158 if (ValidCol(nField))
159 aFields[nCol] = nField;
160 else
161 bValid = false;
162 ++nCol;
165 if (bValid)
167 // Count the number of visible cells (excluding the header row). Each
168 // visible cell corresponds with a single query.
169 SCSIZE nVisible = pQueryRef->getVisibleDataCellCount();
170 if ( nVisible > SCSIZE_MAX / sizeof(void*) )
172 OSL_FAIL("too many filter criteria");
173 nVisible = 0;
176 SCSIZE nNewEntries = nVisible;
177 pParam->Resize( nNewEntries );
179 SCSIZE nIndex = 0;
180 SCROW nRow = 1;
181 OUString aCellStr;
182 while (nRow < nRows)
184 nCol = 0;
185 while (nCol < nCols)
187 aCellStr = pQueryRef->getString(nCol, nRow);
188 aCellStr = ScGlobal::pCharClass->uppercase( aCellStr );
189 if (!aCellStr.isEmpty())
191 if (nIndex < nNewEntries)
193 pParam->GetEntry(nIndex).nField = aFields[nCol];
194 pParam->FillInExcelSyntax(rPool, aCellStr, nIndex, NULL);
195 nIndex++;
196 if (nIndex < nNewEntries)
197 pParam->GetEntry(nIndex).eConnect = SC_AND;
199 else
200 bValid = false;
202 nCol++;
204 nRow++;
205 if (nIndex < nNewEntries)
206 pParam->GetEntry(nIndex).eConnect = SC_OR;
209 return bValid;
212 bool lcl_fillQueryEntries(
213 svl::SharedStringPool& rPool, ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
215 SCSIZE nCount = pParam->GetEntryCount();
216 for (SCSIZE i = 0; i < nCount; ++i)
217 pParam->GetEntry(i).Clear();
219 // Standard QueryTabelle
220 bool bValid = lcl_createStarQuery(rPool, pParam, pDBRef, pQueryRef);
221 // Excel QueryTabelle
222 if (!bValid)
223 bValid = lcl_createExcelQuery(rPool, pParam, pDBRef, pQueryRef);
225 nCount = pParam->GetEntryCount();
226 if (bValid)
228 // bQueryByString muss gesetzt sein
229 for (SCSIZE i = 0; i < nCount; ++i)
230 pParam->GetEntry(i).GetQueryItem().meType = ScQueryEntry::ByString;
232 else
234 // nix
235 for (SCSIZE i = 0; i < nCount; ++i)
236 pParam->GetEntry(i).Clear();
238 return bValid;
243 ScDBRangeBase::ScDBRangeBase(ScDocument* pDoc, RefType eType) :
244 mpDoc(pDoc), meType(eType)
248 ScDBRangeBase::~ScDBRangeBase()
252 bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const
254 if (!pDBRef)
255 return false;
257 return lcl_fillQueryEntries(getDoc()->GetSharedStringPool(), pParam, pDBRef, this);
260 void ScDBRangeBase::fillQueryOptions(ScQueryParamBase* pParam)
262 pParam->bHasHeader = true;
263 pParam->bByRow = true;
264 pParam->bInplace = true;
265 pParam->bCaseSens = false;
266 pParam->bRegExp = false;
267 pParam->bDuplicate = true;
270 ScDBInternalRange::ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange) :
271 ScDBRangeBase(pDoc, INTERNAL), maRange(rRange)
275 ScDBInternalRange::~ScDBInternalRange()
279 SCCOL ScDBInternalRange::getColSize() const
281 return maRange.aEnd.Col() - maRange.aStart.Col() + 1;
284 SCROW ScDBInternalRange::getRowSize() const
286 return maRange.aEnd.Row() - maRange.aStart.Row() + 1;
289 SCSIZE ScDBInternalRange::getVisibleDataCellCount() const
291 SCCOL nCols = getColSize();
292 SCROW nRows = getRowSize();
293 if (nRows <= 1)
294 return 0;
296 return (nRows-1)*nCols;
299 OUString ScDBInternalRange::getString(SCCOL nCol, SCROW nRow) const
301 OUString aStr;
302 const ScAddress& s = maRange.aStart;
303 // #i109200# this is used in formula calculation, use GetInputString, not GetString
304 // (consistent with ScDBInternalRange::getCellString)
305 // GetStringForFormula is not used here, to allow querying for date values.
306 getDoc()->GetInputString(s.Col() + nCol, s.Row() + nRow, maRange.aStart.Tab(), aStr);
307 return aStr;
310 SCCOL ScDBInternalRange::getFirstFieldColumn() const
312 return getRange().aStart.Col();
315 SCCOL ScDBInternalRange::findFieldColumn(SCCOL nIndex) const
317 const ScRange& rRange = getRange();
318 const ScAddress& s = rRange.aStart;
320 SCCOL nDBCol1 = s.Col();
322 // Don't handle out-of-bound condition here. We'll do that later.
323 return nIndex + nDBCol1 - 1;
326 SCCOL ScDBInternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
328 const ScAddress& s = maRange.aStart;
329 const ScAddress& e = maRange.aEnd;
330 OUString aUpper = rStr;
331 lcl_uppercase(aUpper);
333 SCCOL nDBCol1 = s.Col();
334 SCROW nDBRow1 = s.Row();
335 SCTAB nDBTab1 = s.Tab();
336 SCCOL nDBCol2 = e.Col();
338 SCCOL nField = nDBCol1;
339 bool bFound = false;
341 OUString aCellStr;
342 ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 );
343 while (!bFound && (aLook.Col() <= nDBCol2))
345 sal_uInt16 nErr = getDoc()->GetStringForFormula( aLook, aCellStr );
346 if (pErr)
347 *pErr = nErr;
348 lcl_uppercase(aCellStr);
349 bFound = ScGlobal::GetpTransliteration()->isEqual(aCellStr, aUpper);
350 if (!bFound)
351 aLook.IncCol();
353 nField = aLook.Col();
355 return bFound ? nField : -1;
358 ScDBQueryParamBase* ScDBInternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
360 unique_ptr<ScDBQueryParamInternal> pParam(new ScDBQueryParamInternal);
362 // Set the database range first.
363 const ScAddress& s = maRange.aStart;
364 const ScAddress& e = maRange.aEnd;
365 pParam->nCol1 = s.Col();
366 pParam->nRow1 = s.Row();
367 pParam->nCol2 = e.Col();
368 pParam->nRow2 = e.Row();
369 pParam->nTab = s.Tab();
371 fillQueryOptions(pParam.get());
373 // Now construct the query entries from the query range.
374 if (!pQueryRef->fillQueryEntries(pParam.get(), this))
375 return NULL;
377 return pParam.release();
380 bool ScDBInternalRange::isRangeEqual(const ScRange& rRange) const
382 return maRange == rRange;
385 ScDBExternalRange::ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat) :
386 ScDBRangeBase(pDoc, EXTERNAL), mpMatrix(pMat)
388 SCSIZE nC, nR;
389 mpMatrix->GetDimensions(nC, nR);
390 mnCols = static_cast<SCCOL>(nC);
391 mnRows = static_cast<SCROW>(nR);
394 ScDBExternalRange::~ScDBExternalRange()
398 SCCOL ScDBExternalRange::getColSize() const
400 return mnCols;
403 SCROW ScDBExternalRange::getRowSize() const
405 return mnRows;
408 SCSIZE ScDBExternalRange::getVisibleDataCellCount() const
410 SCCOL nCols = getColSize();
411 SCROW nRows = getRowSize();
412 if (nRows <= 1)
413 return 0;
415 return (nRows-1)*nCols;
418 OUString ScDBExternalRange::getString(SCCOL nCol, SCROW nRow) const
420 if (nCol >= mnCols || nRow >= mnRows)
421 return OUString();
423 return mpMatrix->GetString(nCol, nRow).getString();
426 SCCOL ScDBExternalRange::getFirstFieldColumn() const
428 return 0;
431 SCCOL ScDBExternalRange::findFieldColumn(SCCOL nIndex) const
433 return nIndex - 1;
436 SCCOL ScDBExternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
438 if (pErr)
439 pErr = 0;
441 OUString aUpper = rStr;
442 lcl_uppercase(aUpper);
443 for (SCCOL i = 0; i < mnCols; ++i)
445 OUString aUpperVal = mpMatrix->GetString(i, 0).getString();
446 lcl_uppercase(aUpperVal);
447 if (aUpper.equals(aUpperVal))
448 return i;
450 return -1;
453 ScDBQueryParamBase* ScDBExternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
455 unique_ptr<ScDBQueryParamMatrix> pParam(new ScDBQueryParamMatrix);
456 pParam->mpMatrix = mpMatrix;
457 fillQueryOptions(pParam.get());
459 // Now construct the query entries from the query range.
460 if (!pQueryRef->fillQueryEntries(pParam.get(), this))
461 return NULL;
463 return pParam.release();
466 bool ScDBExternalRange::isRangeEqual(const ScRange& /*rRange*/) const
468 return false;
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */