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