Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2008 by Sun Microsystems, Inc.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "doubleref.hxx"
30 : : #include "cell.hxx"
31 : : #include "global.hxx"
32 : : #include "document.hxx"
33 : : #include "queryparam.hxx"
34 : : #include "queryentry.hxx"
35 : : #include "globstr.hrc"
36 : :
37 : : #include <memory>
38 : : #include <vector>
39 : :
40 : : using ::rtl::OUString;
41 : : using ::std::auto_ptr;
42 : : using ::std::vector;
43 : :
44 : : namespace {
45 : :
46 : 216 : void lcl_uppercase(OUString& rStr)
47 : : {
48 [ + - ]: 216 : rStr = ScGlobal::pCharClass->uppercase(rStr.trim());
49 : 216 : }
50 : :
51 : 24 : bool lcl_createStarQuery(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
52 : : {
53 : : // A valid StarQuery must be at least 4 columns wide. To be precise it
54 : : // should be exactly 4 columns ...
55 : : // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
56 : : // column Excel style query range immediately left to itself would result
57 : : // in a circular reference when the field name or operator or value (first
58 : : // to third query range column) is obtained (#i58354#). Furthermore, if the
59 : : // range wasn't sufficiently specified data changes wouldn't flag formula
60 : : // cells for recalculation.
61 : :
62 [ + - ][ + - ]: 24 : if (pQueryRef->getColSize() < 4)
63 : 24 : return false;
64 : :
65 : : sal_Bool bValid;
66 : 0 : OUString aCellStr;
67 : 0 : SCSIZE nIndex = 0;
68 : 0 : SCROW nRow = 0;
69 [ # # ]: 0 : SCROW nRows = pDBRef->getRowSize();
70 : 0 : SCSIZE nNewEntries = static_cast<SCSIZE>(nRows);
71 [ # # ]: 0 : pParam->Resize(nNewEntries);
72 : :
73 [ # # ][ # # ]: 0 : do
[ # # ]
74 : : {
75 [ # # ]: 0 : ScQueryEntry& rEntry = pParam->GetEntry(nIndex);
76 : :
77 : 0 : bValid = false;
78 : :
79 [ # # ]: 0 : if (nIndex > 0)
80 : : {
81 : : // For all entries after the first one, check the and/or connector in the first column.
82 [ # # ]: 0 : aCellStr = pQueryRef->getString(0, nRow);
83 [ # # ]: 0 : lcl_uppercase(aCellStr);
84 [ # # ][ # # ]: 0 : if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_UND)) )
[ # # ]
85 : : {
86 : 0 : rEntry.eConnect = SC_AND;
87 : 0 : bValid = sal_True;
88 : : }
89 [ # # ][ # # ]: 0 : else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) )
[ # # ]
90 : : {
91 : 0 : rEntry.eConnect = SC_OR;
92 : 0 : bValid = sal_True;
93 : : }
94 : : }
95 : :
96 [ # # ][ # # ]: 0 : if ((nIndex < 1) || bValid)
97 : : {
98 : : // field name in the 2nd column.
99 [ # # ]: 0 : aCellStr = pQueryRef->getString(1, nRow);
100 [ # # ]: 0 : SCCOL nField = pDBRef->findFieldColumn(aCellStr); // TODO: must be case insensitive comparison.
101 [ # # ]: 0 : if (ValidCol(nField))
102 : : {
103 : 0 : rEntry.nField = nField;
104 : 0 : bValid = true;
105 : : }
106 : : else
107 : 0 : bValid = false;
108 : : }
109 : :
110 [ # # ]: 0 : if (bValid)
111 : : {
112 : : // equality, non-equality operator in the 3rd column.
113 [ # # ]: 0 : aCellStr = pQueryRef->getString(2, nRow);
114 [ # # ]: 0 : lcl_uppercase(aCellStr);
115 : 0 : const sal_Unicode* p = aCellStr.getStr();
116 [ # # ]: 0 : if (p[0] == sal_Unicode('<'))
117 : : {
118 [ # # ]: 0 : if (p[1] == sal_Unicode('>'))
119 : 0 : rEntry.eOp = SC_NOT_EQUAL;
120 [ # # ]: 0 : else if (p[1] == sal_Unicode('='))
121 : 0 : rEntry.eOp = SC_LESS_EQUAL;
122 : : else
123 : 0 : rEntry.eOp = SC_LESS;
124 : : }
125 [ # # ]: 0 : else if (p[0] == sal_Unicode('>'))
126 : : {
127 [ # # ]: 0 : if (p[1] == sal_Unicode('='))
128 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
129 : : else
130 : 0 : rEntry.eOp = SC_GREATER;
131 : : }
132 [ # # ]: 0 : else if (p[0] == sal_Unicode('='))
133 : 0 : rEntry.eOp = SC_EQUAL;
134 : :
135 : : }
136 : :
137 [ # # ]: 0 : if (bValid)
138 : : {
139 : : // Finally, the right-hand-side value in the 4th column.
140 [ # # ][ # # ]: 0 : rEntry.GetQueryItem().maString = pQueryRef->getString(3, nRow);
141 : 0 : rEntry.bDoQuery = true;
142 : : }
143 : 0 : nIndex++;
144 : 0 : nRow++;
145 : : }
146 : : while (bValid && (nRow < nRows) /* && (nIndex < MAXQUERY) */ );
147 : 24 : return bValid;
148 : : }
149 : :
150 : 24 : bool lcl_createExcelQuery(
151 : : ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
152 : : {
153 : 24 : bool bValid = true;
154 [ + - ]: 24 : SCCOL nCols = pQueryRef->getColSize();
155 [ + - ]: 24 : SCROW nRows = pQueryRef->getRowSize();
156 [ + - ]: 24 : vector<SCCOL> aFields(nCols);
157 : 24 : SCCOL nCol = 0;
158 [ + - ][ + + ]: 96 : while (bValid && (nCol < nCols))
[ + + ]
159 : : {
160 [ + - ]: 72 : OUString aQueryStr = pQueryRef->getString(nCol, 0);
161 [ + - ]: 72 : SCCOL nField = pDBRef->findFieldColumn(aQueryStr);
162 [ + - ]: 72 : if (ValidCol(nField))
163 [ + - ]: 72 : aFields[nCol] = nField;
164 : : else
165 : 0 : bValid = false;
166 : 72 : ++nCol;
167 : 72 : }
168 : :
169 [ + - ]: 24 : if (bValid)
170 : : {
171 : : // Count the number of visible cells (excluding the header row). Each
172 : : // visible cell corresponds with a single query.
173 [ + - ]: 24 : SCSIZE nVisible = pQueryRef->getVisibleDataCellCount();
174 [ - + ]: 24 : if ( nVisible > SCSIZE_MAX / sizeof(void*) )
175 : : {
176 : : OSL_FAIL("zu viele Filterkritierien");
177 : 0 : nVisible = 0;
178 : : }
179 : :
180 : 24 : SCSIZE nNewEntries = nVisible;
181 [ + - ]: 24 : pParam->Resize( nNewEntries );
182 : :
183 : 24 : SCSIZE nIndex = 0;
184 : 24 : SCROW nRow = 1;
185 [ + - ]: 24 : String aCellStr;
186 [ + + ]: 48 : while (nRow < nRows)
187 : : {
188 : 24 : nCol = 0;
189 [ + + ]: 96 : while (nCol < nCols)
190 : : {
191 [ + - ][ + - ]: 72 : aCellStr = pQueryRef->getString(nCol, nRow);
192 [ + - ][ + - ]: 72 : aCellStr = ScGlobal::pCharClass->uppercase( aCellStr );
[ + - ]
193 [ + + ]: 72 : if (aCellStr.Len() > 0)
194 : : {
195 [ + - ]: 36 : if (nIndex < nNewEntries)
196 : : {
197 [ + - ][ + - ]: 36 : pParam->GetEntry(nIndex).nField = aFields[nCol];
198 [ + - ][ + - ]: 36 : pParam->FillInExcelSyntax(rtl::OUString(aCellStr), nIndex);
199 : 36 : nIndex++;
200 [ + - ]: 36 : if (nIndex < nNewEntries)
201 [ + - ]: 36 : pParam->GetEntry(nIndex).eConnect = SC_AND;
202 : : }
203 : : else
204 : 0 : bValid = false;
205 : : }
206 : 72 : nCol++;
207 : : }
208 : 24 : nRow++;
209 [ + - ]: 24 : if (nIndex < nNewEntries)
210 [ + - ]: 24 : pParam->GetEntry(nIndex).eConnect = SC_OR;
211 [ + - ]: 24 : }
212 : : }
213 : 24 : return bValid;
214 : : }
215 : :
216 : 24 : bool lcl_fillQueryEntries(
217 : : ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef)
218 : : {
219 : 24 : SCSIZE nCount = pParam->GetEntryCount();
220 [ + + ]: 216 : for (SCSIZE i = 0; i < nCount; ++i)
221 : 192 : pParam->GetEntry(i).Clear();
222 : :
223 : : // Standard QueryTabelle
224 : 24 : bool bValid = lcl_createStarQuery(pParam, pDBRef, pQueryRef);
225 : : // Excel QueryTabelle
226 [ + - ]: 24 : if (!bValid)
227 : 24 : bValid = lcl_createExcelQuery(pParam, pDBRef, pQueryRef);
228 : :
229 : 24 : nCount = pParam->GetEntryCount();
230 [ + - ]: 24 : if (bValid)
231 : : {
232 : : // bQueryByString muss gesetzt sein
233 [ + + ]: 216 : for (SCSIZE i = 0; i < nCount; ++i)
234 : 192 : pParam->GetEntry(i).GetQueryItem().meType = ScQueryEntry::ByString;
235 : : }
236 : : else
237 : : {
238 : : // nix
239 [ # # ]: 0 : for (SCSIZE i = 0; i < nCount; ++i)
240 : 0 : pParam->GetEntry(i).Clear();
241 : : }
242 : 24 : return bValid;
243 : : }
244 : :
245 : : }
246 : :
247 : : // ============================================================================
248 : :
249 : 48 : ScDBRangeBase::ScDBRangeBase(ScDocument* pDoc, RefType eType) :
250 : 48 : mpDoc(pDoc), meType(eType)
251 : : {
252 : 48 : }
253 : :
254 : 48 : ScDBRangeBase::~ScDBRangeBase()
255 : : {
256 [ - + ]: 48 : }
257 : :
258 : 24 : bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const
259 : : {
260 [ - + ]: 24 : if (!pDBRef)
261 : 0 : return false;
262 : :
263 : 24 : return lcl_fillQueryEntries(pParam, pDBRef, this);
264 : : }
265 : :
266 : 24 : void ScDBRangeBase::fillQueryOptions(ScQueryParamBase* pParam)
267 : : {
268 : 24 : pParam->bHasHeader = true;
269 : 24 : pParam->bByRow = true;
270 : 24 : pParam->bInplace = true;
271 : 24 : pParam->bCaseSens = false;
272 : 24 : pParam->bRegExp = false;
273 : 24 : pParam->bDuplicate = true;
274 : 24 : }
275 : :
276 : 288 : ScDocument* ScDBRangeBase::getDoc() const
277 : : {
278 : 288 : return mpDoc;
279 : : }
280 : :
281 : : // ============================================================================
282 : :
283 : 48 : ScDBInternalRange::ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange) :
284 : 48 : ScDBRangeBase(pDoc, INTERNAL), maRange(rRange)
285 : : {
286 : 48 : }
287 : :
288 : 48 : ScDBInternalRange::~ScDBInternalRange()
289 : : {
290 [ - + ]: 96 : }
291 : :
292 : 36 : const ScRange& ScDBInternalRange::getRange() const
293 : : {
294 : 36 : return maRange;
295 : : }
296 : :
297 : 72 : SCCOL ScDBInternalRange::getColSize() const
298 : : {
299 : 72 : return maRange.aEnd.Col() - maRange.aStart.Col() + 1;
300 : : }
301 : :
302 : 48 : SCROW ScDBInternalRange::getRowSize() const
303 : : {
304 : 48 : return maRange.aEnd.Row() - maRange.aStart.Row() + 1;
305 : : }
306 : :
307 : 24 : SCSIZE ScDBInternalRange::getVisibleDataCellCount() const
308 : : {
309 : 24 : SCCOL nCols = getColSize();
310 : 24 : SCROW nRows = getRowSize();
311 [ - + ]: 24 : if (nRows <= 1)
312 : 0 : return 0;
313 : :
314 : 24 : return (nRows-1)*nCols;
315 : : }
316 : :
317 : 144 : OUString ScDBInternalRange::getString(SCCOL nCol, SCROW nRow) const
318 : : {
319 : 144 : OUString aStr;
320 : 144 : const ScAddress& s = maRange.aStart;
321 : : // GetStringForFormula is not used here, to allow querying for date values.
322 [ + - ]: 144 : getDoc()->GetInputString(s.Col() + nCol, s.Row() + nRow, s.Tab(), aStr);
323 : 144 : return aStr;
324 : : }
325 : :
326 : 24 : SCCOL ScDBInternalRange::getFirstFieldColumn() const
327 : : {
328 : 24 : return getRange().aStart.Col();
329 : : }
330 : :
331 : 12 : SCCOL ScDBInternalRange::findFieldColumn(SCCOL nIndex) const
332 : : {
333 : 12 : const ScRange& rRange = getRange();
334 : 12 : const ScAddress& s = rRange.aStart;
335 : :
336 : 12 : SCCOL nDBCol1 = s.Col();
337 : :
338 : : // Don't handle out-of-bound condition here. We'll do that later.
339 : 12 : return nIndex + nDBCol1 - 1;
340 : : }
341 : :
342 : 72 : SCCOL ScDBInternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
343 : : {
344 : 72 : const ScAddress& s = maRange.aStart;
345 : 72 : const ScAddress& e = maRange.aEnd;
346 : 72 : OUString aUpper = rStr;
347 [ + - ]: 72 : lcl_uppercase(aUpper);
348 : :
349 : 72 : SCCOL nDBCol1 = s.Col();
350 : 72 : SCROW nDBRow1 = s.Row();
351 : 72 : SCTAB nDBTab1 = s.Tab();
352 : 72 : SCCOL nDBCol2 = e.Col();
353 : :
354 : 72 : SCCOL nField = nDBCol1;
355 : 72 : sal_Bool bFound = sal_True;
356 : :
357 : 72 : bFound = false;
358 : 72 : OUString aCellStr;
359 : 72 : ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 );
360 [ + + ][ + - ]: 216 : while (!bFound && (aLook.Col() <= nDBCol2))
[ + + ]
361 : : {
362 [ + - ]: 144 : sal_uInt16 nErr = getDoc()->GetStringForFormula( aLook, aCellStr );
363 [ - + ]: 144 : if (pErr)
364 : 0 : *pErr = nErr;
365 [ + - ]: 144 : lcl_uppercase(aCellStr);
366 [ + - ][ + - ]: 144 : bFound = ScGlobal::GetpTransliteration()->isEqual(aCellStr, aUpper);
[ + - ][ + - ]
[ + - ][ + - ]
367 [ + + ]: 144 : if (!bFound)
368 [ + - ]: 72 : aLook.IncCol();
369 : : }
370 : 72 : nField = aLook.Col();
371 : :
372 [ + - ]: 72 : return bFound ? nField : -1;
373 : : }
374 : :
375 : 24 : ScDBQueryParamBase* ScDBInternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
376 : : {
377 [ + - ][ + - ]: 24 : auto_ptr<ScDBQueryParamInternal> pParam(new ScDBQueryParamInternal);
378 : :
379 : : // Set the database range first.
380 : 24 : const ScAddress& s = maRange.aStart;
381 : 24 : const ScAddress& e = maRange.aEnd;
382 : 24 : pParam->nCol1 = s.Col();
383 : 24 : pParam->nRow1 = s.Row();
384 : 24 : pParam->nCol2 = e.Col();
385 : 24 : pParam->nRow2 = e.Row();
386 : 24 : pParam->nTab = s.Tab();
387 : :
388 : 24 : fillQueryOptions(pParam.get());
389 : :
390 : : // Now construct the query entries from the query range.
391 [ - + ][ + - ]: 24 : if (!pQueryRef->fillQueryEntries(pParam.get(), this))
392 : 0 : return NULL;
393 : :
394 [ + - ]: 24 : return pParam.release();
395 : : }
396 : :
397 : 0 : bool ScDBInternalRange::isRangeEqual(const ScRange& rRange) const
398 : : {
399 : 0 : return maRange == rRange;
400 : : }
401 : :
402 : : // ============================================================================
403 : :
404 : 0 : ScDBExternalRange::ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat) :
405 : 0 : ScDBRangeBase(pDoc, EXTERNAL), mpMatrix(pMat)
406 : : {
407 : : SCSIZE nC, nR;
408 [ # # ]: 0 : mpMatrix->GetDimensions(nC, nR);
409 : 0 : mnCols = static_cast<SCCOL>(nC);
410 : 0 : mnRows = static_cast<SCROW>(nR);
411 : 0 : }
412 : :
413 [ # # ]: 0 : ScDBExternalRange::~ScDBExternalRange()
414 : : {
415 [ # # ]: 0 : }
416 : :
417 : 0 : SCCOL ScDBExternalRange::getColSize() const
418 : : {
419 : 0 : return mnCols;
420 : : }
421 : :
422 : 0 : SCROW ScDBExternalRange::getRowSize() const
423 : : {
424 : 0 : return mnRows;
425 : : }
426 : :
427 : 0 : SCSIZE ScDBExternalRange::getVisibleDataCellCount() const
428 : : {
429 : 0 : SCCOL nCols = getColSize();
430 : 0 : SCROW nRows = getRowSize();
431 [ # # ]: 0 : if (nRows <= 1)
432 : 0 : return 0;
433 : :
434 : 0 : return (nRows-1)*nCols;
435 : : }
436 : :
437 : 0 : OUString ScDBExternalRange::getString(SCCOL nCol, SCROW nRow) const
438 : : {
439 [ # # ][ # # ]: 0 : if (nCol >= mnCols || nRow >= mnRows)
440 : 0 : return OUString();
441 : :
442 : 0 : return mpMatrix->GetString(nCol, nRow);
443 : : }
444 : :
445 : 0 : SCCOL ScDBExternalRange::getFirstFieldColumn() const
446 : : {
447 : 0 : return 0;
448 : : }
449 : :
450 : 0 : SCCOL ScDBExternalRange::findFieldColumn(SCCOL nIndex) const
451 : : {
452 : 0 : return nIndex - 1;
453 : : }
454 : :
455 : 0 : SCCOL ScDBExternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const
456 : : {
457 [ # # ]: 0 : if (pErr)
458 : 0 : pErr = 0;
459 : :
460 : 0 : OUString aUpper = rStr;
461 [ # # ]: 0 : lcl_uppercase(aUpper);
462 [ # # ]: 0 : for (SCCOL i = 0; i < mnCols; ++i)
463 : : {
464 [ # # ]: 0 : OUString aUpperVal = mpMatrix->GetString(i, 0);
465 [ # # ]: 0 : lcl_uppercase(aUpperVal);
466 [ # # ]: 0 : if (aUpper.equals(aUpperVal))
467 : 0 : return i;
468 [ # # ]: 0 : }
469 : 0 : return -1;
470 : : }
471 : :
472 : 0 : ScDBQueryParamBase* ScDBExternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const
473 : : {
474 [ # # ][ # # ]: 0 : auto_ptr<ScDBQueryParamMatrix> pParam(new ScDBQueryParamMatrix);
475 [ # # ]: 0 : pParam->mpMatrix = mpMatrix;
476 : 0 : fillQueryOptions(pParam.get());
477 : :
478 : : // Now construct the query entries from the query range.
479 [ # # ][ # # ]: 0 : if (!pQueryRef->fillQueryEntries(pParam.get(), this))
480 : 0 : return NULL;
481 : :
482 [ # # ]: 0 : return pParam.release();
483 : : }
484 : :
485 : 0 : bool ScDBExternalRange::isRangeEqual(const ScRange& /*rRange*/) const
486 : : {
487 : 0 : return false;
488 : : }
489 : :
490 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|