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 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow) 309 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