1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 // MARKER(update_precomp.py): autogen include statement, do not remove 28 #include "precompiled_sc.hxx" 29 30 #include "dpcachetable.hxx" 31 #include "document.hxx" 32 #include "address.hxx" 33 #include "cell.hxx" 34 #include "dptabdat.hxx" 35 #include "dptabsrc.hxx" 36 #include "dpobject.hxx" 37 #include "queryparam.hxx" 38 39 #include <com/sun/star/i18n/LocaleDataItem.hpp> 40 #include <com/sun/star/sdbc/DataType.hpp> 41 #include <com/sun/star/sdbc/XRow.hpp> 42 #include <com/sun/star/sdbc/XRowSet.hpp> 43 #include <com/sun/star/sdbc/XResultSetMetaData.hpp> 44 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> 45 #include <com/sun/star/util/Date.hpp> 46 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> 47 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> 48 49 #include <memory> 50 51 using namespace ::com::sun::star; 52 53 using ::rtl::OUString; 54 using ::std::vector; 55 using ::std::pair; 56 using ::std::hash_map; 57 using ::std::hash_set; 58 using ::std::auto_ptr; 59 using ::com::sun::star::i18n::LocaleDataItem; 60 using ::com::sun::star::uno::Exception; 61 using ::com::sun::star::uno::Reference; 62 using ::com::sun::star::uno::Sequence; 63 using ::com::sun::star::uno::Any; 64 using ::com::sun::star::uno::UNO_QUERY; 65 using ::com::sun::star::uno::UNO_QUERY_THROW; 66 using ::com::sun::star::sheet::DataPilotFieldFilter; 67 68 69 static sal_Bool lcl_HasQueryEntry( const ScQueryParam& rParam ) 70 { 71 return rParam.GetEntryCount() > 0 && 72 rParam.GetEntry(0).bDoQuery; 73 } 74 75 // ---------------------------------------------------------------------------- 76 77 ScDPCacheTable::FilterItem::FilterItem() : 78 mfValue(0.0), 79 mbHasValue(false) 80 { 81 } 82 bool ScDPCacheTable::FilterItem::match( const ScDPItemData& rCellData ) const 83 { 84 if (rCellData.GetString()!= maString && 85 (!rCellData.IsValue()|| rCellData.GetValue()!= mfValue)) 86 return false; 87 return true; 88 } 89 // ---------------------------------------------------------------------------- 90 91 ScDPCacheTable::SingleFilter::SingleFilter(String aString, double fValue, bool bHasValue) 92 { 93 maItem.maString = aString; 94 maItem.mfValue = fValue; 95 maItem.mbHasValue = bHasValue; 96 } 97 98 bool ScDPCacheTable::SingleFilter::match( const ScDPItemData& rCellData ) const 99 { 100 return maItem.match(rCellData); 101 } 102 103 const String ScDPCacheTable::SingleFilter::getMatchString() 104 { 105 return maItem.maString; 106 } 107 108 double ScDPCacheTable::SingleFilter::getMatchValue() const 109 { 110 return maItem.mfValue; 111 } 112 113 bool ScDPCacheTable::SingleFilter::hasValue() const 114 { 115 return maItem.mbHasValue; 116 } 117 118 // ---------------------------------------------------------------------------- 119 120 ScDPCacheTable::GroupFilter::GroupFilter() 121 { 122 } 123 124 bool ScDPCacheTable::GroupFilter::match( const ScDPItemData& rCellData ) const 125 { 126 vector<FilterItem>::const_iterator itrEnd = maItems.end(); 127 for (vector<FilterItem>::const_iterator itr = maItems.begin(); itr != itrEnd; ++itr) 128 { 129 bool bMatch = itr->match( rCellData); 130 if (bMatch) 131 return true; 132 } 133 return false; 134 } 135 136 void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue) 137 { 138 FilterItem aItem; 139 aItem.maString = rStr; 140 aItem.mfValue = fVal; 141 aItem.mbHasValue = bHasValue; 142 maItems.push_back(aItem); 143 } 144 145 size_t ScDPCacheTable::GroupFilter::getMatchItemCount() const 146 { 147 return maItems.size(); 148 } 149 150 // ---------------------------------------------------------------------------- 151 152 ScDPCacheTable::Criterion::Criterion() : 153 mnFieldIndex(-1), 154 mpFilter(static_cast<FilterBase*>(NULL)) 155 { 156 } 157 158 // ---------------------------------------------------------------------------- 159 160 ScDPCacheTable::ScDPCacheTable( ScDocument* pDoc,long nId ) : 161 mpCache( NULL ), 162 mpNoneCache( NULL ) 163 { 164 if ( nId >= 0 ) 165 mpCache = pDoc->GetDPObjectCache( nId ); 166 else 167 { //create a temp cache object 168 InitNoneCache( NULL ); 169 } 170 } 171 172 ScDPCacheTable::~ScDPCacheTable() 173 { 174 } 175 176 sal_Int32 ScDPCacheTable::getRowSize() const 177 { 178 return GetCache()->GetRowCount(); 179 } 180 181 sal_Int32 ScDPCacheTable::getColSize() const 182 { 183 return GetCache()->GetColumnCount(); 184 } 185 186 void ScDPCacheTable::fillTable( const ScQueryParam& rQuery, sal_Bool* pSpecial, 187 bool bIgnoreEmptyRows, bool bRepeatIfEmpty ) 188 { 189 if ( mpCache == NULL ) 190 InitNoneCache( NULL ); 191 //check cache 192 const SCROW nRowCount = getRowSize(); 193 const SCCOL nColCount = (SCCOL) getColSize(); 194 if ( nRowCount <= 0 || nColCount <= 0) 195 return; 196 197 maRowsVisible.clear(); 198 maRowsVisible.reserve(nRowCount); 199 200 201 // Initialize field entries container. 202 maFieldEntries.clear(); 203 maFieldEntries.reserve(nColCount); 204 205 // Data rows 206 for (SCCOL nCol = 0; nCol < nColCount; ++nCol) 207 { 208 SCROW nMemCount = GetCache()->GetDimMemberCount( nCol ); 209 if ( nMemCount ) 210 { 211 std::vector< SCROW > pAdded( nMemCount, -1 ); 212 213 for (SCROW nRow = 0; nRow < nRowCount; ++nRow ) 214 { 215 SCROW nIndex = GetCache()->GetItemDataId( nCol, nRow, bRepeatIfEmpty ); 216 SCROW nOrder = GetCache()->GetOrder( nCol, nIndex ); 217 218 if ( nCol == 0 ) 219 maRowsVisible.push_back(false); 220 221 if ( lcl_HasQueryEntry(rQuery) && 222 !GetCache()->ValidQuery( nRow , rQuery, pSpecial ) ) 223 continue; 224 if ( bIgnoreEmptyRows && GetCache()->IsRowEmpty( nRow ) ) 225 continue; 226 // Insert a new row into cache table. 227 if ( nCol == 0 ) 228 maRowsVisible.back() = true; 229 230 pAdded[nOrder] = nIndex; 231 } 232 maFieldEntries.push_back( vector<SCROW>() ); 233 for ( SCROW nRow = 0; nRow < nMemCount; nRow++ ) 234 { 235 if ( pAdded[nRow] != -1 ) 236 maFieldEntries.back().push_back( pAdded[nRow] ); 237 } 238 } 239 } 240 } 241 242 void ScDPCacheTable::fillTable() 243 { 244 if ( mpCache == NULL ) 245 InitNoneCache( NULL ); 246 //check cache 247 const SCROW nRowCount = getRowSize(); 248 const SCCOL nColCount = (SCCOL) getColSize(); 249 if ( nRowCount <= 0 || nColCount <= 0) 250 return; 251 252 maRowsVisible.clear(); 253 maRowsVisible.reserve(nRowCount); 254 255 256 // Initialize field entries container. 257 maFieldEntries.clear(); 258 maFieldEntries.reserve(nColCount); 259 260 // Data rows 261 for (SCCOL nCol = 0; nCol < nColCount; ++nCol) 262 { 263 SCROW nMemCount = GetCache()->GetDimMemberCount( nCol ); 264 if ( nMemCount ) 265 { 266 std::vector< SCROW > pAdded( nMemCount, -1 ); 267 268 for (SCROW nRow = 0; nRow < nRowCount; ++nRow ) 269 { 270 SCROW nIndex = GetCache()->GetItemDataId( nCol, nRow, false ); 271 SCROW nOrder = GetCache()->GetOrder( nCol, nIndex ); 272 273 if ( nCol == 0 ) 274 maRowsVisible.push_back(true); 275 276 277 pAdded[nOrder] = nIndex; 278 } 279 maFieldEntries.push_back( vector<SCROW>() ); 280 for ( SCROW nRow = 0; nRow < nMemCount; nRow++ ) 281 { 282 if ( pAdded[nRow] != -1 ) 283 maFieldEntries.back().push_back( pAdded[nRow] ); 284 } 285 } 286 } 287 return; 288 } 289 290 bool ScDPCacheTable::isRowActive(sal_Int32 nRow) const 291 { 292 if (nRow < 0 || static_cast<size_t>(nRow) >= maRowsVisible.size()) 293 // row index out of bound 294 return false; 295 296 return maRowsVisible[nRow]; 297 } 298 299 void ScDPCacheTable::filterByPageDimension(const vector<Criterion>& rCriteria, const hash_set<sal_Int32>& rRepeatIfEmptyDims) 300 { 301 sal_Int32 nRowSize = getRowSize(); 302 if (nRowSize != static_cast<sal_Int32>(maRowsVisible.size())) 303 { 304 // sizes of the two tables differ! 305 return; 306 } 307 308 // #i117661# If maRowsVisible is already false from source filtering, don't set to true again. 309 // filterByPageDimension is called only once after initializing with fillTable 310 // (this is enforced in ScDPSource::FilterCacheTableByPageDimensions). 311 312 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow) 313 maRowsVisible[nRow] = maRowsVisible[nRow] && isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims); 314 } 315 316 const ScDPItemData* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const 317 { 318 SCROW nId= GetCache()->GetItemDataId(nCol, nRow, bRepeatIfEmpty); 319 return GetCache()->GetItemDataById( nCol, nId ); 320 } 321 322 void ScDPCacheTable::getValue( ScDPValueData& rVal, SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const 323 { 324 const ScDPItemData* pData = getCell( nCol, nRow, bRepeatIfEmpty ); 325 326 if (pData) 327 { 328 rVal.fValue = pData->IsValue() ? pData->GetValue() : 0.0; 329 rVal.nType = pData->GetType(); 330 } 331 else 332 rVal.Set(0.0, SC_VALTYPE_EMPTY); 333 } 334 String ScDPCacheTable::getFieldName(SCCOL nIndex) const 335 { 336 return (GetCache()->GetDimensionName( nIndex )); 337 } 338 339 sal_Int32 ScDPCacheTable::getFieldIndex(const String& rStr) const 340 { 341 return GetCache()->GetDimensionIndex( rStr ); 342 } 343 344 const ::std::vector<SCROW>& ScDPCacheTable::getFieldEntries( sal_Int32 nColumn ) const 345 { 346 if (nColumn < 0 || static_cast<size_t>(nColumn) >= maFieldEntries.size()) 347 { 348 // index out of bound. Hopefully this code will never be reached. 349 static const ::std::vector<SCROW> emptyEntries; 350 return emptyEntries; 351 } 352 return maFieldEntries[nColumn]; 353 } 354 355 void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData, 356 const hash_set<sal_Int32>& rRepeatIfEmptyDims) 357 { 358 sal_Int32 nRowSize = getRowSize(); 359 sal_Int32 nColSize = getColSize(); 360 361 if (!nRowSize) 362 // no data to filter. 363 return; 364 365 // Row first, then column. 366 vector< Sequence<Any> > tableData; 367 tableData.reserve(nRowSize+1); 368 369 // Header first. 370 Sequence<Any> headerRow(nColSize); 371 for (SCCOL nCol = 0; nCol < nColSize; ++nCol) 372 { 373 OUString str; 374 str = getFieldName( nCol); 375 Any any; 376 any <<= str; 377 headerRow[nCol] = any; 378 } 379 tableData.push_back(headerRow); 380 381 382 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow) 383 { 384 if (!maRowsVisible[nRow]) 385 // This row is filtered out. 386 continue; 387 388 if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims)) 389 continue; 390 391 // Insert this row into table. 392 393 Sequence<Any> row(nColSize); 394 for (SCCOL nCol = 0; nCol < nColSize; ++nCol) 395 { 396 Any any; 397 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0; 398 // Wang Xu Ming - DataPilot migration 399 const ScDPItemData* pData= getCell(nCol, nRow, bRepeatIfEmpty); 400 if ( pData->IsValue() ) 401 any <<= pData->GetValue(); 402 else 403 { 404 OUString string (pData->GetString() ); 405 any <<= string; 406 } 407 row[nCol] = any; 408 } 409 tableData.push_back(row); 410 } 411 412 // convert vector to Seqeunce 413 sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size()); 414 rTabData.realloc(nTabSize); 415 for (sal_Int32 i = 0; i < nTabSize; ++i) 416 rTabData[i] = tableData[i]; 417 } 418 419 void ScDPCacheTable::clear() 420 { 421 maFieldEntries.clear(); 422 maRowsVisible.clear(); 423 } 424 425 void ScDPCacheTable::swap(ScDPCacheTable& rOther) 426 { 427 maFieldEntries.swap(rOther.maFieldEntries); 428 maRowsVisible.swap(rOther.maRowsVisible); 429 } 430 431 bool ScDPCacheTable::empty() const 432 { 433 return ( mpCache == NULL&& mpNoneCache == NULL ) || maFieldEntries.size()==0; 434 } 435 436 bool ScDPCacheTable::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria, 437 const hash_set<sal_Int32>& rRepeatIfEmptyDims) const 438 { 439 sal_Int32 nColSize = getColSize(); 440 vector<Criterion>::const_iterator itrEnd = rCriteria.end(); 441 for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr) 442 { 443 if (itr->mnFieldIndex >= nColSize) 444 // specified field is outside the source data columns. Don't 445 // use this criterion. 446 continue; 447 448 // Check if the 'repeat if empty' flag is set for this field. 449 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0; 450 const ScDPItemData* pCellData = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty); 451 if (!itr->mpFilter->match(*pCellData)) 452 return false; 453 } 454 return true; 455 } 456 457 458 void ScDPCacheTable::InitNoneCache( ScDocument* pDoc ) 459 { 460 mpCache = NULL; 461 if ( mpNoneCache ) 462 delete mpNoneCache; 463 mpNoneCache = new ScDPTableDataCache( pDoc ); 464 } 465 466 ScDPTableDataCache* ScDPCacheTable::GetCache() const 467 { 468 if ( mpCache ) 469 return mpCache; 470 return mpNoneCache; 471 } 472 // End Comments 473